avrdude/src/term.c

1107 lines
28 KiB
C
Raw Normal View History

/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2000-2004 Brian S. Dean <bsd@bsdhome.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Id$ */
#include "ac_cfg.h"
#include <ctype.h>
#include <string.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <limits.h>
#if defined(HAVE_LIBREADLINE)
# include <readline/readline.h>
# include <readline/history.h>
#endif
#include "avrdude.h"
#include "term.h"
struct command {
char * name;
int (*func)(PROGRAMMER * pgm, struct avrpart * p, int argc, char *argv[]);
char * desc;
};
static int cmd_dump (PROGRAMMER * pgm, struct avrpart * p,
int argc, char *argv[]);
static int cmd_write (PROGRAMMER * pgm, struct avrpart * p,
int argc, char *argv[]);
static int cmd_erase (PROGRAMMER * pgm, struct avrpart * p,
int argc, char *argv[]);
static int cmd_sig (PROGRAMMER * pgm, struct avrpart * p,
int argc, char *argv[]);
static int cmd_part (PROGRAMMER * pgm, struct avrpart * p,
int argc, char *argv[]);
static int cmd_help (PROGRAMMER * pgm, struct avrpart * p,
int argc, char *argv[]);
static int cmd_quit (PROGRAMMER * pgm, struct avrpart * p,
int argc, char *argv[]);
static int cmd_send (PROGRAMMER * pgm, struct avrpart * p,
int argc, char *argv[]);
static int cmd_parms (PROGRAMMER * pgm, struct avrpart * p,
int argc, char *argv[]);
static int cmd_vtarg (PROGRAMMER * pgm, struct avrpart * p,
int argc, char *argv[]);
static int cmd_varef (PROGRAMMER * pgm, struct avrpart * p,
int argc, char *argv[]);
static int cmd_fosc (PROGRAMMER * pgm, struct avrpart * p,
int argc, char *argv[]);
static int cmd_sck (PROGRAMMER * pgm, struct avrpart * p,
int argc, char *argv[]);
static int cmd_spi (PROGRAMMER * pgm, struct avrpart * p,
int argc, char *argv[]);
static int cmd_pgm (PROGRAMMER * pgm, struct avrpart * p,
int argc, char *argv[]);
static int cmd_verbose (PROGRAMMER * pgm, 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>" },
2022-02-14 09:30:21 +00:00
{ "parms", cmd_parms, "display adjustable parameters (STK500 and Curiosity Nano only)" },
{ "vtarg", cmd_vtarg, "set <V[target]> (STK500 and Curiosity Nano only)" },
{ "varef", cmd_varef, "set <V[aref]> (STK500 only)" },
{ "fosc", cmd_fosc, "set <oscillator frequency> (STK500 only)" },
{ "sck", cmd_sck, "set <SCK period> (STK500 only)" },
{ "spi", cmd_spi, "enter direct SPI mode" },
{ "pgm", cmd_pgm, "return to programming mode" },
{ "verbose", cmd_verbose, "change verbosity" },
{ "help", cmd_help, "help" },
{ "?", cmd_help, "help" },
{ "quit", cmd_quit, "quit" }
};
#define NCMDS (sizeof(cmd)/sizeof(struct command))
static int spi_mode = 0;
static int nexttok(char * buf, char ** tok, char ** next)
{
char * q, * n;
q = buf;
while (isspace((int)*q))
q++;
/* isolate first token */
n = q+1;
while (*n && !isspace((int)*n))
n++;
if (*n) {
*n = 0;
n++;
}
/* find start of next token */
while (isspace((int)*n))
n++;
*tok = q;
*next = n;
return 0;
}
static 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;
}
static 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((int)(b[i])) || isdigit((int)(b[i])) || ispunct((int)(b[i])))
buffer[i] = b[i];
else if (isspace((int)(b[i])))
buffer[i] = ' ';
}
for (i=n; i<pad; i++)
buffer[i] = ' ';
buffer[i] = 0;
return 0;
}
static int hexdump_buf(FILE * f, int startaddr, unsigned char * buf, int len)
{
int addr;
int n;
unsigned char * p;
char dst1[80];
char dst2[80];
addr = startaddr;
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;
}
static int cmd_dump(PROGRAMMER * pgm, 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))) {
avrdude_message(MSG_INFO, "Usage: dump <memtype> [<addr> <len>]\n");
return -1;
}
memtype = argv[1];
if (strncmp(prevmem, memtype, strlen(memtype)) != 0) {
addr = 0;
2022-02-28 19:39:55 +00:00
len = 256;
strncpy(prevmem, memtype, sizeof(prevmem)-1);
prevmem[sizeof(prevmem)-1] = 0;
}
mem = avr_locate_mem(p, memtype);
if (mem == NULL) {
avrdude_message(MSG_INFO, "\"%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])) {
avrdude_message(MSG_INFO, "%s (dump): can't parse address \"%s\"\n",
progname, argv[2]);
return -1;
}
len = strtol(argv[3], &e, 0);
if (*e || (e == argv[3])) {
avrdude_message(MSG_INFO, "%s (dump): can't parse length \"%s\"\n",
progname, argv[3]);
return -1;
}
}
maxsize = mem->size;
if (addr >= maxsize) {
if (argc == 2) {
/* wrap around */
addr = 0;
}
else {
avrdude_message(MSG_INFO, "%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) {
avrdude_message(MSG_INFO, "%s (dump): out of memory\n", progname);
return -1;
}
for (i=0; i<len; i++) {
rc = pgm->read_byte(pgm, p, mem, addr+i, &buf[i]);
if (rc != 0) {
avrdude_message(MSG_INFO, "error reading %s address 0x%05lx of part %s\n",
mem->desc, addr+i, p->desc);
if (rc == -1)
avrdude_message(MSG_INFO, "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;
}
static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
int argc, char * argv[])
{
if (argc < 4) {
avrdude_message(MSG_INFO,
"Usage: write <memtype> <start addr> <data1> <data2> <dataN>\n"
" write <memtype> <start addr> <no. bytes> <data1> <dataN> <...>\n\n"
" Add a suffix to manually specify the size for each field:\n"
2022-03-02 19:24:51 +00:00
" HH/hh: 8-bit, H/h/S/s: 16-bit, L/l: 32-bit, LL/ll: 64-bit, F/f: 32-bit float\n");
return -1;
}
int32_t i;
uint8_t write_mode; // Operation mode, "standard" or "fill"
uint8_t start_offset; // Which argc argument
int32_t len; // Number of bytes to write to memory
char * memtype = argv[1]; // Memory name string
AVRMEM * mem = avr_locate_mem(p, memtype);
if (mem == NULL) {
avrdude_message(MSG_INFO, "\"%s\" memory type not defined for part \"%s\"\n",
memtype, p->desc);
return -1;
}
uint32_t maxsize = mem->size;
char * end_ptr;
int32_t addr = strtoul(argv[2], &end_ptr, 0);
if (*end_ptr || (end_ptr == argv[2])) {
avrdude_message(MSG_INFO, "%s (write): can't parse address \"%s\"\n",
progname, argv[2]);
return -1;
}
if (addr > maxsize) {
avrdude_message(MSG_INFO, "%s (write): address 0x%05lx is out of range for %s memory\n",
progname, addr, memtype);
return -1;
}
2022-03-03 18:37:42 +00:00
uint8_t * buf = malloc(mem->size);
if (buf == NULL) {
avrdude_message(MSG_INFO, "%s (write): out of memory\n", progname);
return -1;
}
// Find the first argument to write to flash and how many arguments to parse and write
2022-02-17 21:40:26 +00:00
if (strcmp(argv[argc - 1], "...") == 0) {
write_mode = WRITE_MODE_FILL;
2022-03-03 18:37:42 +00:00
start_offset = 4;
len = strtoul(argv[3], &end_ptr, 0);
if (*end_ptr || (end_ptr == argv[3])) {
avrdude_message(MSG_INFO, "%s (write ...): can't parse address \"%s\"\n",
progname, argv[3]);
return -1;
}
} else {
write_mode = WRITE_MODE_STANDARD;
2022-03-03 18:37:42 +00:00
start_offset = 3;
2022-02-17 21:40:26 +00:00
len = argc - start_offset;
}
// Structure related to data that is being written to memory
struct Data {
// Data info
int32_t bytes_grown;
uint8_t size;
bool is_float;
2022-02-21 12:43:38 +00:00
bool is_signed;
// Data union
union {
float f;
int64_t ll;
uint8_t a[8];
};
2022-02-21 12:43:38 +00:00
} data = {.bytes_grown = 0, .size = 0, .is_float = false, .ll = 0, .is_signed = false};
for (i = start_offset; i < len + start_offset; i++) {
data.is_float = false;
data.size = 0;
2022-02-17 21:40:26 +00:00
// Handle the next argument
if (i < argc - start_offset + 3) {
// Get suffix if present
char suffix = argv[i][strlen(argv[i]) - 1];
char lsuffix = argv[i][strlen(argv[i]) - 2];
if ((suffix == 'L' && lsuffix == 'L') || (suffix == 'l' && lsuffix == 'l')) {
argv[i][strlen(argv[i]) - 2] = '\0';
data.size = 8;
} else if (suffix == 'L' || suffix == 'l') {
argv[i][strlen(argv[i]) - 1] = '\0';
data.size = 4;
} else if ((suffix == 'F' || suffix == 'f') &&
strncmp(argv[i], "0x", 2) != 0 && strncmp(argv[i], "-0x", 3) != 0) {
argv[i][strlen(argv[i]) - 1] = '\0';
data.size = 4;
} else if ((suffix == 'H' && lsuffix == 'H') || (suffix == 'h' && lsuffix == 'h')) {
argv[i][strlen(argv[i]) - 2] = '\0';
data.size = 1;
} else if (suffix == 'H' || suffix == 'h' || suffix == 'S' || suffix == 's') {
argv[i][strlen(argv[i]) - 1] = '\0';
data.size = 2;
} else if (suffix == '\'') {
data.size = 1;
}
2022-02-17 21:40:26 +00:00
// Try integers
data.ll = strtoll(argv[i], &end_ptr, 0);
if (*end_ptr || (end_ptr == argv[i])) {
2022-02-17 21:40:26 +00:00
// Try float
data.f = strtof(argv[i], &end_ptr);
data.is_float = true;
if (*end_ptr || (end_ptr == argv[i])) {
data.is_float = false;
2022-02-17 21:40:26 +00:00
// Try single character
if (argv[i][0] == '\'' && argv[i][2] == '\'') {
data.ll = argv[i][1];
2022-02-17 21:40:26 +00:00
} else {
avrdude_message(MSG_INFO, "\n%s (write): can't parse data \"%s\"\n",
2022-02-17 21:40:26 +00:00
progname, argv[i]);
free(buf);
return -1;
}
}
}
2022-02-21 12:43:38 +00:00
// Print warning if data size might be ambiguous
bool is_hex = (strncmp(argv[i], "0x", 2) == 0);
bool is_neg_hex = (strncmp(argv[i], "-0x", 3) == 0);
bool leading_zero = (strncmp(argv[i], "0x0", 3) == 0);
int8_t hex_digits = (strlen(argv[i]) - 2);
if(!data.size // No pre-defined size
&& (is_neg_hex // Hex with - sign in front
|| (is_hex && leading_zero && (hex_digits & (hex_digits - 1))) // Hex with 3, 5, 6 or 7 digits
|| (!is_hex && !data.is_float && llabs(data.ll) > 0xFF && strlen(argv[i]) > 2))) // Base10 int greater than 255
{
avrdude_message(MSG_INFO, "Warning: no size suffix specified for \"%s\". "
"Writing %d byte(s)\n",
argv[i],
2022-02-21 12:43:38 +00:00
llabs(data.ll) > UINT32_MAX ? 8 :
llabs(data.ll) > UINT16_MAX || data.is_float ? 4 : \
llabs(data.ll) > UINT8_MAX ? 2 : 1);
}
// Flag if signed integer and adjust size
if (data.ll < 0 && !data.is_float) {
data.is_signed = true;
if (data.ll < INT32_MIN)
data.size = 8;
else if (data.ll < INT16_MIN)
data.size = 4;
else if (data.ll < INT8_MIN)
data.size = 2;
else
data.size = 1;
}
}
buf[i - start_offset + data.bytes_grown] = data.a[0];
if (llabs(data.ll) > 0x000000FF || data.size >= 2 || data.is_float)
buf[i - start_offset + ++data.bytes_grown] = data.a[1];
if (llabs(data.ll) > 0x0000FFFF || data.size >= 4 || data.is_float) {
buf[i - start_offset + ++data.bytes_grown] = data.a[2];
buf[i - start_offset + ++data.bytes_grown] = data.a[3];
}
if (llabs(data.ll) > 0xFFFFFFFF || data.size == 8) {
buf[i - start_offset + ++data.bytes_grown] = data.a[4];
buf[i - start_offset + ++data.bytes_grown] = data.a[5];
buf[i - start_offset + ++data.bytes_grown] = data.a[6];
buf[i - start_offset + ++data.bytes_grown] = data.a[7];
}
}
2022-02-17 21:40:26 +00:00
// When in "fill" mode, the maximum size is already predefined
if (write_mode == WRITE_MODE_FILL)
data.bytes_grown = 0;
2022-02-17 21:40:26 +00:00
if ((addr + len + data.bytes_grown) > maxsize) {
2022-02-17 21:40:26 +00:00
avrdude_message(MSG_INFO, "%s (write): selected address and # bytes exceed "
"range for %s memory\n",
progname, memtype);
return -1;
}
pgm->err_led(pgm, OFF);
bool werror = false;
for (i = 0; i < (len + data.bytes_grown); i++) {
int32_t rc = avr_write_byte(pgm, p, mem, addr+i, buf[i]);
if (rc) {
avrdude_message(MSG_INFO, "%s (write): error writing 0x%02x at 0x%05lx, rc=%d\n",
progname, buf[i], addr+i, rc);
if (rc == -1)
avrdude_message(MSG_INFO, "write operation not supported on memory type \"%s\"\n",
mem->desc);
werror = true;
}
uint8_t b;
rc = pgm->read_byte(pgm, p, mem, addr+i, &b);
if (b != buf[i]) {
avrdude_message(MSG_INFO, "%s (write): error writing 0x%02x at 0x%05lx cell=0x%02x\n",
progname, buf[i], addr+i, b);
werror = true;
}
if (werror) {
pgm->err_led(pgm, ON);
}
}
free(buf);
fprintf(stdout, "\n");
return 0;
}
static int cmd_send(PROGRAMMER * pgm, struct avrpart * p,
int argc, char * argv[])
{
unsigned char cmd[4], res[4];
char * e;
int i;
int len;
if (pgm->cmd == NULL) {
avrdude_message(MSG_INFO, "The %s programmer does not support direct ISP commands.\n",
pgm->type);
return -1;
}
if (spi_mode && (pgm->spi == NULL)) {
avrdude_message(MSG_INFO, "The %s programmer does not support direct SPI transfers.\n",
pgm->type);
return -1;
}
if ((argc > 5) || ((argc < 5) && (!spi_mode))) {
avrdude_message(MSG_INFO, spi_mode?
"Usage: send <byte1> [<byte2> [<byte3> [<byte4>]]]\n":
"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])) {
avrdude_message(MSG_INFO, "%s (send): can't parse byte \"%s\"\n",
progname, argv[i]);
return -1;
}
}
pgm->err_led(pgm, OFF);
if (spi_mode)
pgm->spi(pgm, cmd, res, argc-1);
else
pgm->cmd(pgm, cmd, res);
/*
* display results
*/
avrdude_message(MSG_INFO, "results:");
for (i=0; i<len; i++)
avrdude_message(MSG_INFO, " %02x", res[i]);
avrdude_message(MSG_INFO, "\n");
fprintf(stdout, "\n");
return 0;
}
static int cmd_erase(PROGRAMMER * pgm, struct avrpart * p,
int argc, char * argv[])
{
avrdude_message(MSG_INFO, "%s: erasing chip\n", progname);
pgm->chip_erase(pgm, p);
return 0;
}
static int cmd_part(PROGRAMMER * pgm, struct avrpart * p,
int argc, char * argv[])
{
fprintf(stdout, "\n");
avr_display(stdout, p, "", 0);
fprintf(stdout, "\n");
return 0;
}
static int cmd_sig(PROGRAMMER * pgm, struct avrpart * p,
int argc, char * argv[])
{
int i;
int rc;
AVRMEM * m;
rc = avr_signature(pgm, p);
if (rc != 0) {
avrdude_message(MSG_INFO, "error reading signature data, rc=%d\n",
rc);
}
m = avr_locate_mem(p, "signature");
if (m == NULL) {
avrdude_message(MSG_INFO, "signature data not defined for device \"%s\"\n",
p->desc);
}
else {
fprintf(stdout, "Device signature = 0x");
for (i=0; i<m->size; i++)
fprintf(stdout, "%02x", m->buf[i]);
fprintf(stdout, "\n\n");
}
return 0;
}
static int cmd_quit(PROGRAMMER * pgm, struct avrpart * p,
int argc, char * argv[])
{
/* FUSE bit verify will fail if left in SPI mode */
if (spi_mode) {
cmd_pgm(pgm, p, 0, NULL);
}
return 1;
}
static int cmd_parms(PROGRAMMER * pgm, struct avrpart * p,
int argc, char * argv[])
{
if (pgm->print_parms == NULL) {
avrdude_message(MSG_INFO, "%s (parms): the %s programmer does not support "
"adjustable parameters\n",
progname, pgm->type);
return -1;
}
pgm->print_parms(pgm);
return 0;
}
static int cmd_vtarg(PROGRAMMER * pgm, struct avrpart * p,
int argc, char * argv[])
{
int rc;
double v;
char *endp;
if (argc != 2) {
avrdude_message(MSG_INFO, "Usage: vtarg <value>\n");
return -1;
}
v = strtod(argv[1], &endp);
if (endp == argv[1]) {
avrdude_message(MSG_INFO, "%s (vtarg): can't parse voltage \"%s\"\n",
progname, argv[1]);
return -1;
}
if (pgm->set_vtarget == NULL) {
avrdude_message(MSG_INFO, "%s (vtarg): the %s programmer cannot set V[target]\n",
progname, pgm->type);
return -2;
}
if ((rc = pgm->set_vtarget(pgm, v)) != 0) {
avrdude_message(MSG_INFO, "%s (vtarg): failed to set V[target] (rc = %d)\n",
progname, rc);
return -3;
}
return 0;
}
static int cmd_fosc(PROGRAMMER * pgm, struct avrpart * p,
int argc, char * argv[])
{
int rc;
double v;
char *endp;
if (argc != 2) {
avrdude_message(MSG_INFO, "Usage: fosc <value>[M|k] | off\n");
return -1;
}
v = strtod(argv[1], &endp);
if (endp == argv[1]) {
if (strcmp(argv[1], "off") == 0)
v = 0.0;
else {
avrdude_message(MSG_INFO, "%s (fosc): can't parse frequency \"%s\"\n",
progname, argv[1]);
return -1;
}
}
if (*endp == 'm' || *endp == 'M')
v *= 1e6;
else if (*endp == 'k' || *endp == 'K')
v *= 1e3;
if (pgm->set_fosc == NULL) {
avrdude_message(MSG_INFO, "%s (fosc): the %s programmer cannot set oscillator frequency\n",
progname, pgm->type);
return -2;
}
if ((rc = pgm->set_fosc(pgm, v)) != 0) {
avrdude_message(MSG_INFO, "%s (fosc): failed to set oscillator frequency (rc = %d)\n",
progname, rc);
return -3;
}
return 0;
}
static int cmd_sck(PROGRAMMER * pgm, struct avrpart * p,
int argc, char * argv[])
{
int rc;
double v;
char *endp;
if (argc != 2) {
avrdude_message(MSG_INFO, "Usage: sck <value>\n");
return -1;
}
v = strtod(argv[1], &endp);
if (endp == argv[1]) {
avrdude_message(MSG_INFO, "%s (sck): can't parse period \"%s\"\n",
progname, argv[1]);
return -1;
}
v *= 1e-6; /* Convert from microseconds to seconds. */
if (pgm->set_sck_period == NULL) {
avrdude_message(MSG_INFO, "%s (sck): the %s programmer cannot set SCK period\n",
progname, pgm->type);
return -2;
}
if ((rc = pgm->set_sck_period(pgm, v)) != 0) {
avrdude_message(MSG_INFO, "%s (sck): failed to set SCK period (rc = %d)\n",
progname, rc);
return -3;
}
return 0;
}
static int cmd_varef(PROGRAMMER * pgm, struct avrpart * p,
int argc, char * argv[])
{
int rc;
Add initial support for the Atmel STK600, for "classic" AVRs (AT90, ATtiny, ATmega) in both, ISP and high-voltage programming modes. * Makefile.am: Add -lm. * avrdude.conf.in: Add stk600, stk600pp, and stk600hvsp. * config_gram.y: Add support for the stk600* keywords. * lexer.l: (Ditto.) * pgm.h: Add the "chan" parameter to set_varef(). * stk500.c: (Ditto.) * serial.h: Add USB endpoint support to struct filedescriptor. * stk500v2.c: Implement the meat of the STK600 support. * stk500v2.h: Add new prototypes for stk600*() programmers. * stk500v2_private.h: Add new constants used in the STK600. * term.c: Add AREF channel support. * usb_libusb.c: Automatically determine the correct write endpoint ID, the STK600 uses 0x83 while all other tools use 0x82. Propagate the EP to use through struct filedescriptor. * usbdevs.h: Add the STK600 USB product ID. * tools/get-stk600-cards.xsl: XSL transformation for targetboards.xml to obtain the list of socket and routing card IDs, to be used in stk500v2.c (for displaying the names). * tools/get-stk600-devices.xsl: XSL transformation for targetboards.xml to obtain the table of socket/routing cards and their respective AVR device support for doc/avrdude.texi. * avrdude.1: Document all the STK600 stuff. * doc/avrdude.texi: Ditto. Added a new chapter for Programmer Specific Information. Thanks to Eirik Rasmussen from Atmel Norway for his support in getting this code running within that short amount of time! git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@768 81a1dc3b-b13d-400b-aceb-764788c761c2
2008-03-14 13:00:08 +00:00
unsigned int chan;
double v;
char *endp;
Add initial support for the Atmel STK600, for "classic" AVRs (AT90, ATtiny, ATmega) in both, ISP and high-voltage programming modes. * Makefile.am: Add -lm. * avrdude.conf.in: Add stk600, stk600pp, and stk600hvsp. * config_gram.y: Add support for the stk600* keywords. * lexer.l: (Ditto.) * pgm.h: Add the "chan" parameter to set_varef(). * stk500.c: (Ditto.) * serial.h: Add USB endpoint support to struct filedescriptor. * stk500v2.c: Implement the meat of the STK600 support. * stk500v2.h: Add new prototypes for stk600*() programmers. * stk500v2_private.h: Add new constants used in the STK600. * term.c: Add AREF channel support. * usb_libusb.c: Automatically determine the correct write endpoint ID, the STK600 uses 0x83 while all other tools use 0x82. Propagate the EP to use through struct filedescriptor. * usbdevs.h: Add the STK600 USB product ID. * tools/get-stk600-cards.xsl: XSL transformation for targetboards.xml to obtain the list of socket and routing card IDs, to be used in stk500v2.c (for displaying the names). * tools/get-stk600-devices.xsl: XSL transformation for targetboards.xml to obtain the table of socket/routing cards and their respective AVR device support for doc/avrdude.texi. * avrdude.1: Document all the STK600 stuff. * doc/avrdude.texi: Ditto. Added a new chapter for Programmer Specific Information. Thanks to Eirik Rasmussen from Atmel Norway for his support in getting this code running within that short amount of time! git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@768 81a1dc3b-b13d-400b-aceb-764788c761c2
2008-03-14 13:00:08 +00:00
if (argc != 2 && argc != 3) {
avrdude_message(MSG_INFO, "Usage: varef [channel] <value>\n");
return -1;
}
Add initial support for the Atmel STK600, for "classic" AVRs (AT90, ATtiny, ATmega) in both, ISP and high-voltage programming modes. * Makefile.am: Add -lm. * avrdude.conf.in: Add stk600, stk600pp, and stk600hvsp. * config_gram.y: Add support for the stk600* keywords. * lexer.l: (Ditto.) * pgm.h: Add the "chan" parameter to set_varef(). * stk500.c: (Ditto.) * serial.h: Add USB endpoint support to struct filedescriptor. * stk500v2.c: Implement the meat of the STK600 support. * stk500v2.h: Add new prototypes for stk600*() programmers. * stk500v2_private.h: Add new constants used in the STK600. * term.c: Add AREF channel support. * usb_libusb.c: Automatically determine the correct write endpoint ID, the STK600 uses 0x83 while all other tools use 0x82. Propagate the EP to use through struct filedescriptor. * usbdevs.h: Add the STK600 USB product ID. * tools/get-stk600-cards.xsl: XSL transformation for targetboards.xml to obtain the list of socket and routing card IDs, to be used in stk500v2.c (for displaying the names). * tools/get-stk600-devices.xsl: XSL transformation for targetboards.xml to obtain the table of socket/routing cards and their respective AVR device support for doc/avrdude.texi. * avrdude.1: Document all the STK600 stuff. * doc/avrdude.texi: Ditto. Added a new chapter for Programmer Specific Information. Thanks to Eirik Rasmussen from Atmel Norway for his support in getting this code running within that short amount of time! git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@768 81a1dc3b-b13d-400b-aceb-764788c761c2
2008-03-14 13:00:08 +00:00
if (argc == 2) {
chan = 0;
v = strtod(argv[1], &endp);
if (endp == argv[1]) {
avrdude_message(MSG_INFO, "%s (varef): can't parse voltage \"%s\"\n",
Add initial support for the Atmel STK600, for "classic" AVRs (AT90, ATtiny, ATmega) in both, ISP and high-voltage programming modes. * Makefile.am: Add -lm. * avrdude.conf.in: Add stk600, stk600pp, and stk600hvsp. * config_gram.y: Add support for the stk600* keywords. * lexer.l: (Ditto.) * pgm.h: Add the "chan" parameter to set_varef(). * stk500.c: (Ditto.) * serial.h: Add USB endpoint support to struct filedescriptor. * stk500v2.c: Implement the meat of the STK600 support. * stk500v2.h: Add new prototypes for stk600*() programmers. * stk500v2_private.h: Add new constants used in the STK600. * term.c: Add AREF channel support. * usb_libusb.c: Automatically determine the correct write endpoint ID, the STK600 uses 0x83 while all other tools use 0x82. Propagate the EP to use through struct filedescriptor. * usbdevs.h: Add the STK600 USB product ID. * tools/get-stk600-cards.xsl: XSL transformation for targetboards.xml to obtain the list of socket and routing card IDs, to be used in stk500v2.c (for displaying the names). * tools/get-stk600-devices.xsl: XSL transformation for targetboards.xml to obtain the table of socket/routing cards and their respective AVR device support for doc/avrdude.texi. * avrdude.1: Document all the STK600 stuff. * doc/avrdude.texi: Ditto. Added a new chapter for Programmer Specific Information. Thanks to Eirik Rasmussen from Atmel Norway for his support in getting this code running within that short amount of time! git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@768 81a1dc3b-b13d-400b-aceb-764788c761c2
2008-03-14 13:00:08 +00:00
progname, argv[1]);
return -1;
}
} else {
chan = strtoul(argv[1], &endp, 10);
if (endp == argv[1]) {
avrdude_message(MSG_INFO, "%s (varef): can't parse channel \"%s\"\n",
Add initial support for the Atmel STK600, for "classic" AVRs (AT90, ATtiny, ATmega) in both, ISP and high-voltage programming modes. * Makefile.am: Add -lm. * avrdude.conf.in: Add stk600, stk600pp, and stk600hvsp. * config_gram.y: Add support for the stk600* keywords. * lexer.l: (Ditto.) * pgm.h: Add the "chan" parameter to set_varef(). * stk500.c: (Ditto.) * serial.h: Add USB endpoint support to struct filedescriptor. * stk500v2.c: Implement the meat of the STK600 support. * stk500v2.h: Add new prototypes for stk600*() programmers. * stk500v2_private.h: Add new constants used in the STK600. * term.c: Add AREF channel support. * usb_libusb.c: Automatically determine the correct write endpoint ID, the STK600 uses 0x83 while all other tools use 0x82. Propagate the EP to use through struct filedescriptor. * usbdevs.h: Add the STK600 USB product ID. * tools/get-stk600-cards.xsl: XSL transformation for targetboards.xml to obtain the list of socket and routing card IDs, to be used in stk500v2.c (for displaying the names). * tools/get-stk600-devices.xsl: XSL transformation for targetboards.xml to obtain the table of socket/routing cards and their respective AVR device support for doc/avrdude.texi. * avrdude.1: Document all the STK600 stuff. * doc/avrdude.texi: Ditto. Added a new chapter for Programmer Specific Information. Thanks to Eirik Rasmussen from Atmel Norway for his support in getting this code running within that short amount of time! git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@768 81a1dc3b-b13d-400b-aceb-764788c761c2
2008-03-14 13:00:08 +00:00
progname, argv[1]);
return -1;
}
v = strtod(argv[2], &endp);
if (endp == argv[2]) {
avrdude_message(MSG_INFO, "%s (varef): can't parse voltage \"%s\"\n",
Add initial support for the Atmel STK600, for "classic" AVRs (AT90, ATtiny, ATmega) in both, ISP and high-voltage programming modes. * Makefile.am: Add -lm. * avrdude.conf.in: Add stk600, stk600pp, and stk600hvsp. * config_gram.y: Add support for the stk600* keywords. * lexer.l: (Ditto.) * pgm.h: Add the "chan" parameter to set_varef(). * stk500.c: (Ditto.) * serial.h: Add USB endpoint support to struct filedescriptor. * stk500v2.c: Implement the meat of the STK600 support. * stk500v2.h: Add new prototypes for stk600*() programmers. * stk500v2_private.h: Add new constants used in the STK600. * term.c: Add AREF channel support. * usb_libusb.c: Automatically determine the correct write endpoint ID, the STK600 uses 0x83 while all other tools use 0x82. Propagate the EP to use through struct filedescriptor. * usbdevs.h: Add the STK600 USB product ID. * tools/get-stk600-cards.xsl: XSL transformation for targetboards.xml to obtain the list of socket and routing card IDs, to be used in stk500v2.c (for displaying the names). * tools/get-stk600-devices.xsl: XSL transformation for targetboards.xml to obtain the table of socket/routing cards and their respective AVR device support for doc/avrdude.texi. * avrdude.1: Document all the STK600 stuff. * doc/avrdude.texi: Ditto. Added a new chapter for Programmer Specific Information. Thanks to Eirik Rasmussen from Atmel Norway for his support in getting this code running within that short amount of time! git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@768 81a1dc3b-b13d-400b-aceb-764788c761c2
2008-03-14 13:00:08 +00:00
progname, argv[2]);
return -1;
}
}
if (pgm->set_varef == NULL) {
avrdude_message(MSG_INFO, "%s (varef): the %s programmer cannot set V[aref]\n",
progname, pgm->type);
return -2;
}
Add initial support for the Atmel STK600, for "classic" AVRs (AT90, ATtiny, ATmega) in both, ISP and high-voltage programming modes. * Makefile.am: Add -lm. * avrdude.conf.in: Add stk600, stk600pp, and stk600hvsp. * config_gram.y: Add support for the stk600* keywords. * lexer.l: (Ditto.) * pgm.h: Add the "chan" parameter to set_varef(). * stk500.c: (Ditto.) * serial.h: Add USB endpoint support to struct filedescriptor. * stk500v2.c: Implement the meat of the STK600 support. * stk500v2.h: Add new prototypes for stk600*() programmers. * stk500v2_private.h: Add new constants used in the STK600. * term.c: Add AREF channel support. * usb_libusb.c: Automatically determine the correct write endpoint ID, the STK600 uses 0x83 while all other tools use 0x82. Propagate the EP to use through struct filedescriptor. * usbdevs.h: Add the STK600 USB product ID. * tools/get-stk600-cards.xsl: XSL transformation for targetboards.xml to obtain the list of socket and routing card IDs, to be used in stk500v2.c (for displaying the names). * tools/get-stk600-devices.xsl: XSL transformation for targetboards.xml to obtain the table of socket/routing cards and their respective AVR device support for doc/avrdude.texi. * avrdude.1: Document all the STK600 stuff. * doc/avrdude.texi: Ditto. Added a new chapter for Programmer Specific Information. Thanks to Eirik Rasmussen from Atmel Norway for his support in getting this code running within that short amount of time! git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@768 81a1dc3b-b13d-400b-aceb-764788c761c2
2008-03-14 13:00:08 +00:00
if ((rc = pgm->set_varef(pgm, chan, v)) != 0) {
avrdude_message(MSG_INFO, "%s (varef): failed to set V[aref] (rc = %d)\n",
progname, rc);
return -3;
}
return 0;
}
static int cmd_help(PROGRAMMER * pgm, 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;
}
static int cmd_spi(PROGRAMMER * pgm, struct avrpart * p,
int argc, char * argv[])
{
if (pgm->setpin != NULL) {
pgm->setpin(pgm, PIN_AVR_RESET, 1);
spi_mode = 1;
return 0;
}
avrdude_message(MSG_INFO, "`spi' command unavailable for this programmer type\n");
return -1;
}
static int cmd_pgm(PROGRAMMER * pgm, struct avrpart * p,
int argc, char * argv[])
{
if (pgm->setpin != NULL) {
pgm->setpin(pgm, PIN_AVR_RESET, 0);
spi_mode = 0;
pgm->initialize(pgm, p);
return 0;
}
avrdude_message(MSG_INFO, "`pgm' command unavailable for this programmer type\n");
return -1;
}
static int cmd_verbose(PROGRAMMER * pgm, struct avrpart * p,
int argc, char * argv[])
{
int nverb;
char *endp;
if (argc != 1 && argc != 2) {
avrdude_message(MSG_INFO, "Usage: verbose [<value>]\n");
return -1;
}
if (argc == 1) {
avrdude_message(MSG_INFO, "Verbosity level: %d\n", verbose);
return 0;
}
nverb = strtol(argv[1], &endp, 0);
if (endp == argv[2]) {
avrdude_message(MSG_INFO, "%s: can't parse verbosity level \"%s\"\n",
progname, argv[2]);
return -1;
}
if (nverb < 0) {
avrdude_message(MSG_INFO, "%s: verbosity level must be positive: %d\n",
progname, nverb);
return -1;
}
verbose = nverb;
avrdude_message(MSG_INFO, "New verbosity level: %d\n", verbose);
return 0;
}
static int tokenize(char * s, char *** argv)
{
int i, n, l, k, nargs, offset;
int len, slen;
char * buf;
int bufsize;
char ** bufv;
char * bufp;
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) {
char *buf_tmp;
char **bufv_tmp;
/* realloc space for another 20 args */
bufsize += 20;
nargs += 20;
bufp = buf;
buf_tmp = realloc(buf, bufsize);
if (buf_tmp == NULL) {
free(buf);
free(bufv);
return -1;
}
buf = buf_tmp;
bufv_tmp = realloc(bufv, nargs*sizeof(char *));
if (bufv_tmp == NULL) {
free(buf);
free(bufv);
return -1;
}
bufv = bufv_tmp;
nbuf = &buf[l];
/* correct bufv pointers */
k = buf - bufp;
for (i=0; i<n; i++) {
bufv[i] = bufv[i] + k;
}
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;
}
static int do_cmd(PROGRAMMER * pgm, 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(pgm, p, argc, argv);
}
else if (strncasecmp(argv[0], cmd[i].name, len)==0) {
if (hold != -1) {
avrdude_message(MSG_INFO, "%s: command \"%s\" is ambiguous\n",
progname, argv[0]);
return -1;
}
hold = i;
}
}
if (hold != -1)
return cmd[hold].func(pgm, p, argc, argv);
avrdude_message(MSG_INFO, "%s: invalid command \"%s\"\n",
progname, argv[0]);
return -1;
}
char * terminal_get_input(const char *prompt)
{
2022-01-07 12:15:55 +00:00
#if defined(HAVE_LIBREADLINE) && !defined(WIN32)
char *input;
input = readline(prompt);
if ((input != NULL) && (strlen(input) >= 1))
add_history(input);
return input;
#else
char input[256];
printf("%s", prompt);
if (fgets(input, sizeof(input), stdin))
{
/* FIXME: readline strips the '\n', should this too? */
return strdup(input);
}
else
return NULL;
#endif
}
int terminal_mode(PROGRAMMER * pgm, struct avrpart * p)
{
char * cmdbuf;
int i;
char * q;
int rc;
int argc;
char ** argv;
rc = 0;
while ((cmdbuf = terminal_get_input("avrdude> ")) != NULL) {
/*
* find the start of the command, skipping any white space
*/
q = cmdbuf;
while (*q && isspace((int)*q))
q++;
/* skip blank lines and comments */
if (!*q || (*q == '#'))
continue;
/* tokenize command line */
argc = tokenize(q, &argv);
if (argc < 0) {
free(cmdbuf);
return argc;
}
fprintf(stdout, ">>> ");
for (i=0; i<argc; i++)
fprintf(stdout, "%s ", argv[i]);
fprintf(stdout, "\n");
/* run the command */
rc = do_cmd(pgm, p, argc, argv);
free(argv);
if (rc > 0) {
rc = 0;
break;
}
free(cmdbuf);
}
return rc;
}