From b0fcefa9ca3a20d93108405c57921db29deeef74 Mon Sep 17 00:00:00 2001 From: "Brian S. Dean" Date: Thu, 20 Feb 2003 03:53:49 +0000 Subject: [PATCH] Add Motorola S-record support. Submitted by: "Alexey V.Levdikov" git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk@200 81a1dc3b-b13d-400b-aceb-764788c761c2 --- avrdude/avrdude.1 | 2 +- avrdude/fileio.c | 383 +++++++++++++++++++++++++++++++++++++++++++++- avrdude/main.c | 6 +- 3 files changed, 381 insertions(+), 10 deletions(-) diff --git a/avrdude/avrdude.1 b/avrdude/avrdude.1 index d06f0f8c..d1561ecb 100644 --- a/avrdude/avrdude.1 +++ b/avrdude/avrdude.1 @@ -441,4 +441,4 @@ This man page by .ie t J\(:org Wunsch. .el Joerg Wunsch. .Sh BUGS -Motorola S-record files are not yet implemented. +Please report bugs to avrdude-dev@nongnu.org. diff --git a/avrdude/fileio.c b/avrdude/fileio.c index 37dfab35..83727725 100644 --- a/avrdude/fileio.c +++ b/avrdude/fileio.c @@ -39,7 +39,7 @@ struct ihexrec { unsigned char reclen; - unsigned short loadofs; + unsigned int loadofs; unsigned char rectyp; unsigned char data[IHEX_MAXDATA]; unsigned char cksum; @@ -56,6 +56,17 @@ int b2ihex(unsigned char * inbuf, int bufsize, int ihex2b(char * infile, FILE * inf, unsigned char * outbuf, int bufsize); +int b2srec(unsigned char * inbuf, int bufsize, + int recsize, int startaddr, + char * outfile, FILE * outf); + +int srec2b(char * infile, FILE * inf, + unsigned char * outbuf, int bufsize); + +int ihex_readrec(struct ihexrec * ihex, char * rec); + +int srec_readrec(struct ihexrec * srec, char * rec); + int fileio_rbin(struct fioparms * fio, char * filename, FILE * f, unsigned char * buf, int size); @@ -344,6 +355,348 @@ int ihex2b(char * infile, FILE * inf, } +int b2srec(unsigned char * inbuf, int bufsize, + int recsize, int startaddr, + char * outfile, FILE * outf) +{ + unsigned char * buf; + unsigned int nextaddr, stopaddr; + int n, nbytes, addr_width; + int i; + unsigned char cksum; + unsigned char startf, stopf ,emptyf; + + char * tmpl=0; + + if (recsize > 255) { + fprintf(stderr, "%s: ERROR: recsize=%d, must be < 256\n", + progname, recsize); + return -1; + } + + buf = inbuf; + nextaddr = 0; + stopaddr = 0; + startf = 0; + stopf = 0; + + /* search for ranges of 'real' data */ + for (i=startaddr; i bufsize) + n = bufsize; + + if (n) { + cksum = 0; + if (nextaddr + n <= 0xffff) { + addr_width = 2; + tmpl="S1%02X%04X"; + } + else if (nextaddr + n <= 0xffffff) { + addr_width = 3; + tmpl="S2%02X%06X"; + } + else if (nextaddr + n <= 0xffffffff) { + addr_width = 4; + tmpl="S3%02X%08X"; + } + else { + fprintf(stderr, "%s: ERROR: address=%d, out of range\n", + progname, nextaddr); + return -1; + } + + /* skip the lines filled with 0xff */ + emptyf = 1; + for (i=nextaddr; i0; i--) + cksum += (nextaddr >> (i-1) * 8) & 0xff; + + for (i=nextaddr; i0; i--) + cksum += (nextaddr >> (i - 1) * 8) & 0xff; + cksum = 0xff - cksum; + fprintf(outf, "%02X\n", cksum); + + return nbytes; +} + + +int srec_readrec(struct ihexrec * srec, char * rec) +{ + int i, j; + char buf[8]; + int offset, len, addr_width; + char * e; + unsigned char cksum; + int rc; + + len = strlen(rec); + offset = 1; + cksum = 0; + addr_width = 2; + + /* record type */ + if (offset + 1 > len) + return -1; + srec->rectyp = rec[offset++]; + if (srec->rectyp == 0x32 || srec->rectyp == 0x38) + addr_width = 3; /* S2,S8-record */ + else if (srec->rectyp == 0x33 || srec->rectyp == 0x37) + addr_width = 4; /* S3,S7-record */ + + /* reclen */ + if (offset + 2 > len) + return -1; + for (i=0; i<2; i++) + buf[i] = rec[offset++]; + buf[i] = 0; + srec->reclen = strtoul(buf, &e, 16); + cksum += srec->reclen; + srec->reclen -= (addr_width+1); + if (e == buf || *e != 0) + return -1; + + /* load offset */ + if (offset + addr_width > len) + return -1; + for (i=0; iloadofs = strtoull(buf, &e, 16); + if (e == buf || *e != 0) + return -1; + + for (i=addr_width; i>0; i--) + cksum += (srec->loadofs >> (i - 1) * 8) & 0xff; + + /* data */ + for (j=0; jreclen; j++) { + if (offset+2 > len) + return -1; + for (i=0; i<2; i++) + buf[i] = rec[offset++]; + buf[i] = 0; + srec->data[j] = strtoul(buf, &e, 16); + if (e == buf || *e != 0) + return -1; + cksum += srec->data[j]; + } + + /* cksum */ + if (offset + 2 > len) + return -1; + for (i=0; i<2; i++) + buf[i] = rec[offset++]; + buf[i] = 0; + srec->cksum = strtoul(buf, &e, 16); + if (e == buf || *e != 0) + return -1; + + rc = 0xff - cksum; + return rc; +} + + +int srec2b(char * infile, FILE * inf, + unsigned char * outbuf, int bufsize) +{ + char buffer [ MAX_LINE_LEN ]; + unsigned char * buf; + unsigned int nextaddr, baseaddr, maxaddr; + int i; + int lineno; + int len; + struct ihexrec srec; + int rc; + int reccount; + unsigned char datarec; + + char * msg = 0; + + lineno = 0; + buf = outbuf; + baseaddr = 0; + maxaddr = 0; + reccount = 0; + + while (fgets((char *)buffer,MAX_LINE_LEN,inf)!=NULL) { + lineno++; + len = strlen(buffer); + if (buffer[len-1] == '\n') + buffer[--len] = 0; + if (buffer[0] != 0x53) + continue; + rc = srec_readrec(&srec, buffer); + + if (rc < 0) { + fprintf(stderr, "%s: ERROR: invalid record at line %d of \"%s\"\n", + progname, lineno, infile); + return -1; + } + else if (rc != srec.cksum) { + fprintf(stderr, "%s: ERROR: checksum mismatch at line %d of \"%s\"\n", + progname, lineno, infile); + fprintf(stderr, "%s: checksum=0x%02x, computed checksum=0x%02x\n", + progname, srec.cksum, rc); + return -1; + } + + datarec=0; + switch (srec.rectyp) { + case 0x30: /* S0 - header record*/ + /* skip */ + break; + + case 0x31: /* S1 - 16 bit address data record */ + datarec=1; + msg="%s: ERROR: address 0x%04x out of range at line %d of %s\n"; + break; + + case 0x32: /* S2 - 24 bit address data record */ + datarec=1; + msg="%s: ERROR: address 0x%06x out of range at line %d of %s\n"; + break; + + case 0x33: /* S3 - 32 bit address data record */ + datarec=1; + msg="%s: ERROR: address 0x%08x out of range at line %d of %s\n"; + break; + + case 0x34: /* S4 - symbol record (LSI extension) */ + fprintf(stderr, + "%s: ERROR: not supported record at line %d of %s\n", + progname, lineno, infile); + return -1; + + case 0x35: /* S5 - count of S1,S2 and S3 records previously tx'd */ + if (srec.loadofs != reccount){ + fprintf(stderr, + "%s: ERROR: count of transmitted data records mismatch " + "at line %d of \"%s\"\n", + progname, lineno, infile); + fprintf(stderr, "%s: transmitted data records= %d, expected " + "value= %d\n", + progname, reccount, srec.loadofs); + return -1; + } + break; + + case 0x37: /* S7 Record - end record for 32 bit address data */ + case 0x38: /* S8 Record - end record for 24 bit address data */ + case 0x39: /* S9 Record - end record for 16 bit address data */ + return maxaddr; + + default: + fprintf(stderr, + "%s: ERROR: don't know how to deal with rectype S%d " + "at line %d of %s\n", + progname, srec.rectyp, lineno, infile); + return -1; + } + + if (datarec == 1) { + nextaddr = srec.loadofs + baseaddr; + if (nextaddr + srec.reclen > bufsize) { + fprintf(stderr, msg, progname, nextaddr+srec.reclen, lineno, infile); + return -1; + } + for (i=0; i maxaddr) + maxaddr = nextaddr+srec.reclen; + reccount++; + } + + } + + fprintf(stderr, + "%s: WARNING: no end of file record found for Motorola S-Records " + "file \"%s\"\n", + progname, infile); + + return maxaddr; +} + int fileio_rbin(struct fioparms * fio, char * filename, FILE * f, unsigned char * buf, int size) @@ -408,9 +761,31 @@ int fileio_ihex(struct fioparms * fio, int fileio_srec(struct fioparms * fio, char * filename, FILE * f, unsigned char * buf, int size) { - fprintf(stderr, "%s: Motorola S-Record %s format not yet supported\n", - progname, fio->iodesc); - return -1; + int rc; + + switch (fio->op) { + case FIO_WRITE: + rc = b2srec(buf, size, 32, 0, filename, f); + if (rc < 0) { + return -1; + } + break; + + case FIO_READ: + rc = srec2b(filename, f, buf, size); + if (rc < 0) + return -1; + break; + + default: + fprintf(stderr, "%s: ERROR: invalid Motorola S-Records file I/O " + "operation=%d\n", + progname, fio->op); + return -1; + break; + } + + return rc; } diff --git a/avrdude/main.c b/avrdude/main.c index b1d51e93..610b6bc8 100644 --- a/avrdude/main.c +++ b/avrdude/main.c @@ -457,11 +457,7 @@ int main(int argc, char * argv []) case 'a' : filefmt = FMT_AUTO; break; case 'i' : filefmt = FMT_IHEX; break; case 'r' : filefmt = FMT_RBIN; break; - case 's' : - fprintf(stderr, - "%s: Motorola S-Record format not yet supported\n\n", - progname); - exit(1); + case 's' : filefmt = FMT_SREC; break; break; default : fprintf(stderr, "%s: invalid file format \"%s\"\n\n",