/* * Copyright 2001 Brian S. Dean <bsd@bsdhome.com> * 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$ */ #include <stdio.h> #include <stdlib.h> #include <limits.h> #include <readline/readline.h> #include <readline/history.h> #include "avr.h" #include "config.h" #include "lists.h" #include "pindefs.h" #include "ppi.h" extern char * progname; extern char progbuf[]; extern PROGRAMMER * pgm; struct command { char * name; int (*func)(int fd, struct avrpart * p, int argc, char *argv[]); char * desc; }; char * term_version = "$Id$"; 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_erase (int fd, struct avrpart * p, int argc, char *argv[]); int cmd_sig (int fd, struct avrpart * p, int argc, char *argv[]); int cmd_part (int fd, struct avrpart * p, int argc, char *argv[]); int cmd_help (int fd, struct avrpart * p, int argc, char *argv[]); int cmd_quit (int fd, struct avrpart * p, int argc, char *argv[]); int cmd_send (int fd, struct avrpart * p, int argc, char *argv[]); struct command cmd[] = { { "dump", cmd_dump, "dump memory : %s <memtype> <addr> <N-Bytes>" }, { "read", cmd_dump, "alias for dump" }, { "write", cmd_write, "write memory : %s <memtype> <addr> <b1> <b2> ... <bN>" }, { "erase", cmd_erase, "perform a chip erase" }, { "sig", cmd_sig, "display device signature bytes" }, { "part", cmd_part, "display the current part information" }, { "send", cmd_send, "send a raw command : %s <b1> <b2> <b3> <b4>" }, { "help", cmd_help, "help" }, { "?", cmd_help, "help" }, { "quit", cmd_quit, "quit" } }; #define NCMDS (sizeof(cmd)/sizeof(struct command)) 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, unsigned 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; unsigned char * buf; int maxsize; unsigned long i; static unsigned long addr=0; static int len=64; AVRMEM * mem; char * memtype = NULL; int rc; if (!((argc == 2) || (argc == 4))) { fprintf(stderr, "Usage: dump <memtype> [<addr> <len>]\n"); return -1; } memtype = argv[1]; mem = avr_locate_mem(p, memtype); if (mem == NULL) { fprintf(stderr, "\"%s\" memory type not defined for part \"%s\"\n", memtype, p->desc); return -1; } if (argc == 4) { 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; } } maxsize = mem->size; if (addr > maxsize) { fprintf(stderr, "%s (dump): address 0x%05lx is out of range for %s memory\n", progname, addr, mem->desc); return -1; } /* trim len if nessary to not read past the end of memory */ if ((addr + len) > maxsize) len = maxsize - addr; buf = malloc(len); if (buf == NULL) { fprintf(stderr, "%s (dump): out of memory\n", progname); return -1; } for (i=0; i<len; i++) { rc = avr_read_byte(fd, p, mem, addr+i, &buf[i]); if (rc != 0) { fprintf(stderr, "error reading %s address 0x%05lx of part %s\n", mem->desc, addr+i, p->desc); return -1; } } hexdump_buf(stdout, addr, buf, len); fprintf(stdout, "\n"); free(buf); addr = addr + len; return 0; } int cmd_write(int fd, struct avrpart * p, int argc, char * argv[]) { char * e; int len, maxsize; char * memtype; unsigned long addr, i; char * buf; int rc; int werror; AVRMEM * mem; if (argc < 4) { fprintf(stderr, "Usage: write flash|eeprom|fuse <addr> <byte1> " "<byte2> ... byteN>\n"); return -1; } memtype = argv[1]; mem = avr_locate_mem(p, memtype); if (mem == NULL) { fprintf(stderr, "\"%s\" memory type not defined for part \"%s\"\n", memtype, p->desc); return -1; } maxsize = mem->size; 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%05lx is out of range for %s memory\n", progname, addr, 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, 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]); free(buf); return -1; } } LED_OFF(fd, pgm->pinno[PIN_LED_ERR]); for (werror=0, i=0; i<len; i++) { rc = avr_write_byte(fd, p, mem, addr+i, buf[i]); if (rc) { fprintf(stderr, "%s (write): error writing 0x%02x at 0x%05lx\n", progname, buf[i], addr+i); werror = 1; } if (werror) { LED_ON(fd, pgm->pinno[PIN_LED_ERR]); } } free(buf); fprintf(stdout, "\n"); return 0; } int cmd_send(int fd, struct avrpart * p, int argc, char * argv[]) { unsigned char cmd[4], res[4]; char * e; int i; int len; if (argc != 5) { fprintf(stderr, "Usage: send <byte1> <byte2> <byte3> <byte4>\n"); return -1; } /* number of bytes to write at the specified address */ len = argc - 1; /* load command bytes */ for (i=1; i<argc; i++) { cmd[i-1] = strtoul(argv[i], &e, 0); if (*e || (e == argv[i])) { fprintf(stderr, "%s (send): can't parse byte \"%s\"\n", progname, argv[i]); return -1; } } LED_OFF(fd, pgm->pinno[PIN_LED_ERR]); avr_cmd(fd, cmd, res); /* * display results */ fprintf(stderr, "results:"); for (i=0; i<len; i++) fprintf(stderr, " %02x", res[i]); fprintf(stderr, "\n"); fprintf(stdout, "\n"); return 0; } int cmd_erase(int fd, struct avrpart * p, int argc, char * argv[]) { fprintf(stderr, "%s: erasing chip\n", progname); avr_chip_erase(fd,p); return 0; } int cmd_part(int fd, struct avrpart * p, int argc, char * argv[]) { fprintf(stdout, "\n"); avr_display(stdout, p, ""); fprintf(stdout, "\n"); return 0; } int cmd_sig(int fd, struct avrpart * p, int argc, char * argv[]) { int i; int rc; AVRMEM * m; rc = avr_signature(fd, p); if (rc != 0) { fprintf(stderr, "error reading signature data, rc=%d\n", rc); } m = avr_locate_mem(p, "signature"); if (m == NULL) { fprintf(stderr, "signature data not defined for device \"%s\"\n", p->desc); } else { fprintf(stdout, "Device signature = 0x", progname); for (i=0; i<m->size; i++) fprintf(stdout, "%02x", m->buf[i]); fprintf(stdout, "\n\n"); } return 0; } int cmd_quit(int fd, struct avrpart * p, int argc, char * argv[]) { return 1; } int cmd_help(int fd, struct avrpart * p, int argc, char * argv[]) { int i; fprintf(stdout, "Valid commands:\n\n"); for (i=0; i<NCMDS; i++) { fprintf(stdout, " %-6s : ", cmd[i].name); fprintf(stdout, cmd[i].desc, cmd[i].name); fprintf(stdout, "\n"); } fprintf(stdout, "\nUse the 'part' command to display valid memory types for use with the\n" "'dump' and 'write' commands.\n\n"); return 0; } 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; int hold; int len; len = strlen(argv[0]); hold = -1; for (i=0; i<NCMDS; i++) { if (strcasecmp(argv[0], cmd[i].name) == 0) { return cmd[i].func(fd, p, argc, argv); } else if (strncasecmp(argv[0], cmd[i].name, len)==0) { if (hold != -1) { fprintf(stderr, "%s: command \"%s\" is ambiguous\n", progname, argv[0]); return -1; } hold = i; } } if (hold != -1) return cmd[hold].func(fd, p, argc, argv); fprintf(stderr, "%s: invalid command \"%s\"\n", progname, argv[0]); return -1; } int terminal_mode(int fd, struct avrpart * p) { char * cmdbuf; int i, len; char * q; int rc; int argc; char ** argv; rc = 0; while ((cmdbuf = readline("avrprog> ")) != NULL) { len = strlen(cmdbuf); if (len >= 1) add_history(cmdbuf); /* * 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"); /* run the command */ rc = do_cmd(fd, p, argc, argv); free(argv); if (rc > 0) { rc = 0; break; } free(cmdbuf); } return rc; }