diff --git a/avrdude/avrprog.c b/avrdude/avrprog.c index af00d821..4a0db623 100644 --- a/avrdude/avrprog.c +++ b/avrdude/avrprog.c @@ -71,6 +71,9 @@ char * version = "$Id$"; char * progname; +char progbuf[PATH_MAX]; /* temporary buffer of spaces the same + length as progname; used for lining up + multiline messages */ /* @@ -153,6 +156,26 @@ enum { }; +int cmd_dump(int fd, struct avrpart * p, int argc, char *argv[]); +int cmd_write(int fd, struct avrpart * p, int argc, char *argv[]); +int cmd_quit(int fd, struct avrpart * p, int argc, char *argv[]); + +struct command { + char * name; + int (*func)(int fd, struct avrpart * p, int argc, char *argv[]); +}; + + +struct command cmd[] = { + { "dump", cmd_dump }, + { "write", cmd_write }, + { "quit", cmd_quit } +}; + +#define NCMDS (sizeof(cmd)/sizeof(struct command)) + + + #define MAX_LINE_LEN 256 /* max line length for ASCII format input files */ @@ -1235,6 +1258,482 @@ char * memtypestr ( AVRMEM memtype ) } +int nexttok ( char * buf, char ** tok, char ** next ) +{ + char * q, * n; + + q = buf; + while (isspace(*q)) + q++; + + /* isolate first token */ + n = q+1; + while (*n && !isspace(*n)) + n++; + + if (*n) { + *n = 0; + n++; + } + + /* find start of next token */ + while (isspace(*n)) + n++; + + *tok = q; + *next = n; + + return 0; +} + + +int hexdump_line ( char * buffer, unsigned char * p, int n, int pad ) +{ + char * hexdata = "0123456789abcdef"; + char * b; + int i, j; + + b = buffer; + + j = 0; + for (i=0; i<n; i++) { + if (i && ((i % 8) == 0)) + b[j++] = ' '; + b[j++] = hexdata[(p[i] & 0xf0) >> 4]; + b[j++] = hexdata[(p[i] & 0x0f)]; + if (i < 15) + b[j++] = ' '; + } + + for (i=j; i<pad; i++) + b[i] = ' '; + + b[i] = 0; + + for (i=0; i<pad; i++) { + if (!((b[i] == '0') || (b[i] == ' '))) + return 0; + } + + return 1; +} + + +int chardump_line ( char * buffer, unsigned char * p, int n, int pad ) +{ + int i; + char b [ 128 ]; + + for (i=0; i<n; i++) { + memcpy ( b, p, n ); + buffer[i] = '.'; + if (isalpha(b[i]) || isdigit(b[i]) || ispunct(b[i])) + buffer[i] = b[i]; + else if (isspace(b[i])) + buffer[i] = ' '; + } + + for (i=n; i<pad; i++) + buffer[i] = ' '; + + buffer[i] = 0; + + return 0; +} + + +int hexdump_buf ( FILE * f, int startaddr, char * buf, int len ) +{ + int addr; + int i, n; + unsigned char * p; + char dst1[80]; + char dst2[80]; + + addr = startaddr; + i = 0; + p = (unsigned char *)buf; + while (len) { + n = 16; + if (n > len) + n = len; + hexdump_line(dst1, p, n, 48); + chardump_line(dst2, p, n, 16); + fprintf(stdout, "%04x %s |%s|\n", addr, dst1, dst2); + len -= n; + addr += n; + p += n; + } + + return 0; +} + + +int cmd_dump ( int fd, struct avrpart * p, int argc, char * argv[] ) +{ + char * e; + int i, j; + int len, maxsize; + AVRMEM memtype; + unsigned short addr, daddr; + char * buf; + + if (argc != 4) { + fprintf(stderr, "Usage: dump flash|eeprom <addr> <len>\n"); + return -1; + } + + if (strcmp(argv[1],"flash")==0) { + memtype = AVR_FLASH; + maxsize = p->flash_size; + } + else if (strcmp(argv[1],"eeprom")==0) { + memtype = AVR_EEPROM; + maxsize = p->eeprom_size; + } + else { + fprintf(stderr, "%s (dump): invalid memory type \"%s\"\n", + progname, argv[1]); + return -1; + } + + addr = strtoul(argv[2], &e, 0); + if (*e || (e == argv[2])) { + fprintf(stderr, "%s (dump): can't parse address \"%s\"\n", + progname, argv[2]); + return -1; + } + + len = strtol(argv[3], &e, 0); + if (*e || (e == argv[3])) { + fprintf(stderr, "%s (dump): can't parse length \"%s\"\n", + progname, argv[3]); + return -1; + } + + if (addr > maxsize) { + fprintf(stderr, + "%s (dump): address 0x%04x is out of range for %s memory\n", + progname, addr, memtypestr(memtype)); + return -1; + } + + if ((addr + len) > maxsize) { + fprintf(stderr, + "%s (dump): selected address and length exceed " + "range for %s memory\n", + progname, memtypestr(memtype)); + return -1; + } + + buf = malloc(len); + if (buf == NULL) { + fprintf(stderr, "%s (dump): out of memory\n", progname); + return -1; + } + + j = 0; + daddr = addr; + if (memtype == AVR_FLASH) { + daddr = addr / 2; + if (addr & 0x01) { + buf[j++] = avr_read_byte( fd, p, AVR_FLASH_HI, daddr); + daddr++; + } + } + + i = daddr; + while (j < len) { + if (memtype == AVR_FLASH) { + buf[j++] = avr_read_byte( fd, p, AVR_FLASH_LO, i); + if (j < len) { + buf[j++] = avr_read_byte( fd, p, AVR_FLASH_HI, i); + } + } + else { + buf[j++] = avr_read_byte( fd, p, AVR_EEPROM, i); + } + i++; + } + + hexdump_buf(stdout, addr, buf, len); + + fprintf(stdout, "\n"); + + free(buf); + + return 0; +} + +int cmd_write ( int fd, struct avrpart * p, int argc, char * argv[] ) +{ + char * e; + int i, j; + int len, maxsize; + AVRMEM memtype; + unsigned short addr, daddr; + char * buf; + int rc; + + if (argc < 4) { + fprintf(stderr, + "Usage: write flash|eeprom <addr> <byte1> <byte2> ... byteN>\n"); + return -1; + } + + if (strcmp(argv[1],"flash")==0) { + memtype = AVR_FLASH; + maxsize = p->flash_size; + } + else if (strcmp(argv[1],"eeprom")==0) { + memtype = AVR_EEPROM; + maxsize = p->eeprom_size; + } + else { + fprintf(stderr, "%s (write): invalid memory type \"%s\"\n", + progname, argv[1]); + return -1; + } + + addr = strtoul(argv[2], &e, 0); + if (*e || (e == argv[2])) { + fprintf(stderr, "%s (write): can't parse address \"%s\"\n", + progname, argv[2]); + return -1; + } + + if (addr > maxsize) { + fprintf(stderr, + "%s (write): address 0x%04x is out of range for %s memory\n", + progname, addr, memtypestr(memtype)); + return -1; + } + + /* number of bytes to write at the specified address */ + len = argc - 3; + + if ((addr + len) > maxsize) { + fprintf(stderr, + "%s (write): selected address and # bytes exceed " + "range for %s memory\n", + progname, memtypestr(memtype)); + return -1; + } + + buf = malloc(len); + if (buf == NULL) { + fprintf(stderr, "%s (write): out of memory\n", progname); + return -1; + } + + for (i=3; i<argc; i++) { + buf[i-3] = strtoul(argv[i], &e, 0); + if (*e || (e == argv[i])) { + fprintf(stderr, "%s (write): can't parse byte \"%s\"\n", + progname, argv[i]); + return -1; + } + } + + j = 0; + daddr = addr; + if (memtype == AVR_FLASH) { + daddr = addr / 2; + if (addr & 0x01) { + /* handle odd numbered memory locations in the flash area */ + rc = avr_write_byte(fd, p, AVR_FLASH_HI, daddr, buf[j++]); + if (rc) { + fprintf(stderr, "%s (write): error writing 0x%02x at 0x%04x\n", + progname, buf[j-1], daddr*2+1); + } + daddr++; + } + } + + i = daddr; + while (j < len) { + if (memtype == AVR_FLASH) { + rc = avr_write_byte( fd, p, AVR_FLASH_LO, i, buf[j++]); + if (rc) { + fprintf(stderr, "%s (write): error writing 0x%02x at 0x%04x\n", + progname, buf[j-1], i*2); + } + if (j < len) { + rc = avr_write_byte( fd, p, AVR_FLASH_HI, i, buf[j++]); + if (rc) { + fprintf(stderr, "%s (write): error writing 0x%02x at 0x%04x\n", + progname, buf[j-1], i*2+1); + } + } + } + else { + rc = avr_write_byte( fd, p, AVR_EEPROM, i, buf[j++]); + if (rc) { + fprintf(stderr, "%s (write): error writing 0x%02x at 0x%04x\n", + progname, buf[j-1], i); + } + } + i++; + } + + fprintf(stdout, "\n"); + + return 0; +} + + +int cmd_quit ( int fd, struct avrpart * p, int argc, char * argv[] ) +{ + return 1; +} + + +int tokenize ( char * s, char *** argv ) +{ + int i, n, l, nargs, offset; + int len, slen; + char * buf; + int bufsize; + char ** bufv; + char * q, * r; + char * nbuf; + char ** av; + + slen = strlen(s); + + /* + * initialize allow for 20 arguments, use realloc to grow this if + * necessary + */ + nargs = 20; + bufsize = slen + 20; + buf = malloc(bufsize); + bufv = (char **) malloc(nargs*sizeof(char *)); + for (i=0; i<nargs; i++) { + bufv[i] = NULL; + } + buf[0] = 0; + + n = 0; + l = 0; + nbuf = buf; + r = s; + while (*r) { + nexttok(r, &q, &r); + strcpy(nbuf, q); + bufv[n] = nbuf; + len = strlen(q); + l += len + 1; + nbuf += len + 1; + nbuf[0] = 0; + n++; + if ((n % 20) == 0) { + /* realloc space for another 20 args */ + bufsize += 20; + nargs += 20; + buf = realloc(buf, bufsize); + bufv = realloc(bufv, nargs*sizeof(char *)); + nbuf = &buf[l]; + for (i=n; i<nargs; i++) + bufv[i] = NULL; + } + } + + /* + * We have parsed all the args, n == argc, bufv contains an array of + * pointers to each arg, and buf points to one memory block that + * contains all the args, back to back, seperated by a nul + * terminator. Consilidate bufv and buf into one big memory block + * so that the code that calls us, will have an easy job of freeing + * this memory. + */ + av = (char **) malloc(slen + n + (n+1)*sizeof(char *)); + q = (char *)&av[n+1]; + memcpy(q, buf, l); + for (i=0; i<n; i++) { + offset = bufv[i] - buf; + av[i] = q + offset; + } + av[i] = NULL; + + free(buf); + free(bufv); + + *argv = av; + + return n; +} + + +int do_cmd ( int fd, struct avrpart * p, int argc, char * argv[] ) +{ + int i; + + for (i=0; i<NCMDS; i++) { + if (strcasecmp(argv[0], cmd[i].name) == 0) { + return cmd[i].func(fd, p, argc, argv); + } + } + + fprintf(stderr, "%s: invalid command \"%s\"\n", + progname, argv[0]); + + return -1; +} + + +int go_interactive ( int fd, struct avrpart * p ) +{ + char cmdbuf[MAX_LINE_LEN]; + int i, len; + char * q; + int rc; + int argc; + char ** argv; + + fprintf(stdout, "avrprog> "); + while (fgets(cmdbuf, MAX_LINE_LEN, stdin) != NULL) { + len = strlen(cmdbuf); + if (cmdbuf[len-1] == '\n') + cmdbuf[--len] = 0; + + /* + * find the start of the command, skipping any white space + */ + q = cmdbuf; + while (*q && isspace(*q)) + q++; + + /* skip blank lines and comments */ + if (!*q || (*q == '#')) + continue; + + /* tokenize command line */ + argc = tokenize(q, &argv); + + fprintf(stdout, ">>> "); + for (i=0; i<argc; i++) + fprintf(stdout, "%s ", argv[i]); + fprintf(stdout, "\n"); + +#if 1 + /* run the command */ + rc = do_cmd(fd, p, argc, argv); + free(argv); + if (rc > 0) { + rc = 0; + break; + } +#endif + + fprintf(stdout, "avrprog> "); + } + + return rc; +} + + + /* * main routine */ @@ -1247,7 +1746,6 @@ int main ( int argc, char * argv [] ) int ch; /* options flag */ int size; /* size of memory region */ int len; /* length for various strings */ - char pbuf[PATH_MAX]; /* temporary buffer */ char * p1; /* used to parse CVS Id */ char * p2; /* used to parse CVS Ed */ unsigned char sig[4]; /* AVR signature bytes */ @@ -1286,8 +1784,8 @@ int main ( int argc, char * argv [] ) len = strlen(progname) + 2; for (i=0; i<len; i++) - pbuf[i] = ' '; - pbuf[i] = 0; + progbuf[i] = ' '; + progbuf[i] = 0; /* * Print out an identifying string so folks can tell what version @@ -1307,7 +1805,7 @@ int main ( int argc, char * argv [] ) fprintf(stderr, "\n"); fprintf(stderr, "%s: Copyright 2000 Brian Dean, bsd@bsdhome.com\n" - "%sRevision ", progname, pbuf); + "%sRevision ", progname, progbuf); for (i=0; i<p2-p1; i++) fprintf(stderr, "%c", p1[i]); fprintf(stderr, "\n\n"); @@ -1462,13 +1960,13 @@ int main ( int argc, char * argv [] ) "%sChip Erase delay = %d us\n" "%sFlash Polled Readback = 0x%02x\n" "%sEEPROM Polled Readback = 0x%02x, 0x%02x\n", - pbuf, p->partdesc, - pbuf, p->flash_size, - pbuf, p->eeprom_size, - pbuf, p->min_write_delay, p->max_write_delay, - pbuf, p->chip_erase_delay, - pbuf, p->f_readback, - pbuf, p->e_readback[0], p->e_readback[1]); + progbuf, p->partdesc, + progbuf, p->flash_size, + progbuf, p->eeprom_size, + progbuf, p->min_write_delay, p->max_write_delay, + progbuf, p->chip_erase_delay, + progbuf, p->f_readback, + progbuf, p->e_readback[0], p->e_readback[1]); fprintf(stderr, "\n"); p->flash = (unsigned char *) malloc(p->flash_size); @@ -1532,7 +2030,7 @@ int main ( int argc, char * argv [] ) fprintf(stderr, "%sDouble check connections and try again, or use -F to override\n" "%sthis check.\n\n", - pbuf, pbuf ); + progbuf, progbuf ); exit(1); } } @@ -1551,7 +2049,7 @@ int main ( int argc, char * argv [] ) } - if ((inputf==NULL) && (outputf==NULL)) { + if (!interactive && ((inputf==NULL) && (outputf==NULL))) { /* * Check here to see if any other operations were selected and * generate an error message because if they were, we need either @@ -1566,8 +2064,13 @@ int main ( int argc, char * argv [] ) goto main_exit; } - - if (doread) { + if (interactive) { + /* + * interactive command mode + */ + exitrc = go_interactive(fd, p); + } + else if (doread) { /* * read out the specified device memory and write it to a file */ @@ -1636,7 +2139,7 @@ int main ( int argc, char * argv [] ) close(fd); - fprintf(stderr, "\n" ); + fprintf(stderr, "\n%s done. Thank you.\n\n", progname); return exitrc; }