666 lines
14 KiB
C
666 lines
14 KiB
C
/*
|
|
* Copyright (c) 2000, 2001, 2002 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[])
|
|
{
|
|
static char prevmem[128] = {0};
|
|
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];
|
|
|
|
if (strncmp(prevmem, memtype, strlen(memtype)) != 0) {
|
|
addr = 0;
|
|
len = 64;
|
|
strncpy(prevmem, memtype, sizeof(prevmem)-1);
|
|
prevmem[sizeof(prevmem)-1] = 0;
|
|
}
|
|
|
|
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);
|
|
if (rc == -1)
|
|
fprintf(stderr, "read operation not supported on memory type \"%s\"\n",
|
|
mem->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 <memtype> <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);
|
|
if (rc == -1)
|
|
fprintf(stderr,
|
|
"write operation not supported on memory type \"%s\"\n",
|
|
mem->desc);
|
|
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;
|
|
}
|
|
|
|
|