mirror of
https://github.com/avrdudes/avrdude.git
synced 2026-09-22 00:56:21 +03:00
Merge pull request #1373 from stefanrueger/terminal
Implement -T cmd to mix terminal commands with -U commands
This commit is contained in:
@@ -228,6 +228,7 @@ add_library(libavrdude
|
||||
strutil.c
|
||||
teensy.c
|
||||
teensy.h
|
||||
term.c
|
||||
tpi.h
|
||||
updi_constants.h
|
||||
updi_link.c
|
||||
@@ -292,8 +293,6 @@ target_link_libraries(libavrdude
|
||||
|
||||
add_executable(avrdude
|
||||
main.c
|
||||
term.c
|
||||
term.h
|
||||
developer_opts.c
|
||||
developer_opts.h
|
||||
developer_opts_private.h
|
||||
|
||||
@@ -175,6 +175,7 @@ libavrdude_a_SOURCES = \
|
||||
strutil.c \
|
||||
teensy.c \
|
||||
teensy.h \
|
||||
term.c \
|
||||
tpi.h \
|
||||
usbasp.c \
|
||||
usbasp.h \
|
||||
@@ -214,9 +215,7 @@ avrdude_SOURCES = \
|
||||
whereami.h \
|
||||
developer_opts.c \
|
||||
developer_opts.h \
|
||||
developer_opts_private.h \
|
||||
term.c \
|
||||
term.h
|
||||
developer_opts_private.h
|
||||
|
||||
man_MANS = avrdude.1
|
||||
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
.Op Fl O
|
||||
.Op Fl P Ar port
|
||||
.Op Fl q
|
||||
.Op Fl T Ar cmd
|
||||
.Op Fl t
|
||||
.Op Fl U Ar memtype:op:filename:filefmt
|
||||
.Op Fl v
|
||||
@@ -694,17 +695,28 @@ to the device. Specify it more often for even quieter operations.
|
||||
.It Fl s, u
|
||||
These options used to control the obsolete "safemode" feature which
|
||||
is no longer present. They are silently ignored for backwards compatibility.
|
||||
.It Fl T Ar cmd
|
||||
Slots a terminal command line
|
||||
.Ar cmd
|
||||
into the intermixed list of -T terminal commands and -U memory operations.
|
||||
The terminal command line is executed when it is its turn in the mixed list.
|
||||
Except for the simplest of terminal commands the argument
|
||||
.Ar cmd
|
||||
will most likely need to be set in quotes, see your OS shell manual for
|
||||
details.
|
||||
.It Fl t
|
||||
Tells
|
||||
.Nm
|
||||
to enter the interactive ``terminal'' mode instead of up- or downloading
|
||||
files. See below for a detailed description of the terminal mode.
|
||||
to enter the interactive terminal shell before up- or downloading files
|
||||
via the -U option or processing other -T terminal commands, if any. See
|
||||
below for a detailed description of the terminal mode.
|
||||
.It Xo Fl U Ar memtype Ns
|
||||
.Ar \&: Ns Ar op Ns
|
||||
.Ar \&: Ns Ar filename Ns
|
||||
.Op \&: Ns Ar format
|
||||
.Xc
|
||||
Perform a memory operation as indicated. The
|
||||
Perform a memory operation as indicated. Multiple -U operations are
|
||||
allowed. The
|
||||
.Ar memtype
|
||||
field specifies the memory type to operate on.
|
||||
The available memory types are device-dependent, the actual
|
||||
|
||||
@@ -757,9 +757,17 @@ to the device. Specify it a second time for even quieter operation.
|
||||
These options used to control the obsolete "safemode" feature which
|
||||
is no longer present. They are silently ignored for backwards compatibility.
|
||||
|
||||
@item -T @var{cmd}
|
||||
Slots a terminal command line @var{cmd} into the intermixed list of
|
||||
@code{-T} terminal commands and @code{-U} memory operations. The terminal
|
||||
command line is executed when it is its turn in the mixed list. Except for
|
||||
the simplest of terminal commands the argument @var{cmd} will most likely
|
||||
need to be set in quotes, see your OS shell manual for details.
|
||||
|
||||
@item -t
|
||||
Tells AVRDUDE to enter the interactive ``terminal'' mode instead of up-
|
||||
or downloading files. See below for a detailed description of the
|
||||
Tells AVRDUDE to enter the interactive terminal shell before uploading or
|
||||
downloading files via the @code{-U} option or processing other @code{-T}
|
||||
terminal commands, if any. See below for a detailed description of the
|
||||
terminal mode.
|
||||
|
||||
@item -U @var{memtype}:@var{op}:@var{filename}[:@var{format}]
|
||||
@@ -2563,6 +2571,66 @@ avrdude done. Thank you.
|
||||
@end cartouche
|
||||
@end smallexample
|
||||
|
||||
@page
|
||||
|
||||
@noindent
|
||||
@strong{Mixing terminal commands and @code{-U} memory operations:} the
|
||||
example below burns a bootloader, uses a terminal line to write
|
||||
application data to flash, loads the application, configures the brownout
|
||||
detection level to 2.7 V and, finally, stores the full flash as new hex
|
||||
file. Note the use of different quotation marks in @code{bash} to pass the
|
||||
terminal command lines as single entity to AVRDUDE.
|
||||
|
||||
@smallexample
|
||||
@cartouche
|
||||
|
||||
$ avrdude -qc dryrun -p m328p \
|
||||
-U urboot_m328p_1s_autobaud_uart0_pr_ee_ce.hex \
|
||||
-T 'write flash 0x7D00 0xc0cac01a 0xcafe "secret Coca Cola recipe"' \
|
||||
-U flash:w:cola-vending-machine.hex \
|
||||
-T "config -v bod=*2v7" \
|
||||
-U flash:r:app+data.hex:I
|
||||
|
||||
avrdude: AVR device initialized and ready to accept instructions
|
||||
avrdude: device signature = 0x1e950f (probably m328p)
|
||||
avrdude: Note: flash memory has been specified, an erase cycle will be performed.
|
||||
To disable this feature, specify the -D option.
|
||||
avrdude: erasing chip
|
||||
|
||||
avrdude: processing -U flash:w:urboot_m328p_1s_autobaud_uart0_pr_ee_ce.hex:i
|
||||
avrdude: reading input file urboot_m328p_1s_autobaud_uart0_pr_ee_ce.hex for flash
|
||||
with 368 bytes in 2 sections within [0x7e80, 0x7fff]
|
||||
using 3 pages and 16 pad bytes
|
||||
avrdude: writing 368 bytes flash ...
|
||||
avrdude: 368 bytes of flash written
|
||||
avrdude: verifying flash memory against urboot_m328p_1s_autobaud_uart0_pr_ee_ce.hex
|
||||
avrdude: 368 bytes of flash verified
|
||||
|
||||
avrdude: processing -T write flash 0x7D00 0xc0cac01a 0xcafe "secret Coca Cola recipe"
|
||||
avrdude: synching cache to device ... done
|
||||
|
||||
avrdude: processing -U flash:w:cola-vending-machine.hex:i
|
||||
avrdude: reading input file cola-vending-machine.hex for flash
|
||||
with 736 bytes in 1 section within [0, 0x2df]
|
||||
using 6 pages and 32 pad bytes
|
||||
avrdude: writing 736 bytes flash ...
|
||||
avrdude: 736 bytes of flash written
|
||||
avrdude: verifying flash memory against cola-vending-machine.hex
|
||||
avrdude: 736 bytes of flash verified
|
||||
|
||||
avrdude: processing -T config -v bod=*2v7
|
||||
config bodlevel=bod_2v7 # 5
|
||||
|
||||
avrdude: processing -U flash:r:app+data.hex:I
|
||||
avrdude: reading flash memory ...
|
||||
avrdude: writing output file app+data.hex
|
||||
|
||||
avrdude done. Thank you.
|
||||
|
||||
@end cartouche
|
||||
@end smallexample
|
||||
|
||||
|
||||
@page
|
||||
|
||||
@c
|
||||
|
||||
31
src/fileio.c
31
src/fileio.c
@@ -130,7 +130,36 @@ char *fileio_fmtstr(FILEFMT format) {
|
||||
return "octal byte list";
|
||||
default:
|
||||
return "invalid format";
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
int fileio_fmtchr(FILEFMT format) {
|
||||
switch (format) {
|
||||
case FMT_AUTO:
|
||||
return 'a';
|
||||
case FMT_SREC:
|
||||
return 's';
|
||||
case FMT_IHEX:
|
||||
return 'i';
|
||||
case FMT_IHXC:
|
||||
return 'I';
|
||||
case FMT_RBIN:
|
||||
return 'r';
|
||||
case FMT_ELF:
|
||||
return 'e';
|
||||
case FMT_IMM:
|
||||
return 'm';
|
||||
case FMT_BIN:
|
||||
return 'b';
|
||||
case FMT_DEC:
|
||||
return 'd';
|
||||
case FMT_HEX:
|
||||
return 'h';
|
||||
case FMT_OCT:
|
||||
return 'o';
|
||||
default:
|
||||
return '?';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1020,6 +1020,8 @@ FILEFMT fileio_format(char c);
|
||||
|
||||
char *fileio_fmtstr(FILEFMT format);
|
||||
|
||||
int fileio_fmtchr(FILEFMT format);
|
||||
|
||||
FILE *fileio_fopenr(const char *fname);
|
||||
|
||||
int fileio_fmt_autodetect_fp(FILE *f);
|
||||
@@ -1051,10 +1053,11 @@ enum updateflags {
|
||||
|
||||
|
||||
typedef struct update_t {
|
||||
char * memtype;
|
||||
int op;
|
||||
char * filename;
|
||||
int format;
|
||||
const char *cmdline; // -T line is stored here and takes precedence if it exists
|
||||
char *memtype; // Memory name for -U
|
||||
int op; // Symbolic memory operation DEVICE_... for -U
|
||||
char *filename; // Filename for -U, can be -
|
||||
int format; // File format FMT_...
|
||||
} UPDATE;
|
||||
|
||||
typedef struct { // File reads for flash can exclude trailing 0xff, which are cut off
|
||||
@@ -1072,21 +1075,15 @@ typedef struct { // File reads for flash can exclude trailing 0xf
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern UPDATE * parse_op(char * s);
|
||||
extern UPDATE * dup_update(UPDATE * upd);
|
||||
extern UPDATE * new_update(int op, char * memtype, int filefmt,
|
||||
char * filename);
|
||||
extern void free_update(UPDATE * upd);
|
||||
extern int do_op(const PROGRAMMER *pgm, const AVRPART *p, UPDATE *upd,
|
||||
enum updateflags flags);
|
||||
|
||||
extern int memstats(const AVRPART *p, const char *memtype, int size, Filestats *fsp);
|
||||
|
||||
// Convenience functions for printing
|
||||
const char *update_plural(int x);
|
||||
const char *update_inname(const char *fn);
|
||||
const char *update_outname(const char *fn);
|
||||
const char *update_interval(int a, int b);
|
||||
UPDATE *parse_op(const char *s);
|
||||
UPDATE *dup_update(const UPDATE *upd);
|
||||
UPDATE *new_update(int op, const char *memstr, int filefmt, const char *fname);
|
||||
UPDATE *cmd_update(const char *cmd);
|
||||
extern void free_update(UPDATE *upd);
|
||||
char *update_str(const UPDATE *upd);
|
||||
int do_op(const PROGRAMMER *pgm, const AVRPART *p, const UPDATE *upd,
|
||||
enum updateflags flags);
|
||||
int memstats(const AVRPART *p, const char *memtype, int size, Filestats *fsp);
|
||||
|
||||
// Helper functions for dry run to determine file access
|
||||
int update_is_okfile(const char *fn);
|
||||
@@ -1235,6 +1232,10 @@ char *str_uc(char *s);
|
||||
char *str_lcfirst(char *s);
|
||||
char *str_ucfirst(char *s);
|
||||
char *str_utoa(unsigned n, char *buf, int base);
|
||||
const char *str_plural(int x);
|
||||
const char *str_inname(const char *fn);
|
||||
const char *str_outname(const char *fn);
|
||||
const char *str_interval(int a, int b);
|
||||
bool is_bigendian();
|
||||
void change_endian(void *p, int size);
|
||||
int memall(const void *p, char c, size_t n);
|
||||
@@ -1245,6 +1246,12 @@ unsigned long long int str_int(const char *str, int type, const char **errpp);
|
||||
int str_membuf(const char *str, int type, unsigned char *buf, int size, const char **errpp);
|
||||
char *str_nexttok(char *buf, const char *delim, char **next);
|
||||
|
||||
int terminal_mode(const PROGRAMMER *pgm, const AVRPART *p);
|
||||
int terminal_mode_noninteractive(const PROGRAMMER *pgm, const AVRPART *p);
|
||||
int terminal_line(const PROGRAMMER *pgm, const AVRPART *p, const char *line);
|
||||
char *terminal_get_input(const char *prompt);
|
||||
void terminal_setup_update_progress();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
75
src/main.c
75
src/main.c
@@ -49,7 +49,6 @@
|
||||
#include "avrdude.h"
|
||||
#include "libavrdude.h"
|
||||
#include "config.h"
|
||||
#include "term.h"
|
||||
#include "developer_opts.h"
|
||||
|
||||
/* Get VERSION from ac_cfg.h */
|
||||
@@ -225,34 +224,35 @@ static void usage(void)
|
||||
msg_error(
|
||||
"Usage: %s [options]\n"
|
||||
"Options:\n"
|
||||
" -p <partno> Specify AVR device\n"
|
||||
" -p <wildcard>/<flags> Run developer options for matched AVR devices\n"
|
||||
" -b <baudrate> Override RS-232 baud rate\n"
|
||||
" -B <bitclock> Specify bit clock period (us)\n"
|
||||
" -C <config-file> Specify location of configuration file\n"
|
||||
" -c <programmer> Specify programmer type\n"
|
||||
" -c <wildcard>/<flags> Run developer options for matched programmers\n"
|
||||
" -A Disable trailing-0xff removal from file and AVR read\n"
|
||||
" -D Disable auto erase for flash memory; implies -A\n"
|
||||
" -i <delay> ISP Clock Delay [in microseconds]\n"
|
||||
" -P <port> Specify connection port\n"
|
||||
" -F Override invalid signature or initialisation check\n"
|
||||
" -e Perform a chip erase\n"
|
||||
" -O Perform RC oscillator calibration (see AVR053)\n"
|
||||
" -p <partno> Specify AVR device\n"
|
||||
" -p <wildcard>/<flags> Run developer options for matched AVR devices\n"
|
||||
" -b <baudrate> Override RS-232 baud rate\n"
|
||||
" -B <bitclock> Specify bit clock period (us)\n"
|
||||
" -C <config-file> Specify location of configuration file\n"
|
||||
" -c <programmer> Specify programmer type\n"
|
||||
" -c <wildcard>/<flags> Run developer options for matched programmers\n"
|
||||
" -A Disable trailing-0xff removal for file/AVR read\n"
|
||||
" -D Disable auto erase for flash memory; implies -A\n"
|
||||
" -i <delay> ISP Clock Delay [in microseconds]\n"
|
||||
" -P <port> Specify connection port\n"
|
||||
" -F Override invalid signature or initial checks\n"
|
||||
" -e Perform a chip erase\n"
|
||||
" -O Perform RC oscillator calibration (see AVR053)\n"
|
||||
" -t Enter terminal shell before processing -U/T\n"
|
||||
" -T <terminal cmd line> Slot terminal line into a list and run in turn\n"
|
||||
" -U <memtype>:r|w|v:<filename>[:format]\n"
|
||||
" Memory operation specification\n"
|
||||
" Multiple -U options are allowed, each request\n"
|
||||
" is performed in the order specified\n"
|
||||
" -n Do not write to the device whilst processing -U\n"
|
||||
" -V Do not automatically verify during -U\n"
|
||||
" -t Enter terminal mode\n"
|
||||
" -E <exitspec>[,<exitspec>] List programmer exit specifications\n"
|
||||
" -x <extended_param> Pass <extended_param> to programmer, see -xhelp\n"
|
||||
" -v Verbose output; -v -v for more\n"
|
||||
" -q Quell progress output; -q -q for less\n"
|
||||
" -l logfile Use logfile rather than stderr for diagnostics\n"
|
||||
" -? Display this usage\n"
|
||||
"\navrdude version %s, URL: <https://github.com/avrdudes/avrdude>\n",
|
||||
" Memory operation specification\n"
|
||||
" Multiple -U/T options are allowed; each request\n"
|
||||
" is performed in the specified intermixed order\n"
|
||||
" -n Do not write to the device whilst processing -U\n"
|
||||
" -V Do not automatically verify during -U\n"
|
||||
" -E <exitsp>[,<exitsp>] List programmer exit specifications\n"
|
||||
" -x <extended_param> Pass <extended_param> to programmer, see -xhelp\n"
|
||||
" -v Verbose output; -v -v for more\n"
|
||||
" -q Quell progress output; -q -q for less\n"
|
||||
" -l logfile Use logfile rather than stderr for diagnostics\n"
|
||||
" -? Display this usage\n"
|
||||
"\navrdude version %s, https://github.com/avrdudes/avrdude\n",
|
||||
progname, version);
|
||||
}
|
||||
|
||||
@@ -632,7 +632,7 @@ int main(int argc, char * argv [])
|
||||
/*
|
||||
* process command line arguments
|
||||
*/
|
||||
while ((ch = getopt(argc,argv,"?Ab:B:c:C:DeE:Fi:l:np:OP:qstU:uvVx:yY:")) != -1) {
|
||||
while ((ch = getopt(argc,argv,"?Ab:B:c:C:DeE:Fi:l:np:OP:qstT:U:uvVx:yY:")) != -1) {
|
||||
|
||||
switch (ch) {
|
||||
case 'b': /* override default programmer baud rate */
|
||||
@@ -772,6 +772,10 @@ int main(int argc, char * argv [])
|
||||
pmsg_error("\"safemode\" feature no longer supported\n");
|
||||
break;
|
||||
|
||||
case 'T':
|
||||
ladd(updates, cmd_update(optarg));
|
||||
break;
|
||||
|
||||
case 'U':
|
||||
upd = parse_op(optarg);
|
||||
if (upd == NULL) {
|
||||
@@ -1235,7 +1239,7 @@ int main(int argc, char * argv [])
|
||||
int doexit = 0;
|
||||
for (ln=lfirst(updates); ln; ln=lnext(ln)) {
|
||||
upd = ldata(ln);
|
||||
if (upd->memtype == NULL) {
|
||||
if (upd->memtype == NULL && upd->cmdline == NULL) {
|
||||
const char *mtype = p->prog_modes & PM_PDI? "application": "flash";
|
||||
pmsg_notice2("defaulting memtype in -U %c:%s option to \"%s\"\n",
|
||||
(upd->op == DEVICE_READ)? 'r': (upd->op == DEVICE_WRITE)? 'w': 'v',
|
||||
@@ -1445,6 +1449,8 @@ int main(int argc, char * argv [])
|
||||
uflags &= ~UF_AUTO_ERASE;
|
||||
for (ln=lfirst(updates); ln; ln=lnext(ln)) {
|
||||
upd = ldata(ln);
|
||||
if(!upd->memtype)
|
||||
continue;
|
||||
m = avr_locate_mem(p, upd->memtype);
|
||||
if (m == NULL)
|
||||
continue;
|
||||
@@ -1495,8 +1501,16 @@ int main(int argc, char * argv [])
|
||||
}
|
||||
|
||||
|
||||
int wrmem = 0;
|
||||
for (ln=lfirst(updates); ln; ln=lnext(ln)) {
|
||||
upd = ldata(ln);
|
||||
if(upd->cmdline && wrmem) { // Invalidate cache if device was written to
|
||||
wrmem = 0;
|
||||
pgm->reset_cache(pgm, p);
|
||||
} else if(!upd->cmdline) { // Flush cache before any device memory access
|
||||
pgm->flush_cache(pgm, p);
|
||||
wrmem |= upd->op == DEVICE_WRITE;
|
||||
}
|
||||
rc = do_op(pgm, p, upd, uflags);
|
||||
if (rc && rc != LIBAVRDUDE_SOFTFAIL) {
|
||||
exitrc = 1;
|
||||
@@ -1504,6 +1518,7 @@ int main(int argc, char * argv [])
|
||||
} else if(rc == 0 && upd->op == DEVICE_WRITE && avr_memtype_is_flash_type(upd->memtype))
|
||||
ce_delayed = 0; // Redeemed chip erase promise
|
||||
}
|
||||
pgm->flush_cache(pgm, p);
|
||||
|
||||
main_exit:
|
||||
|
||||
|
||||
@@ -298,6 +298,39 @@ char *str_utoa(unsigned n, char *buf, int base) {
|
||||
}
|
||||
|
||||
|
||||
// Convenience functions for printing
|
||||
const char *str_plural(int x) {
|
||||
return x==1? "": "s";
|
||||
}
|
||||
|
||||
const char *str_inname(const char *fn) {
|
||||
return !fn? "???": strcmp(fn, "-")? fn: "<stdin>";
|
||||
}
|
||||
|
||||
const char *str_outname(const char *fn) {
|
||||
return !fn? "???": strcmp(fn, "-")? fn: "<stdout>";
|
||||
}
|
||||
|
||||
// Return sth like "[0, 0x1ff]"
|
||||
const char *str_interval(int a, int b) {
|
||||
// Cyclic buffer for 20+ temporary interval strings each max 41 bytes at 64-bit int
|
||||
static char space[20*41 + 80], *sp;
|
||||
if(!sp || sp-space > (int) sizeof space - 80)
|
||||
sp = space;
|
||||
|
||||
char *ret = sp;
|
||||
|
||||
sprintf(sp, a<16? "[%d": "[0x%x", a);
|
||||
sp += strlen(sp);
|
||||
sprintf(sp, b<16? ", %d]": ", 0x%x]", b);
|
||||
|
||||
// Advance beyond return string in temporary ring buffer
|
||||
sp += strlen(sp)+1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
bool is_bigendian() {
|
||||
union {char a[2]; int16_t i;} u = {.i = 1};
|
||||
return u.a[1] == 1;
|
||||
|
||||
153
src/term.c
153
src/term.c
@@ -56,37 +56,36 @@
|
||||
|
||||
|
||||
#include "avrdude.h"
|
||||
#include "term.h"
|
||||
|
||||
struct command {
|
||||
char *name;
|
||||
int (*func)(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]);
|
||||
int (*func)(const PROGRAMMER *pgm, const AVRPART *p, int argc, char *argv[]);
|
||||
size_t fnoff;
|
||||
char *desc;
|
||||
};
|
||||
|
||||
|
||||
static int cmd_dump (PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]);
|
||||
static int cmd_write (PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]);
|
||||
static int cmd_flush (PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]);
|
||||
static int cmd_abort (PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]);
|
||||
static int cmd_erase (PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]);
|
||||
static int cmd_pgerase(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]);
|
||||
static int cmd_config (PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]);
|
||||
static int cmd_sig (PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]);
|
||||
static int cmd_part (PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]);
|
||||
static int cmd_help (PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]);
|
||||
static int cmd_quit (PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]);
|
||||
static int cmd_send (PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]);
|
||||
static int cmd_parms (PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]);
|
||||
static int cmd_vtarg (PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]);
|
||||
static int cmd_varef (PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]);
|
||||
static int cmd_fosc (PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]);
|
||||
static int cmd_sck (PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]);
|
||||
static int cmd_spi (PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]);
|
||||
static int cmd_pgm (PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]);
|
||||
static int cmd_verbose(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]);
|
||||
static int cmd_quell (PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]);
|
||||
static int cmd_dump (const PROGRAMMER *pgm, const AVRPART *p, int argc, char *argv[]);
|
||||
static int cmd_write (const PROGRAMMER *pgm, const AVRPART *p, int argc, char *argv[]);
|
||||
static int cmd_flush (const PROGRAMMER *pgm, const AVRPART *p, int argc, char *argv[]);
|
||||
static int cmd_abort (const PROGRAMMER *pgm, const AVRPART *p, int argc, char *argv[]);
|
||||
static int cmd_erase (const PROGRAMMER *pgm, const AVRPART *p, int argc, char *argv[]);
|
||||
static int cmd_pgerase(const PROGRAMMER *pgm, const AVRPART *p, int argc, char *argv[]);
|
||||
static int cmd_config (const PROGRAMMER *pgm, const AVRPART *p, int argc, char *argv[]);
|
||||
static int cmd_sig (const PROGRAMMER *pgm, const AVRPART *p, int argc, char *argv[]);
|
||||
static int cmd_part (const PROGRAMMER *pgm, const AVRPART *p, int argc, char *argv[]);
|
||||
static int cmd_help (const PROGRAMMER *pgm, const AVRPART *p, int argc, char *argv[]);
|
||||
static int cmd_quit (const PROGRAMMER *pgm, const AVRPART *p, int argc, char *argv[]);
|
||||
static int cmd_send (const PROGRAMMER *pgm, const AVRPART *p, int argc, char *argv[]);
|
||||
static int cmd_parms (const PROGRAMMER *pgm, const AVRPART *p, int argc, char *argv[]);
|
||||
static int cmd_vtarg (const PROGRAMMER *pgm, const AVRPART *p, int argc, char *argv[]);
|
||||
static int cmd_varef (const PROGRAMMER *pgm, const AVRPART *p, int argc, char *argv[]);
|
||||
static int cmd_fosc (const PROGRAMMER *pgm, const AVRPART *p, int argc, char *argv[]);
|
||||
static int cmd_sck (const PROGRAMMER *pgm, const AVRPART *p, int argc, char *argv[]);
|
||||
static int cmd_spi (const PROGRAMMER *pgm, const AVRPART *p, int argc, char *argv[]);
|
||||
static int cmd_pgm (const PROGRAMMER *pgm, const AVRPART *p, int argc, char *argv[]);
|
||||
static int cmd_verbose(const PROGRAMMER *pgm, const AVRPART *p, int argc, char *argv[]);
|
||||
static int cmd_quell (const PROGRAMMER *pgm, const AVRPART *p, int argc, char *argv[]);
|
||||
|
||||
#define _fo(x) offsetof(PROGRAMMER, x)
|
||||
|
||||
@@ -172,7 +171,7 @@ static int chardump_line(char *buffer, unsigned char *p, int n, int pad) {
|
||||
}
|
||||
|
||||
|
||||
static int hexdump_buf(FILE *f, AVRMEM *m, int startaddr, unsigned char *buf, int len) {
|
||||
static int hexdump_buf(const FILE *f, const AVRMEM *m, int startaddr, const unsigned char *buf, int len) {
|
||||
char dst1[80];
|
||||
char dst2[80];
|
||||
|
||||
@@ -199,11 +198,11 @@ static int hexdump_buf(FILE *f, AVRMEM *m, int startaddr, unsigned char *buf, in
|
||||
}
|
||||
|
||||
|
||||
static int cmd_dump(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
|
||||
static int cmd_dump(const PROGRAMMER *pgm, const AVRPART *p, int argc, char *argv[]) {
|
||||
static struct mem_addr_len {
|
||||
int addr;
|
||||
int len;
|
||||
AVRMEM *mem;
|
||||
const AVRMEM *mem;
|
||||
} read_mem[32];
|
||||
static int i;
|
||||
const char *cmd = tolower(**argv) == 'd'? "dump": "read";
|
||||
@@ -233,7 +232,7 @@ static int cmd_dump(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
|
||||
memtype = argv[1];
|
||||
else
|
||||
memtype = (char*)read_mem[i].mem->desc;
|
||||
AVRMEM *mem = avr_locate_mem(p, memtype);
|
||||
const AVRMEM *mem = avr_locate_mem(p, memtype);
|
||||
if (mem == NULL) {
|
||||
pmsg_error("(%s) %s memory type not defined for part %s\n", cmd, memtype, p->desc);
|
||||
return -1;
|
||||
@@ -363,8 +362,12 @@ static size_t maxstrlen(int argc, char **argv) {
|
||||
return max;
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
WRITE_MODE_STANDARD = 0,
|
||||
WRITE_MODE_FILL = 1,
|
||||
} Write_mode_t;
|
||||
|
||||
static int cmd_write(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
|
||||
static int cmd_write(const PROGRAMMER *pgm, const AVRPART *p, int argc, char *argv[]) {
|
||||
if (argc < 3 || (argc > 1 && str_eq(argv[1], "-?"))) {
|
||||
msg_error(
|
||||
"Syntax: write <mem> <addr> <data>[,] {<data>[,]}\n"
|
||||
@@ -419,7 +422,7 @@ static int cmd_write(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
|
||||
int start_offset; // Which argc argument
|
||||
int len; // Number of bytes to write to memory
|
||||
char *memtype = argv[1]; // Memory name string
|
||||
AVRMEM *mem = avr_locate_mem(p, memtype);
|
||||
const AVRMEM *mem = avr_locate_mem(p, memtype);
|
||||
if (mem == NULL) {
|
||||
pmsg_error("(write) %s memory type not defined for part %s\n", memtype, p->desc);
|
||||
return -1;
|
||||
@@ -575,7 +578,7 @@ static int cmd_write(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
|
||||
if(write_mode == WRITE_MODE_FILL) {
|
||||
if(recorded < len) {
|
||||
pmsg_warning("(write ...) can only fill %d < %d byte%s as last item has zero bytes\n",
|
||||
recorded, len, update_plural(recorded));
|
||||
recorded, len, str_plural(recorded));
|
||||
len = recorded;
|
||||
}
|
||||
bytes_grown = 0;
|
||||
@@ -585,7 +588,7 @@ static int cmd_write(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
pmsg_notice2("(write) writing %d byte%s starting from address 0x%02x",
|
||||
len + bytes_grown, update_plural(len + bytes_grown), addr);
|
||||
len + bytes_grown, str_plural(len + bytes_grown), addr);
|
||||
if (write_mode == WRITE_MODE_FILL && filling)
|
||||
msg_notice2("; remaining space filled with %s", argv[argc - 2]);
|
||||
msg_notice2("\v");
|
||||
@@ -632,7 +635,7 @@ static int cmd_write(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
|
||||
static int cmd_flush(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
|
||||
static int cmd_flush(const PROGRAMMER *pgm, const AVRPART *p, int argc, char *argv[]) {
|
||||
if(argc > 1) {
|
||||
msg_error(
|
||||
"Syntax: flush\n"
|
||||
@@ -646,7 +649,7 @@ static int cmd_flush(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
|
||||
static int cmd_abort(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
|
||||
static int cmd_abort(const PROGRAMMER *pgm, const AVRPART *p, int argc, char *argv[]) {
|
||||
if(argc > 1) {
|
||||
msg_error(
|
||||
"Syntax: abort\n"
|
||||
@@ -660,7 +663,7 @@ static int cmd_abort(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
|
||||
static int cmd_send(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
|
||||
static int cmd_send(const PROGRAMMER *pgm, const AVRPART *p, int argc, char *argv[]) {
|
||||
unsigned char cmd[4], res[4];
|
||||
const char *errptr;
|
||||
int i;
|
||||
@@ -713,7 +716,7 @@ static int cmd_send(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
|
||||
static int cmd_erase(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
|
||||
static int cmd_erase(const PROGRAMMER *pgm, const AVRPART *p, int argc, char *argv[]) {
|
||||
if (argc > 4 || argc == 3 || (argc > 1 && str_eq(argv[1], "-?"))) {
|
||||
msg_error(
|
||||
"Syntax: erase <mem> <addr> <len> # Fill section with 0xff values\n"
|
||||
@@ -726,7 +729,7 @@ static int cmd_erase(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
|
||||
|
||||
if (argc > 1) {
|
||||
char *memtype = argv[1];
|
||||
AVRMEM *mem = avr_locate_mem(p, memtype);
|
||||
const AVRMEM *mem = avr_locate_mem(p, memtype);
|
||||
if (mem == NULL) {
|
||||
pmsg_error("(erase) %s memory type not defined for part %s\n", argv[1], p->desc);
|
||||
return -1;
|
||||
@@ -752,7 +755,7 @@ static int cmd_erase(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
|
||||
|
||||
if(rc == LIBAVRDUDE_SOFTFAIL) {
|
||||
pmsg_info("(erase) emulating chip erase by writing 0xff to flash ");
|
||||
AVRMEM *flm = avr_locate_mem(p, "flash");
|
||||
const AVRMEM *flm = avr_locate_mem(p, "flash");
|
||||
if(!flm) {
|
||||
msg_error("but flash not defined for part %s?\n", p->desc);
|
||||
return -1;
|
||||
@@ -792,7 +795,7 @@ static int cmd_erase(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
|
||||
static int cmd_pgerase(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
|
||||
static int cmd_pgerase(const PROGRAMMER *pgm, const AVRPART *p, int argc, char *argv[]) {
|
||||
if(argc != 3 || (argc > 1 && str_eq(argv[1], "-?"))) {
|
||||
msg_error(
|
||||
"Syntax: pgerase <mem> <addr>\n"
|
||||
@@ -802,7 +805,7 @@ static int cmd_pgerase(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
char *memtype = argv[1];
|
||||
AVRMEM *mem = avr_locate_mem(p, memtype);
|
||||
const AVRMEM *mem = avr_locate_mem(p, memtype);
|
||||
if(!mem) {
|
||||
pmsg_error("(pgerase) %s memory type not defined for part %s\n", memtype, p->desc);
|
||||
return -1;
|
||||
@@ -837,7 +840,7 @@ static int cmd_pgerase(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
|
||||
|
||||
// Config command
|
||||
|
||||
const int MAX_PAD = 10; // Align value labels if difference between their lengths is less than this
|
||||
static const int MAX_PAD = 10; // Align value labels if difference between their lengths is less than this
|
||||
|
||||
typedef union { // Lock memory can be 1 or 4 bytes
|
||||
uint8_t b[4];
|
||||
@@ -889,7 +892,7 @@ static int getfusel(const PROGRAMMER *pgm, const AVRPART *p, Fusel_t *fl, const
|
||||
goto back;
|
||||
}
|
||||
|
||||
AVRMEM *mem = avr_locate_mem(p, cci->memstr);
|
||||
const AVRMEM *mem = avr_locate_mem(p, cci->memstr);
|
||||
if(!mem) {
|
||||
err = cache_string(tofree = str_sprintf("%s memory type not defined for part %s", cci->memstr, p->desc));
|
||||
free(tofree);
|
||||
@@ -1138,7 +1141,7 @@ static void printfuse(Cfg_t *cc, int ii, Flock_t *fc, int nf, int printed, Cfg_o
|
||||
term_out("#\n");
|
||||
}
|
||||
|
||||
static int cmd_config(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
|
||||
static int cmd_config(const PROGRAMMER *pgm, const AVRPART *p, int argc, char *argv[]) {
|
||||
Cfg_opts_t o = { 0 };
|
||||
int help = 0, invalid = 0, itemac=1;
|
||||
|
||||
@@ -1251,7 +1254,7 @@ static int cmd_config(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
|
||||
cc[i].t = ct+i;
|
||||
const char *mt = str_starts(ct[i].memtype, "lock")? locktype: ct[i].memtype;
|
||||
cc[i].memstr = mt;
|
||||
AVRMEM *mem = avr_locate_mem(p, mt);
|
||||
const AVRMEM *mem = avr_locate_mem(p, mt);
|
||||
if(!mem) {
|
||||
pmsg_warning("(config) %s unavailable as memory %s is not defined for %s\n", ct[i].name, mt, p->desc);
|
||||
continue;
|
||||
@@ -1413,7 +1416,7 @@ static int cmd_config(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
|
||||
|
||||
fl_t towrite;
|
||||
towrite.i = (fusel.current & ~ct[ci].mask) | (toassign<<ct[ci].lsh);
|
||||
AVRMEM *mem = avr_locate_mem(p, cc[ci].memstr);
|
||||
const AVRMEM *mem = avr_locate_mem(p, cc[ci].memstr);
|
||||
if(!mem) {
|
||||
pmsg_error("(config) %s memory type not defined for part %s\n", cc[ci].memstr, p->desc);
|
||||
ret = -1;
|
||||
@@ -1443,7 +1446,7 @@ finished:
|
||||
}
|
||||
|
||||
|
||||
static int cmd_part(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
|
||||
static int cmd_part(const PROGRAMMER *pgm, const AVRPART *p, int argc, char *argv[]) {
|
||||
if(argc > 1) {
|
||||
msg_error(
|
||||
"Syntax: part\n"
|
||||
@@ -1460,10 +1463,10 @@ static int cmd_part(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
|
||||
static int cmd_sig(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
|
||||
static int cmd_sig(const PROGRAMMER *pgm, const AVRPART *p, int argc, char *argv[]) {
|
||||
int i;
|
||||
int rc;
|
||||
AVRMEM *m;
|
||||
const AVRMEM *m;
|
||||
|
||||
if(argc > 1) {
|
||||
msg_error(
|
||||
@@ -1493,7 +1496,7 @@ static int cmd_sig(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
|
||||
static int cmd_quit(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
|
||||
static int cmd_quit(const PROGRAMMER *pgm, const AVRPART *p, int argc, char *argv[]) {
|
||||
if(argc > 1) {
|
||||
msg_error(
|
||||
"Syntax: quit\n"
|
||||
@@ -1510,7 +1513,7 @@ static int cmd_quit(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
|
||||
static int cmd_parms(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
|
||||
static int cmd_parms(const PROGRAMMER *pgm, const AVRPART *p, int argc, char *argv[]) {
|
||||
if(argc > 1) {
|
||||
msg_error(
|
||||
"Syntax: parms\n"
|
||||
@@ -1525,7 +1528,7 @@ static int cmd_parms(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
|
||||
static int cmd_vtarg(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
|
||||
static int cmd_vtarg(const PROGRAMMER *pgm, const AVRPART *p, int argc, char *argv[]) {
|
||||
int rc;
|
||||
double v;
|
||||
char *endp;
|
||||
@@ -1550,7 +1553,7 @@ static int cmd_vtarg(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
|
||||
static int cmd_fosc(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
|
||||
static int cmd_fosc(const PROGRAMMER *pgm, const AVRPART *p, int argc, char *argv[]) {
|
||||
int rc;
|
||||
double v;
|
||||
char *endp;
|
||||
@@ -1583,7 +1586,7 @@ static int cmd_fosc(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
|
||||
static int cmd_sck(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
|
||||
static int cmd_sck(const PROGRAMMER *pgm, const AVRPART *p, int argc, char *argv[]) {
|
||||
int rc;
|
||||
double v;
|
||||
char *endp;
|
||||
@@ -1609,7 +1612,7 @@ static int cmd_sck(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
|
||||
static int cmd_varef(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
|
||||
static int cmd_varef(const PROGRAMMER *pgm, const AVRPART *p, int argc, char *argv[]) {
|
||||
int rc;
|
||||
unsigned int chan;
|
||||
double v;
|
||||
@@ -1651,7 +1654,7 @@ static int cmd_varef(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
|
||||
static int cmd_help(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
|
||||
static int cmd_help(const PROGRAMMER *pgm, const AVRPART *p, int argc, char *argv[]) {
|
||||
if(argc > 1) {
|
||||
msg_error(
|
||||
"Syntax: help\n"
|
||||
@@ -1677,7 +1680,7 @@ static int cmd_help(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_spi(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
|
||||
static int cmd_spi(const PROGRAMMER *pgm, const AVRPART *p, int argc, char *argv[]) {
|
||||
if(argc > 1) {
|
||||
msg_error(
|
||||
"Syntax: spi\n"
|
||||
@@ -1691,7 +1694,7 @@ static int cmd_spi(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_pgm(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
|
||||
static int cmd_pgm(const PROGRAMMER *pgm, const AVRPART *p, int argc, char *argv[]) {
|
||||
if(argc > 1) {
|
||||
msg_error(
|
||||
"Syntax: pgm\n"
|
||||
@@ -1707,7 +1710,7 @@ static int cmd_pgm(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
|
||||
static int cmd_verbose(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
|
||||
static int cmd_verbose(const PROGRAMMER *pgm, const AVRPART *p, int argc, char *argv[]) {
|
||||
int nverb;
|
||||
const char *errptr;
|
||||
|
||||
@@ -1739,7 +1742,7 @@ static int cmd_verbose(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
|
||||
static int cmd_quell(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
|
||||
static int cmd_quell(const PROGRAMMER *pgm, const AVRPART *p, int argc, char *argv[]) {
|
||||
int nquell;
|
||||
const char *errptr;
|
||||
|
||||
@@ -1834,7 +1837,7 @@ static char *tokenize(char *s, int *argcp, char ***argvp) {
|
||||
}
|
||||
|
||||
|
||||
static int do_cmd(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
|
||||
static int do_cmd(const PROGRAMMER *pgm, const AVRPART *p, int argc, char *argv[]) {
|
||||
int i;
|
||||
int hold, matches;
|
||||
size_t len;
|
||||
@@ -1877,7 +1880,7 @@ char *terminal_get_input(const char *prompt) {
|
||||
}
|
||||
|
||||
|
||||
static int process_line(char *q, PROGRAMMER *pgm, struct avrpart *p) {
|
||||
static int process_line(char *q, const PROGRAMMER *pgm, const AVRPART *p) {
|
||||
int argc, rc = 0;
|
||||
char **argv;
|
||||
|
||||
@@ -1906,11 +1909,27 @@ static int process_line(char *q, PROGRAMMER *pgm, struct avrpart *p) {
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Process individual terminal line
|
||||
* - Used by main's -T argument
|
||||
* - The terminal manages a cache, -U does not: the caller is responsible for executing
|
||||
* + pgm->flush_cache(pgm, p) between -T line and -U memory read/avrdude exit
|
||||
* + pgm->reset_cache(pgm, p) between -U memory write and -T line
|
||||
*/
|
||||
|
||||
int terminal_line(const PROGRAMMER *pgm, const AVRPART *p, const char *line) {
|
||||
char *ln = cfg_strdup(__func__, line);
|
||||
int ret = process_line(ln, pgm, p);
|
||||
free(ln);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
#if defined(HAVE_LIBREADLINE)
|
||||
|
||||
static PROGRAMMER *term_pgm;
|
||||
static struct avrpart *term_p;
|
||||
static const PROGRAMMER *term_pgm;
|
||||
static const AVRPART *term_p;
|
||||
|
||||
static int term_running;
|
||||
|
||||
@@ -1960,7 +1979,7 @@ static int readytoread() {
|
||||
}
|
||||
|
||||
// Callback processes commands whenever readline() has finished
|
||||
void term_gotline(char *cmdstr) {
|
||||
static void term_gotline(char *cmdstr) {
|
||||
if(cmdstr) {
|
||||
if(*cmdstr) {
|
||||
add_history(cmdstr);
|
||||
@@ -1991,7 +2010,7 @@ void term_gotline(char *cmdstr) {
|
||||
}
|
||||
|
||||
|
||||
int terminal_mode_interactive(PROGRAMMER *pgm, struct avrpart *p) {
|
||||
static int terminal_mode_interactive(const PROGRAMMER *pgm, const AVRPART *p) {
|
||||
term_pgm = pgm; // For callback routine
|
||||
term_p = p;
|
||||
|
||||
@@ -2014,7 +2033,7 @@ int terminal_mode_interactive(PROGRAMMER *pgm, struct avrpart *p) {
|
||||
#endif
|
||||
|
||||
|
||||
int terminal_mode_noninteractive(PROGRAMMER *pgm, struct avrpart *p) {
|
||||
int terminal_mode_noninteractive(const PROGRAMMER *pgm, const AVRPART *p) {
|
||||
char *cmdbuf;
|
||||
int rc = 0;
|
||||
|
||||
@@ -2030,7 +2049,9 @@ int terminal_mode_noninteractive(PROGRAMMER *pgm, struct avrpart *p) {
|
||||
return pgm->flush_cache(pgm, p);
|
||||
}
|
||||
|
||||
int terminal_mode(PROGRAMMER *pgm, struct avrpart *p) {
|
||||
|
||||
// Terminal shell that is called on avrdude -t
|
||||
int terminal_mode(const PROGRAMMER *pgm, const AVRPART *p) {
|
||||
#if defined(HAVE_LIBREADLINE)
|
||||
// GNU libreadline can also work if input is a pipe.
|
||||
// EditLine (NetBSD, MacOS) has issues with that, so only use it when
|
||||
|
||||
43
src/term.h
43
src/term.h
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* 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$ */
|
||||
|
||||
#ifndef term_h
|
||||
#define term_h
|
||||
|
||||
#include "libavrdude.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
WRITE_MODE_STANDARD = 0,
|
||||
WRITE_MODE_FILL = 1,
|
||||
} mode;
|
||||
|
||||
int terminal_mode(PROGRAMMER * pgm, struct avrpart * p);
|
||||
char * terminal_get_input(const char *prompt);
|
||||
void terminal_setup_update_progress();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
129
src/update.c
129
src/update.c
@@ -42,15 +42,15 @@
|
||||
* flash write). This allows colons in filenames other than those for
|
||||
* enclosing <op> and separating <fmt>, eg, C:/some/file.hex
|
||||
*/
|
||||
UPDATE *parse_op(char *s) {
|
||||
UPDATE *parse_op(const char *s) {
|
||||
// Assume -U <file>[:<fmt>] first
|
||||
UPDATE *upd = (UPDATE *) cfg_malloc(__func__, sizeof *upd);
|
||||
upd->memtype = NULL; // Defaults to flash or application
|
||||
upd->op = DEVICE_WRITE;
|
||||
char *fn = s;
|
||||
const char *fn = s;
|
||||
|
||||
// Check for <memory>:c: start in which case override defaults
|
||||
char *fc = strchr(s, ':');
|
||||
const char *fc = strchr(s, ':');
|
||||
if(fc && fc[1] && fc[2] == ':') {
|
||||
if(!strchr("rwv", fc[1])) {
|
||||
pmsg_error("invalid I/O mode :%c: in -U %s\n", fc[1], s);
|
||||
@@ -95,8 +95,7 @@ UPDATE *parse_op(char *s) {
|
||||
}
|
||||
|
||||
|
||||
UPDATE * dup_update(UPDATE * upd)
|
||||
{
|
||||
UPDATE *dup_update(const UPDATE *upd) {
|
||||
UPDATE * u;
|
||||
|
||||
u = (UPDATE *) cfg_malloc("dup_update()", sizeof(UPDATE));
|
||||
@@ -112,20 +111,25 @@ UPDATE * dup_update(UPDATE * upd)
|
||||
return u;
|
||||
}
|
||||
|
||||
UPDATE * new_update(int op, char * memtype, int filefmt, char * filename)
|
||||
{
|
||||
UPDATE *new_update(int op, const char *memstr, int filefmt, const char *fname) {
|
||||
UPDATE * u;
|
||||
|
||||
u = (UPDATE *) cfg_malloc("new_update()", sizeof(UPDATE));
|
||||
|
||||
u->memtype = cfg_strdup("new_update()", memtype);
|
||||
u->filename = cfg_strdup("new_update()", filename);
|
||||
u->memtype = cfg_strdup("new_update()", memstr);
|
||||
u->filename = cfg_strdup("new_update()", fname);
|
||||
u->op = op;
|
||||
u->format = filefmt;
|
||||
|
||||
return u;
|
||||
}
|
||||
|
||||
UPDATE *cmd_update(const char *cmd) {
|
||||
UPDATE *u = (UPDATE *) cfg_malloc(__func__, sizeof *u);
|
||||
u->cmdline = cmd;
|
||||
return u;
|
||||
}
|
||||
|
||||
void free_update(UPDATE * u)
|
||||
{
|
||||
if (u != NULL) {
|
||||
@@ -141,6 +145,15 @@ void free_update(UPDATE * u)
|
||||
}
|
||||
}
|
||||
|
||||
char *update_str(const UPDATE *upd) {
|
||||
if(upd->cmdline)
|
||||
return str_sprintf("-T %s", upd->cmdline);
|
||||
return str_sprintf("-U %s:%c:%s:%c",
|
||||
upd->memtype,
|
||||
upd->op == DEVICE_READ? 'r': upd->op == DEVICE_WRITE? 'w': 'v',
|
||||
upd->filename,
|
||||
fileio_fmtchr(upd->format));
|
||||
}
|
||||
|
||||
// Memory statistics considering holes after a file read returned size bytes
|
||||
int memstats(const AVRPART *p, const char *memtype, int size, Filestats *fsp) {
|
||||
@@ -211,39 +224,6 @@ int memstats(const AVRPART *p, const char *memtype, int size, Filestats *fsp) {
|
||||
}
|
||||
|
||||
|
||||
// Convenience functions for printing
|
||||
const char *update_plural(int x) {
|
||||
return x==1? "": "s";
|
||||
}
|
||||
|
||||
const char *update_inname(const char *fn) {
|
||||
return !fn? "???": strcmp(fn, "-")? fn: "<stdin>";
|
||||
}
|
||||
|
||||
const char *update_outname(const char *fn) {
|
||||
return !fn? "???": strcmp(fn, "-")? fn: "<stdout>";
|
||||
}
|
||||
|
||||
// Return sth like "[0, 0x1ff]"
|
||||
const char *update_interval(int a, int b) {
|
||||
// Cyclic buffer for 20+ temporary interval strings each max 41 bytes at 64-bit int
|
||||
static char space[20*41 + 80], *sp;
|
||||
if(!sp || sp-space > (int) sizeof space - 80)
|
||||
sp = space;
|
||||
|
||||
char *ret = sp;
|
||||
|
||||
sprintf(sp, a<16? "[%d": "[0x%x", a);
|
||||
sp += strlen(sp);
|
||||
sprintf(sp, b<16? ", %d]": ", 0x%x]", b);
|
||||
|
||||
// Advance beyond return string in temporary ring buffer
|
||||
sp += strlen(sp)+1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
// Helper functions for dry run to determine file access
|
||||
|
||||
int update_is_okfile(const char *fn) {
|
||||
@@ -290,7 +270,7 @@ int update_is_readable(const char *fn) {
|
||||
static void ioerror(const char *iotype, const UPDATE *upd) {
|
||||
int errnocp = errno;
|
||||
|
||||
pmsg_ext_error("file %s is not %s: ", update_outname(upd->filename), iotype);
|
||||
pmsg_ext_error("file %s is not %s: ", str_outname(upd->filename), iotype);
|
||||
if(errnocp)
|
||||
msg_ext_error("%s", strerror(errnocp));
|
||||
else if(upd->filename && *upd->filename)
|
||||
@@ -298,13 +278,16 @@ static void ioerror(const char *iotype, const UPDATE *upd) {
|
||||
msg_ext_error("\n");
|
||||
}
|
||||
|
||||
// Basic checks to reveal serious failure before programming
|
||||
// Basic checks to reveal serious failure before programming (and on autodetect set format)
|
||||
int update_dryrun(const AVRPART *p, UPDATE *upd) {
|
||||
static char **wrote;
|
||||
static int nfwritten;
|
||||
|
||||
int known, format_detect, ret = LIBAVRDUDE_SUCCESS;
|
||||
|
||||
if(upd->cmdline) // Todo: parse terminal command line?
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Reject an update if memory name is not known amongst any part (suspect a typo)
|
||||
* but accept when the specific part does not have it (allow unifying i/faces)
|
||||
@@ -380,12 +363,20 @@ int update_dryrun(const AVRPART *p, UPDATE *upd) {
|
||||
}
|
||||
|
||||
|
||||
int do_op(const PROGRAMMER *pgm, const AVRPART *p, UPDATE *upd, enum updateflags flags) {
|
||||
int do_op(const PROGRAMMER *pgm, const AVRPART *p, const UPDATE *upd, enum updateflags flags) {
|
||||
AVRPART *v;
|
||||
AVRMEM *mem;
|
||||
int size;
|
||||
int rc;
|
||||
Filestats fs, fs_patched;
|
||||
char *tofree;
|
||||
|
||||
msg_info("\v\n");
|
||||
pmsg_info("processing %s\n", tofree = update_str(upd));
|
||||
free(tofree);
|
||||
|
||||
if(upd->cmdline)
|
||||
return terminal_line(pgm, p, upd->cmdline);
|
||||
|
||||
mem = avr_locate_mem(p, upd->memtype);
|
||||
if (mem == NULL) {
|
||||
@@ -422,11 +413,11 @@ int do_op(const PROGRAMMER *pgm, const AVRPART *p, UPDATE *upd, enum updateflags
|
||||
|
||||
if (rc == 0)
|
||||
pmsg_notice("flash is empty, resulting file has no contents\n");
|
||||
pmsg_info("writing output file %s\n", update_outname(upd->filename));
|
||||
pmsg_info("writing output file %s\n", str_outname(upd->filename));
|
||||
|
||||
rc = fileio(FIO_WRITE, upd->filename, upd->format, p, upd->memtype, size);
|
||||
if (rc < 0) {
|
||||
pmsg_error("write to file %s failed\n", update_outname(upd->filename));
|
||||
pmsg_error("write to file %s failed\n", str_outname(upd->filename));
|
||||
return LIBAVRDUDE_GENERAL_FAILURE;
|
||||
}
|
||||
break;
|
||||
@@ -436,27 +427,27 @@ int do_op(const PROGRAMMER *pgm, const AVRPART *p, UPDATE *upd, enum updateflags
|
||||
|
||||
rc = fileio(FIO_READ, upd->filename, upd->format, p, upd->memtype, -1);
|
||||
if (rc < 0) {
|
||||
pmsg_error("read from file %s failed\n", update_inname(upd->filename));
|
||||
pmsg_error("read from file %s failed\n", str_inname(upd->filename));
|
||||
return LIBAVRDUDE_GENERAL_FAILURE;
|
||||
}
|
||||
|
||||
pmsg_info("reading input file %s for %s%s\n",
|
||||
update_inname(upd->filename), mem->desc, alias_mem_desc);
|
||||
str_inname(upd->filename), mem->desc, alias_mem_desc);
|
||||
|
||||
if(memstats(p, upd->memtype, rc, &fs) < 0)
|
||||
return LIBAVRDUDE_GENERAL_FAILURE;
|
||||
|
||||
imsg_info("with %d byte%s in %d section%s within %s\n",
|
||||
fs.nbytes, update_plural(fs.nbytes),
|
||||
fs.nsections, update_plural(fs.nsections),
|
||||
update_interval(fs.firstaddr, fs.lastaddr));
|
||||
fs.nbytes, str_plural(fs.nbytes),
|
||||
fs.nsections, str_plural(fs.nsections),
|
||||
str_interval(fs.firstaddr, fs.lastaddr));
|
||||
if(mem->page_size > 1) {
|
||||
imsg_info("using %d page%s and %d pad byte%s",
|
||||
fs.npages, update_plural(fs.npages),
|
||||
fs.nfill, update_plural(fs.nfill));
|
||||
fs.npages, str_plural(fs.npages),
|
||||
fs.nfill, str_plural(fs.nfill));
|
||||
if(fs.ntrailing)
|
||||
msg_info(", cutting off %d trailing 0xff byte%s",
|
||||
fs.ntrailing, update_plural(fs.ntrailing));
|
||||
fs.ntrailing, str_plural(fs.ntrailing));
|
||||
msg_info("\n");
|
||||
}
|
||||
|
||||
@@ -466,7 +457,7 @@ int do_op(const PROGRAMMER *pgm, const AVRPART *p, UPDATE *upd, enum updateflags
|
||||
if(mem && !strcmp(mem->desc, "flash")) {
|
||||
rc = pgm->flash_readhook(pgm, p, mem, upd->filename, rc);
|
||||
if (rc < 0) {
|
||||
pmsg_notice("readhook for file %s failed\n", update_inname(upd->filename));
|
||||
pmsg_notice("readhook for file %s failed\n", str_inname(upd->filename));
|
||||
return LIBAVRDUDE_GENERAL_FAILURE;
|
||||
}
|
||||
if(memstats(p, upd->memtype, rc, &fs_patched) < 0)
|
||||
@@ -475,16 +466,16 @@ int do_op(const PROGRAMMER *pgm, const AVRPART *p, UPDATE *upd, enum updateflags
|
||||
pmsg_info("preparing flash input for device%s\n",
|
||||
pgm->prog_modes & PM_SPM? " bootloader": "");
|
||||
imsg_notice2("with %d byte%s in %d section%s within %s\n",
|
||||
fs_patched.nbytes, update_plural(fs_patched.nbytes),
|
||||
fs_patched.nsections, update_plural(fs_patched.nsections),
|
||||
update_interval(fs_patched.firstaddr, fs_patched.lastaddr));
|
||||
fs_patched.nbytes, str_plural(fs_patched.nbytes),
|
||||
fs_patched.nsections, str_plural(fs_patched.nsections),
|
||||
str_interval(fs_patched.firstaddr, fs_patched.lastaddr));
|
||||
if(mem->page_size > 1) {
|
||||
imsg_notice2("using %d page%s and %d pad byte%s",
|
||||
fs_patched.npages, update_plural(fs_patched.npages),
|
||||
fs_patched.nfill, update_plural(fs_patched.nfill));
|
||||
fs_patched.npages, str_plural(fs_patched.npages),
|
||||
fs_patched.nfill, str_plural(fs_patched.nfill));
|
||||
if(fs_patched.ntrailing)
|
||||
msg_notice2(", and %d trailing 0xff byte%s",
|
||||
fs_patched.ntrailing, update_plural(fs_patched.ntrailing));
|
||||
fs_patched.ntrailing, str_plural(fs_patched.ntrailing));
|
||||
msg_notice2("\n");
|
||||
}
|
||||
}
|
||||
@@ -494,7 +485,7 @@ int do_op(const PROGRAMMER *pgm, const AVRPART *p, UPDATE *upd, enum updateflags
|
||||
|
||||
// Write the buffer contents to the selected memory type
|
||||
pmsg_info("writing %d byte%s %s%s ...\n", fs.nbytes,
|
||||
update_plural(fs.nbytes), mem->desc, alias_mem_desc);
|
||||
str_plural(fs.nbytes), mem->desc, alias_mem_desc);
|
||||
|
||||
if (!(flags & UF_NOWRITE)) {
|
||||
if(mem->size > 32 || verbose > 1)
|
||||
@@ -512,7 +503,7 @@ int do_op(const PROGRAMMER *pgm, const AVRPART *p, UPDATE *upd, enum updateflags
|
||||
}
|
||||
|
||||
pmsg_info("%d byte%s of %s%s written\n", fs.nbytes,
|
||||
update_plural(fs.nbytes), mem->desc, alias_mem_desc);
|
||||
str_plural(fs.nbytes), mem->desc, alias_mem_desc);
|
||||
|
||||
if (!(flags & UF_VERIFY)) // Fall through for auto verify unless
|
||||
break;
|
||||
@@ -525,17 +516,17 @@ int do_op(const PROGRAMMER *pgm, const AVRPART *p, UPDATE *upd, enum updateflags
|
||||
int userverify = upd->op == DEVICE_VERIFY; // Explicit -U :v by user
|
||||
|
||||
pmsg_info("verifying %s%s memory against %s\n", mem->desc,
|
||||
alias_mem_desc, update_inname(upd->filename));
|
||||
alias_mem_desc, str_inname(upd->filename));
|
||||
|
||||
// No need to read file when fallen through from DEVICE_WRITE
|
||||
if (userverify) {
|
||||
pmsg_notice("load %s%s data from input file %s\n", mem->desc,
|
||||
alias_mem_desc, update_inname(upd->filename));
|
||||
alias_mem_desc, str_inname(upd->filename));
|
||||
|
||||
rc = fileio(FIO_READ_FOR_VERIFY, upd->filename, upd->format, p, upd->memtype, -1);
|
||||
|
||||
if (rc < 0) {
|
||||
pmsg_error("read from file %s failed\n", update_inname(upd->filename));
|
||||
pmsg_error("read from file %s failed\n", str_inname(upd->filename));
|
||||
return LIBAVRDUDE_GENERAL_FAILURE;
|
||||
}
|
||||
size = rc;
|
||||
@@ -552,7 +543,7 @@ int do_op(const PROGRAMMER *pgm, const AVRPART *p, UPDATE *upd, enum updateflags
|
||||
if (quell_progress < 2) {
|
||||
if (userverify)
|
||||
pmsg_notice("input file %s contains %d byte%s\n",
|
||||
update_inname(upd->filename), fs.nbytes, update_plural(fs.nbytes));
|
||||
str_inname(upd->filename), fs.nbytes, str_plural(fs.nbytes));
|
||||
pmsg_notice2("reading on-chip %s%s data ...\n", mem->desc, alias_mem_desc);
|
||||
}
|
||||
|
||||
@@ -579,7 +570,7 @@ int do_op(const PROGRAMMER *pgm, const AVRPART *p, UPDATE *upd, enum updateflags
|
||||
}
|
||||
|
||||
int verified = fs.nbytes+fs.ntrailing;
|
||||
pmsg_info("%d byte%s of %s%s verified\n", verified, update_plural(verified), mem->desc, alias_mem_desc);
|
||||
pmsg_info("%d byte%s of %s%s verified\n", verified, str_plural(verified), mem->desc, alias_mem_desc);
|
||||
|
||||
pgm->vfy_led(pgm, OFF);
|
||||
avr_free_part(v);
|
||||
|
||||
Reference in New Issue
Block a user