2001-01-19 02:46:50 +00:00
|
|
|
/*
|
2001-10-01 14:04:46 +00:00
|
|
|
* Copyright 2001 Brian S. Dean <bsd@bsdhome.com>
|
2001-01-19 02:46:50 +00:00
|
|
|
* All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
*
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY BRIAN S. DEAN ``AS IS'' AND ANY
|
|
|
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BRIAN S. DEAN BE LIABLE
|
|
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
|
|
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
|
|
|
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
|
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
|
|
|
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
|
|
|
* DAMAGE.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* $Id$ */
|
|
|
|
|
2001-01-26 17:22:40 +00:00
|
|
|
#include <limits.h>
|
2001-01-19 02:46:50 +00:00
|
|
|
#include <stdio.h>
|
2001-01-26 17:22:40 +00:00
|
|
|
#include <stdlib.h>
|
2001-01-19 02:46:50 +00:00
|
|
|
#include <string.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
|
|
|
|
#include "avr.h"
|
|
|
|
#include "fileio.h"
|
|
|
|
|
|
|
|
|
2001-01-26 17:22:40 +00:00
|
|
|
#define IHEX_MAXDATA 256
|
|
|
|
|
2001-09-19 17:04:25 +00:00
|
|
|
#define MAX_LINE_LEN 256 /* max line length for ASCII format input files */
|
|
|
|
|
|
|
|
|
2001-01-26 17:22:40 +00:00
|
|
|
struct ihexrec {
|
|
|
|
unsigned char reclen;
|
|
|
|
unsigned short loadofs;
|
|
|
|
unsigned char rectyp;
|
|
|
|
unsigned char data[IHEX_MAXDATA];
|
|
|
|
unsigned char cksum;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2001-01-19 02:46:50 +00:00
|
|
|
extern char * progname;
|
|
|
|
extern char progbuf[];
|
|
|
|
|
2001-01-26 20:34:08 +00:00
|
|
|
char * fileio_version = "$Id$";
|
2001-01-19 02:46:50 +00:00
|
|
|
|
2001-10-13 03:13:13 +00:00
|
|
|
int b2ihex(unsigned char * inbuf, int bufsize,
|
2001-01-19 02:46:50 +00:00
|
|
|
int recsize, int startaddr,
|
2001-10-13 03:13:13 +00:00
|
|
|
char * outfile, FILE * outf);
|
2001-01-19 02:46:50 +00:00
|
|
|
|
2001-10-13 03:13:13 +00:00
|
|
|
int ihex2b(char * infile, FILE * inf,
|
|
|
|
unsigned char * outbuf, int bufsize);
|
2001-01-19 02:46:50 +00:00
|
|
|
|
2001-10-13 03:13:13 +00:00
|
|
|
int fileio_rbin(struct fioparms * fio,
|
|
|
|
char * filename, FILE * f, unsigned char * buf, int size);
|
2001-01-19 02:46:50 +00:00
|
|
|
|
2001-10-13 03:13:13 +00:00
|
|
|
int fileio_ihex(struct fioparms * fio,
|
|
|
|
char * filename, FILE * f, unsigned char * buf, int size);
|
2001-01-19 02:46:50 +00:00
|
|
|
|
2001-10-13 03:13:13 +00:00
|
|
|
int fileio_srec(struct fioparms * fio,
|
|
|
|
char * filename, FILE * f, unsigned char * buf, int size);
|
2001-01-19 02:46:50 +00:00
|
|
|
|
2001-10-13 03:13:13 +00:00
|
|
|
int fmt_autodetect(char * fname);
|
2001-01-19 02:46:50 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
2001-10-13 03:13:13 +00:00
|
|
|
char * fmtstr(FILEFMT format)
|
2001-01-19 02:46:50 +00:00
|
|
|
{
|
|
|
|
switch (format) {
|
|
|
|
case FMT_AUTO : return "auto-detect"; break;
|
|
|
|
case FMT_SREC : return "Motorola S-Record"; break;
|
|
|
|
case FMT_IHEX : return "Intel Hex"; break;
|
|
|
|
case FMT_RBIN : return "raw binary"; break;
|
|
|
|
default : return "invalid format"; break;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2001-10-13 03:13:13 +00:00
|
|
|
int b2ihex(unsigned char * inbuf, int bufsize,
|
2001-10-14 02:53:21 +00:00
|
|
|
int recsize, int startaddr,
|
|
|
|
char * outfile, FILE * outf)
|
2001-01-19 02:46:50 +00:00
|
|
|
{
|
|
|
|
unsigned char * buf;
|
|
|
|
unsigned int nextaddr;
|
2001-10-14 02:53:21 +00:00
|
|
|
int n, nbytes, n_64k;
|
2001-01-19 02:46:50 +00:00
|
|
|
int i;
|
|
|
|
unsigned char cksum;
|
|
|
|
|
|
|
|
if (recsize > 255) {
|
2001-10-13 03:13:13 +00:00
|
|
|
fprintf(stderr, "%s: recsize=%d, must be < 256\n",
|
|
|
|
progname, recsize);
|
2001-01-19 02:46:50 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2001-10-14 02:53:21 +00:00
|
|
|
n_64k = 0;
|
2001-01-19 02:46:50 +00:00
|
|
|
nextaddr = startaddr;
|
2001-01-20 16:34:28 +00:00
|
|
|
buf = inbuf;
|
|
|
|
nbytes = 0;
|
2001-01-19 02:46:50 +00:00
|
|
|
|
|
|
|
while (bufsize) {
|
|
|
|
n = recsize;
|
|
|
|
if (n > bufsize)
|
|
|
|
n = bufsize;
|
|
|
|
|
2001-10-14 02:53:21 +00:00
|
|
|
if ((nextaddr + n) > 0x10000)
|
|
|
|
n = 0x10000 - nextaddr;
|
|
|
|
|
2001-01-19 02:46:50 +00:00
|
|
|
if (n) {
|
|
|
|
cksum = 0;
|
2001-10-13 03:13:13 +00:00
|
|
|
fprintf(outf, ":%02X%04X00", n, nextaddr);
|
2001-01-19 02:46:50 +00:00
|
|
|
cksum += n + ((nextaddr >> 8) & 0x0ff) + (nextaddr & 0x0ff);
|
|
|
|
for (i=0; i<n; i++) {
|
2001-10-13 03:13:13 +00:00
|
|
|
fprintf(outf, "%02X", buf[i]);
|
2001-01-19 02:46:50 +00:00
|
|
|
cksum += buf[i];
|
|
|
|
}
|
|
|
|
cksum = -cksum;
|
2001-10-13 03:13:13 +00:00
|
|
|
fprintf(outf, "%02X\n", cksum);
|
2001-01-19 02:46:50 +00:00
|
|
|
|
|
|
|
nextaddr += n;
|
2001-01-20 16:34:28 +00:00
|
|
|
nbytes += n;
|
2001-01-19 02:46:50 +00:00
|
|
|
}
|
|
|
|
|
2001-10-14 02:53:21 +00:00
|
|
|
if (nextaddr >= 0x10000) {
|
|
|
|
int lo, hi;
|
|
|
|
/* output an extended address record */
|
|
|
|
n_64k++;
|
|
|
|
lo = n_64k & 0xff;
|
|
|
|
hi = (n_64k >> 8) & 0xff;
|
|
|
|
cksum = 0;
|
|
|
|
fprintf(outf, ":02000004%02X%02X", hi, lo);
|
|
|
|
cksum += 2 + 0 + 4 + hi + lo;
|
|
|
|
cksum = -cksum;
|
|
|
|
fprintf(outf, "%02X\n", cksum);
|
|
|
|
nextaddr = 0;
|
|
|
|
}
|
|
|
|
|
2001-01-19 02:46:50 +00:00
|
|
|
/* advance to next 'recsize' bytes */
|
|
|
|
buf += n;
|
|
|
|
bufsize -= n;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*-----------------------------------------------------------------
|
|
|
|
add the end of record data line
|
|
|
|
-----------------------------------------------------------------*/
|
|
|
|
cksum = 0;
|
|
|
|
n = 0;
|
|
|
|
nextaddr = 0;
|
2001-10-13 03:13:13 +00:00
|
|
|
fprintf(outf, ":%02X%04X01", n, nextaddr);
|
2001-01-20 15:38:55 +00:00
|
|
|
cksum += n + ((nextaddr >> 8) & 0x0ff) + (nextaddr & 0x0ff) + 1;
|
2001-01-19 02:46:50 +00:00
|
|
|
cksum = -cksum;
|
2001-10-13 03:13:13 +00:00
|
|
|
fprintf(outf, "%02X\n", cksum);
|
2001-01-19 02:46:50 +00:00
|
|
|
|
2001-01-20 16:34:28 +00:00
|
|
|
return nbytes;
|
2001-01-19 02:46:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-10-13 03:13:13 +00:00
|
|
|
int ihex_readrec(struct ihexrec * ihex, char * rec)
|
2001-01-26 17:22:40 +00:00
|
|
|
{
|
|
|
|
int i, j;
|
|
|
|
char buf[8];
|
|
|
|
int offset, len;
|
|
|
|
char * e;
|
|
|
|
unsigned char cksum;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
len = strlen(rec);
|
|
|
|
offset = 1;
|
|
|
|
cksum = 0;
|
|
|
|
|
|
|
|
/* reclen */
|
|
|
|
if (offset + 2 > len)
|
|
|
|
return -1;
|
|
|
|
for (i=0; i<2; i++)
|
|
|
|
buf[i] = rec[offset++];
|
|
|
|
buf[i] = 0;
|
|
|
|
ihex->reclen = strtoul(buf, &e, 16);
|
|
|
|
if (e == buf || *e != 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* load offset */
|
|
|
|
if (offset + 4 > len)
|
|
|
|
return -1;
|
|
|
|
for (i=0; i<4; i++)
|
|
|
|
buf[i] = rec[offset++];
|
|
|
|
buf[i] = 0;
|
|
|
|
ihex->loadofs = strtoul(buf, &e, 16);
|
|
|
|
if (e == buf || *e != 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* record type */
|
|
|
|
if (offset + 2 > len)
|
|
|
|
return -1;
|
|
|
|
for (i=0; i<2; i++)
|
|
|
|
buf[i] = rec[offset++];
|
|
|
|
buf[i] = 0;
|
|
|
|
ihex->rectyp = strtoul(buf, &e, 16);
|
|
|
|
if (e == buf || *e != 0)
|
|
|
|
return -1;
|
|
|
|
|
2001-10-13 03:13:13 +00:00
|
|
|
cksum = ihex->reclen + ((ihex->loadofs >> 8) & 0x0ff) +
|
2001-01-26 17:22:40 +00:00
|
|
|
(ihex->loadofs & 0x0ff) + ihex->rectyp;
|
|
|
|
|
|
|
|
/* data */
|
|
|
|
for (j=0; j<ihex->reclen; j++) {
|
|
|
|
if (offset + 2 > len)
|
|
|
|
return -1;
|
|
|
|
for (i=0; i<2; i++)
|
|
|
|
buf[i] = rec[offset++];
|
|
|
|
buf[i] = 0;
|
|
|
|
ihex->data[j] = strtoul(buf, &e, 16);
|
|
|
|
if (e == buf || *e != 0)
|
|
|
|
return -1;
|
|
|
|
cksum += ihex->data[j];
|
|
|
|
}
|
|
|
|
|
|
|
|
/* cksum */
|
|
|
|
if (offset + 2 > len)
|
|
|
|
return -1;
|
|
|
|
for (i=0; i<2; i++)
|
|
|
|
buf[i] = rec[offset++];
|
|
|
|
buf[i] = 0;
|
|
|
|
ihex->cksum = strtoul(buf, &e, 16);
|
|
|
|
if (e == buf || *e != 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
rc = -cksum & 0x000000ff;
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2001-01-26 17:47:33 +00:00
|
|
|
/*
|
|
|
|
* Intel Hex to binary buffer
|
|
|
|
*
|
|
|
|
* Given an open file 'inf' which contains Intel Hex formated data,
|
|
|
|
* parse the file and lay it out within the memory buffer pointed to
|
|
|
|
* by outbuf. The size of outbuf, 'bufsize' is honored; if data would
|
|
|
|
* fall outsize of the memory buffer outbuf, an error is generated.
|
|
|
|
*
|
|
|
|
* Return the maximum memory address within 'outbuf' that was written.
|
|
|
|
* If an error occurs, return -1.
|
|
|
|
*
|
|
|
|
* */
|
2001-01-26 17:22:40 +00:00
|
|
|
|
2001-10-13 03:13:13 +00:00
|
|
|
int ihex2b(char * infile, FILE * inf,
|
|
|
|
unsigned char * outbuf, int bufsize)
|
2001-01-19 02:46:50 +00:00
|
|
|
{
|
2001-01-26 17:22:40 +00:00
|
|
|
char buffer [ MAX_LINE_LEN ];
|
2001-01-19 02:46:50 +00:00
|
|
|
unsigned char * buf;
|
2001-01-26 17:47:33 +00:00
|
|
|
unsigned int nextaddr, baseaddr, maxaddr;
|
2001-01-26 17:22:40 +00:00
|
|
|
int i;
|
2001-01-19 02:46:50 +00:00
|
|
|
int lineno;
|
2001-01-26 17:22:40 +00:00
|
|
|
int len;
|
|
|
|
struct ihexrec ihex;
|
|
|
|
int rc;
|
2001-01-19 02:46:50 +00:00
|
|
|
|
|
|
|
lineno = 0;
|
|
|
|
buf = outbuf;
|
2001-01-26 17:22:40 +00:00
|
|
|
baseaddr = 0;
|
2001-01-26 17:47:33 +00:00
|
|
|
maxaddr = 0;
|
2001-01-19 02:46:50 +00:00
|
|
|
|
|
|
|
while (fgets((char *)buffer,MAX_LINE_LEN,inf)!=NULL) {
|
|
|
|
lineno++;
|
2001-01-26 17:22:40 +00:00
|
|
|
len = strlen(buffer);
|
|
|
|
if (buffer[len-1] == '\n')
|
|
|
|
buffer[--len] = 0;
|
2001-01-19 02:46:50 +00:00
|
|
|
if (buffer[0] != ':')
|
|
|
|
continue;
|
2001-01-26 17:22:40 +00:00
|
|
|
rc = ihex_readrec(&ihex, buffer);
|
|
|
|
if (rc < 0) {
|
2001-01-19 02:46:50 +00:00
|
|
|
fprintf(stderr, "%s: invalid record at line %d of \"%s\"\n",
|
|
|
|
progname, lineno, infile);
|
|
|
|
return -1;
|
|
|
|
}
|
2001-01-26 17:22:40 +00:00
|
|
|
else if (rc != ihex.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, ihex.cksum, rc);
|
2001-01-19 02:46:50 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2001-01-26 17:22:40 +00:00
|
|
|
switch (ihex.rectyp) {
|
2001-01-19 02:46:50 +00:00
|
|
|
|
2001-01-26 17:22:40 +00:00
|
|
|
case 0: /* data record */
|
|
|
|
nextaddr = ihex.loadofs + baseaddr;
|
|
|
|
if (nextaddr + ihex.reclen > bufsize) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"%s: ERROR: address 0x%04x out of range at line %d of %s\n",
|
|
|
|
progname, nextaddr+ihex.reclen, lineno, infile);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
for (i=0; i<ihex.reclen; i++) {
|
|
|
|
buf[nextaddr+i] = ihex.data[i];
|
|
|
|
}
|
2001-01-26 17:47:33 +00:00
|
|
|
if (nextaddr+ihex.reclen > maxaddr)
|
|
|
|
maxaddr = nextaddr+ihex.reclen;
|
2001-01-26 17:22:40 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 1: /* end of file record */
|
2001-01-26 17:47:33 +00:00
|
|
|
return maxaddr;
|
2001-01-26 17:22:40 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 2: /* extended segment address record */
|
|
|
|
baseaddr = (ihex.data[0] << 8 | ihex.data[1]) << 4;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 3: /* start segment address record */
|
|
|
|
/* we don't do anything with the start address */
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 4: /* extended linear address record */
|
|
|
|
baseaddr = (ihex.data[0] << 8 | ihex.data[1]) << 16;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 5: /* start linear address record */
|
|
|
|
/* we don't do anything with the start address */
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
fprintf(stderr,
|
|
|
|
"%s: don't know how to deal with rectype=%d "
|
|
|
|
"at line %d of %s\n",
|
|
|
|
progname, ihex.rectyp, lineno, infile);
|
|
|
|
return -1;
|
|
|
|
break;
|
2001-01-19 02:46:50 +00:00
|
|
|
}
|
|
|
|
|
2001-01-20 16:34:28 +00:00
|
|
|
} /* while */
|
2001-01-19 02:46:50 +00:00
|
|
|
|
2001-01-26 17:22:40 +00:00
|
|
|
fprintf(stderr,
|
|
|
|
"%s: WARNING: no end of file record found for Intel Hex "
|
|
|
|
"file \"%s\"\n",
|
|
|
|
progname, infile);
|
|
|
|
|
2001-01-26 17:47:33 +00:00
|
|
|
return maxaddr;
|
2001-01-19 02:46:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2001-10-13 03:13:13 +00:00
|
|
|
int fileio_rbin(struct fioparms * fio,
|
|
|
|
char * filename, FILE * f, unsigned char * buf, int size)
|
2001-01-19 02:46:50 +00:00
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
switch (fio->op) {
|
|
|
|
case FIO_READ:
|
|
|
|
rc = fread(buf, 1, size, f);
|
|
|
|
break;
|
|
|
|
case FIO_WRITE:
|
|
|
|
rc = fwrite(buf, 1, size, f);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
fprintf(stderr, "%s: fileio: invalid operation=%d\n",
|
|
|
|
progname, fio->op);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2001-01-20 16:34:28 +00:00
|
|
|
if (rc < 0 || (fio->op == FIO_WRITE && rc < size)) {
|
2001-01-19 02:46:50 +00:00
|
|
|
fprintf(stderr,
|
|
|
|
"%s: %s error %s %s: %s; %s %d of the expected %d bytes\n",
|
|
|
|
progname, fio->iodesc, fio->dir, filename, strerror(errno),
|
|
|
|
fio->rw, rc, size);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-10-13 03:13:13 +00:00
|
|
|
int fileio_ihex(struct fioparms * fio,
|
|
|
|
char * filename, FILE * f, unsigned char * buf, int size)
|
2001-01-19 02:46:50 +00:00
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
switch (fio->op) {
|
|
|
|
case FIO_WRITE:
|
|
|
|
rc = b2ihex(buf, size, 32, 0, filename, f);
|
2001-01-20 16:34:28 +00:00
|
|
|
if (rc < 0) {
|
2001-01-19 02:46:50 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FIO_READ:
|
|
|
|
rc = ihex2b(filename, f, buf, size);
|
2001-01-20 16:34:28 +00:00
|
|
|
if (rc < 0)
|
2001-01-19 02:46:50 +00:00
|
|
|
return -1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
fprintf(stderr, "%s: invalid Intex Hex file I/O operation=%d\n",
|
|
|
|
progname, fio->op);
|
|
|
|
return -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2001-01-20 16:34:28 +00:00
|
|
|
return rc;
|
2001-01-19 02:46:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-10-13 03:13:13 +00:00
|
|
|
int fileio_srec(struct fioparms * fio,
|
|
|
|
char * filename, FILE * f, unsigned char * buf, int size)
|
2001-01-19 02:46:50 +00:00
|
|
|
{
|
|
|
|
fprintf(stderr, "%s: Motorola S-Record %s format not yet supported\n",
|
|
|
|
progname, fio->iodesc);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-10-13 03:13:13 +00:00
|
|
|
int fileio_setparms(int op, struct fioparms * fp)
|
2001-01-19 02:46:50 +00:00
|
|
|
{
|
|
|
|
fp->op = op;
|
|
|
|
|
|
|
|
switch (op) {
|
|
|
|
case FIO_READ:
|
|
|
|
fp->mode = "r";
|
|
|
|
fp->iodesc = "input";
|
|
|
|
fp->dir = "from";
|
|
|
|
fp->rw = "read";
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FIO_WRITE:
|
|
|
|
fp->mode = "w";
|
|
|
|
fp->iodesc = "output";
|
|
|
|
fp->dir = "to";
|
|
|
|
fp->rw = "wrote";
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
fprintf(stderr, "%s: invalid I/O operation %d\n",
|
|
|
|
progname, op);
|
|
|
|
return -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2001-10-13 03:13:13 +00:00
|
|
|
int fmt_autodetect(char * fname)
|
2001-01-19 02:46:50 +00:00
|
|
|
{
|
|
|
|
FILE * f;
|
|
|
|
unsigned char buf[MAX_LINE_LEN];
|
|
|
|
int i;
|
|
|
|
int len;
|
|
|
|
int found;
|
|
|
|
|
|
|
|
f = fopen(fname, "r");
|
|
|
|
if (f == NULL) {
|
|
|
|
fprintf(stderr, "%s: error opening %s: %s\n",
|
|
|
|
progname, fname, strerror(errno));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (fgets((char *)buf, MAX_LINE_LEN, f)!=NULL) {
|
|
|
|
buf[MAX_LINE_LEN-1] = 0;
|
|
|
|
len = strlen((char *)buf);
|
|
|
|
if (buf[len-1] == '\n')
|
|
|
|
buf[--len] = 0;
|
|
|
|
|
|
|
|
/* check for binary data */
|
|
|
|
found = 0;
|
|
|
|
for (i=0; i<len; i++) {
|
|
|
|
if (buf[i] > 127) {
|
|
|
|
found = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (found)
|
|
|
|
return FMT_RBIN;
|
|
|
|
|
|
|
|
/* check for lines that look like intel hex */
|
|
|
|
if ((buf[0] == ':') && (len >= 11)) {
|
|
|
|
found = 1;
|
|
|
|
for (i=1; i<len; i++) {
|
|
|
|
if (!isxdigit(buf[1])) {
|
|
|
|
found = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (found)
|
|
|
|
return FMT_IHEX;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check for lines that look like motorola s-record */
|
|
|
|
if ((buf[0] == 'S') && (len >= 10) && isdigit(buf[1])) {
|
|
|
|
found = 1;
|
|
|
|
for (i=1; i<len; i++) {
|
|
|
|
if (!isxdigit(buf[1])) {
|
|
|
|
found = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (found)
|
|
|
|
return FMT_SREC;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2001-10-13 03:13:13 +00:00
|
|
|
int fileio(int op, char * filename, FILEFMT format,
|
|
|
|
struct avrpart * p, int memtype, int size)
|
2001-01-19 02:46:50 +00:00
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
FILE * f;
|
|
|
|
char * fname;
|
|
|
|
unsigned char * buf;
|
|
|
|
struct fioparms fio;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
rc = fileio_setparms(op, &fio);
|
|
|
|
if (rc < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (strcmp(filename, "-")==0) {
|
|
|
|
if (fio.op == FIO_READ) {
|
|
|
|
fname = "<stdin>";
|
|
|
|
f = stdin;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
fname = "<stdout>";
|
|
|
|
f = stdout;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
fname = filename;
|
|
|
|
f = fopen(fname, fio.mode);
|
|
|
|
if (f == NULL) {
|
|
|
|
fprintf(stderr, "%s: can't open %s file %s: %s\n",
|
|
|
|
progname, fio.iodesc, fname, strerror(errno));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-01-22 01:59:47 +00:00
|
|
|
/* point at the requested memory buffer */
|
2001-10-13 03:12:52 +00:00
|
|
|
buf = p->mem[memtype].buf;
|
2001-01-22 01:59:47 +00:00
|
|
|
if (fio.op == FIO_READ)
|
2001-10-13 03:12:52 +00:00
|
|
|
size = p->mem[memtype].size;
|
2001-01-19 02:46:50 +00:00
|
|
|
|
|
|
|
if (fio.op == FIO_READ) {
|
|
|
|
/* 0xff fill unspecified memory */
|
|
|
|
for (i=0; i<size; i++) {
|
|
|
|
buf[i] = 0xff;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (format == FMT_AUTO) {
|
|
|
|
format = fmt_autodetect(fname);
|
|
|
|
if (format < 0) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"%s: can't determine file format for %s, specify explicitly\n",
|
|
|
|
progname, fname);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
fprintf(stderr, "%s: %s file %s auto detected as %s\n\n",
|
|
|
|
progname, fio.iodesc, fname, fmtstr(format));
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (format) {
|
|
|
|
case FMT_IHEX:
|
|
|
|
rc = fileio_ihex(&fio, fname, f, buf, size);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FMT_SREC:
|
|
|
|
rc = fileio_srec(&fio, fname, f, buf, size);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FMT_RBIN:
|
|
|
|
rc = fileio_rbin(&fio, fname, f, buf, size);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
fprintf(stderr, "%s: invalid %s file format: %d\n",
|
|
|
|
progname, fio.iodesc, format);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|