#include "defs.h"
#include "serial.h"
#include "srec.h"
#include <time.h>
#include "gdb_assert.h"
#include "gdb_string.h"
extern void report_transfer_performance (unsigned long, time_t, time_t);
extern int remote_debug;
static int make_srec (char *srec, CORE_ADDR targ_addr, bfd * abfd,
asection * sect, int sectoff, int *maxrecsize,
int flags);
void
load_srec (struct serial *desc, const char *file, bfd_vma load_offset,
int maxrecsize,
int flags, int hashmark, int (*waitack) (void))
{
bfd *abfd;
asection *s;
char *srec;
int i;
int reclen;
time_t start_time, end_time;
unsigned long data_count = 0;
srec = (char *) alloca (maxrecsize + 1);
abfd = bfd_openr (file, 0);
if (!abfd)
{
printf_filtered ("Unable to open file %s\n", file);
return;
}
if (bfd_check_format (abfd, bfd_object) == 0)
{
printf_filtered ("File is not an object file\n");
return;
}
start_time = time (NULL);
reclen = maxrecsize;
make_srec (srec, 0, NULL, (asection *) 1, 0, &reclen, flags);
if (remote_debug)
{
srec[reclen] = '\0';
puts_debug ("sent -->", srec, "<--");
}
serial_write (desc, srec, reclen);
for (s = abfd->sections; s; s = s->next)
if (s->flags & SEC_LOAD)
{
int numbytes;
bfd_vma addr = bfd_get_section_vma (abfd, s) + load_offset;
bfd_size_type size = bfd_get_section_size_before_reloc (s);
char *section_name = (char *) bfd_get_section_name (abfd, s);
printf_filtered ("%s\t: 0x%s .. 0x%s ",
section_name,
paddr (addr),
paddr (addr + size));
gdb_flush (gdb_stdout);
data_count += size;
for (i = 0; i < size; i += numbytes)
{
reclen = maxrecsize;
numbytes = make_srec (srec, (CORE_ADDR) (addr + i), abfd, s,
i, &reclen, flags);
if (remote_debug)
{
srec[reclen] = '\0';
puts_debug ("sent -->", srec, "<--");
}
do
{
serial_write (desc, srec, reclen);
if (ui_load_progress_hook)
if (ui_load_progress_hook (section_name, (unsigned long) i))
error ("Canceled the download");
}
while (waitack != NULL && !waitack ());
if (hashmark)
{
putchar_unfiltered ('#');
gdb_flush (gdb_stdout);
}
}
if (ui_load_progress_hook)
if (ui_load_progress_hook (section_name, (unsigned long) i))
error ("Canceled the download");
putchar_unfiltered ('\n');
}
if (hashmark)
putchar_unfiltered ('\n');
end_time = time (NULL);
reclen = maxrecsize;
make_srec (srec, abfd->start_address, NULL, NULL, 0, &reclen, flags);
if (remote_debug)
{
srec[reclen] = '\0';
puts_debug ("sent -->", srec, "<--");
}
serial_write (desc, srec, reclen);
serial_write (desc, "\r\r", 2);
if (remote_debug)
puts_debug ("sent -->", "\r\r", "<---");
serial_flush_input (desc);
report_transfer_performance (data_count, start_time, end_time);
}
static int
make_srec (char *srec, CORE_ADDR targ_addr, bfd *abfd, asection *sect,
int sectoff, int *maxrecsize, int flags)
{
unsigned char checksum;
int tmp;
const static char hextab[] = "0123456789ABCDEF";
const static char data_code_table[] = "123";
const static char term_code_table[] = "987";
const static char header_code_table[] = "000";
char const *code_table;
int addr_size;
int payload_size;
char *binbuf;
char *p;
if (sect)
{
tmp = flags;
code_table = abfd ? data_code_table : header_code_table;
binbuf = alloca (*maxrecsize / 2);
}
else
{
tmp = flags >> SREC_TERM_SHIFT;
code_table = term_code_table;
binbuf = NULL;
}
if ((tmp & SREC_2_BYTE_ADDR) && (targ_addr <= 0xffff))
addr_size = 2;
else if ((tmp & SREC_3_BYTE_ADDR) && (targ_addr <= 0xffffff))
addr_size = 3;
else if (tmp & SREC_4_BYTE_ADDR)
addr_size = 4;
else
internal_error (__FILE__, __LINE__,
"make_srec: Bad address (0x%s), or bad flags (0x%x).",
paddr (targ_addr), flags);
if (sect && abfd)
{
payload_size = (*maxrecsize - (1 + 1 + 2 + addr_size * 2 + 2)) / 2;
payload_size = min (payload_size, sect->_raw_size - sectoff);
bfd_get_section_contents (abfd, sect, binbuf, sectoff, payload_size);
}
else
payload_size = 0;
snprintf (srec, (*maxrecsize) + 1, "S%c%02X%0*X",
code_table[addr_size - 2],
addr_size + payload_size + 1,
addr_size * 2, (int) targ_addr);
checksum = 0;
checksum += (payload_size + addr_size + 1
+ (targ_addr & 0xff)
+ ((targ_addr >> 8) & 0xff)
+ ((targ_addr >> 16) & 0xff)
+ ((targ_addr >> 24) & 0xff));
gdb_assert (strlen (srec) == 1 + 1 + 2 + addr_size * 2);
p = srec + 1 + 1 + 2 + addr_size * 2;
for (tmp = 0; tmp < payload_size; tmp++)
{
unsigned char k;
k = binbuf[tmp];
*p++ = hextab[k >> 4];
*p++ = hextab[k & 0xf];
checksum += k;
}
checksum = ~checksum;
*p++ = hextab[checksum >> 4];
*p++ = hextab[checksum & 0xf];
*p++ = '\r';
*maxrecsize = p - srec;
return payload_size;
}