avrdude/src/main.c

1467 lines
41 KiB
C
Raw Permalink Normal View History

/*
* avrdude - A Downloader/Uploader for AVR device programmers
Mega-commit to bring in both, the STK500v2 support from Erik Walthinsen, as well as JTAG ICE mkII support (by me). Erik's submission has been cleaned up a little bit, mostly to add his name and the current year to the copyright of the new file, remove trailing white space before importing the files, and fix the minor syntax errors in his avrdude.conf.in additions (missing semicolons). The JTAG ICE mkII support should be considered alpha to beta quality at this point. Few things are still to be done, like defering the hfuse (OCDEN) tweaks until they are really required. Also, for reasons not yet known, the target MCU doesn't start to run after signing off from the ICE, it needs a power-cycle first (at least on my STK500). Note that for the JTAG ICE, I did change a few things in the internal API. Notably I made the serial receive timeout configurable by the backends via an exported variable (done in both the Posix and the Win32 implementation), and I made the serial_recv() function return a -1 instead of bailing out with exit(1) upon encountering a receive timeout (currently only done in the Posix implementation). Both measures together allow me to receive a datastreem from the ICE at 115 kbps on a somewhat lossy PCI multi-UART card that occasionally drops a character. The JTAG ICE mkII protocol has enough of safety layers to allow recovering from these events, but the previous code wasn't prepared for any kind of recovery. The Win32 change for this still has to be done, and the traditional drivers need to be converted to exit(1) upon encountering a timeout (as they're now getting a -1 returned they didn't see before in that case). git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@451 81a1dc3b-b13d-400b-aceb-764788c761c2
2005-05-10 19:17:12 +00:00
* Copyright (C) 2000-2005 Brian S. Dean <bsd@bsdhome.com>
* Copyright Joerg Wunsch <j@uriah.heep.sax.de>
*
* 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$ */
/*
Mega-commit to bring in both, the STK500v2 support from Erik Walthinsen, as well as JTAG ICE mkII support (by me). Erik's submission has been cleaned up a little bit, mostly to add his name and the current year to the copyright of the new file, remove trailing white space before importing the files, and fix the minor syntax errors in his avrdude.conf.in additions (missing semicolons). The JTAG ICE mkII support should be considered alpha to beta quality at this point. Few things are still to be done, like defering the hfuse (OCDEN) tweaks until they are really required. Also, for reasons not yet known, the target MCU doesn't start to run after signing off from the ICE, it needs a power-cycle first (at least on my STK500). Note that for the JTAG ICE, I did change a few things in the internal API. Notably I made the serial receive timeout configurable by the backends via an exported variable (done in both the Posix and the Win32 implementation), and I made the serial_recv() function return a -1 instead of bailing out with exit(1) upon encountering a receive timeout (currently only done in the Posix implementation). Both measures together allow me to receive a datastreem from the ICE at 115 kbps on a somewhat lossy PCI multi-UART card that occasionally drops a character. The JTAG ICE mkII protocol has enough of safety layers to allow recovering from these events, but the previous code wasn't prepared for any kind of recovery. The Win32 change for this still has to be done, and the traditional drivers need to be converted to exit(1) upon encountering a timeout (as they're now getting a -1 returned they didn't see before in that case). git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@451 81a1dc3b-b13d-400b-aceb-764788c761c2
2005-05-10 19:17:12 +00:00
* Code to program an Atmel AVR device through one of the supported
* programmers.
*
* For parallel port connected programmers, the pin definitions can be
* changed via a config file. See the config file for instructions on
* how to add a programmer definition.
*
*/
#include "ac_cfg.h"
#include <stdio.h>
#include <stdlib.h>
#include <whereami.h>
#include <stdarg.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include "avrdude.h"
#include "libavrdude.h"
#include "config.h"
#include "term.h"
#include "developer_opts.h"
/* Get VERSION from ac_cfg.h */
char * version = VERSION;
char * progname;
char progbuf[PATH_MAX]; /* temporary buffer of spaces the same
length as progname; used for lining up
multiline messages */
int avrdude_message(int msglvl, const char *format, ...)
{
int rc = 0;
va_list ap;
if (verbose >= msglvl) {
va_start(ap, format);
rc = vfprintf(stderr, format, ap);
va_end(ap);
}
return rc;
}
static const char *avrdude_message_type(int msglvl) {
switch(msglvl) {
case MSG_EXT_ERROR: return "OS error";
case MSG_ERROR: return "error";
case MSG_WARNING: return "warning";
case MSG_INFO: return "info";
case MSG_NOTICE: return "notice";
case MSG_NOTICE2: return "notice2";
case MSG_DEBUG: return "debug";
case MSG_TRACE: return "trace";
case MSG_TRACE2: return "trace2";
default: return "unknown msglvl";
}
}
int avrdude_message2(FILE *fp, int lno, const char *file, const char *func, int msgmode, int msglvl, const char *format, ...) {
int rc = 0;
va_list ap;
if(msglvl <= MSG_ERROR) // Serious error? Freee progress bars (if any)
report_progress(1, -1, NULL);
if(msgmode & MSG2_FLUSH) {
fflush(stdout);
fflush(stderr);
}
// Reduce effective verbosity level by number of -q above one when printing to stderr
if ((quell_progress < 2 || fp != stderr? verbose: verbose+1-quell_progress) >= msglvl) {
if(msgmode & MSG2_PROGNAME) {
fprintf(fp, "%s", progname);
if(verbose >= MSG_NOTICE && (msgmode & MSG2_FUNCTION))
fprintf(fp, " %s()", func);
if(verbose >= MSG_DEBUG && (msgmode & MSG2_FILELINE)) {
const char *pr = strrchr(file, '/'); // only print basename
#if defined (WIN32)
if(!pr)
pr = strrchr(file, '\\');
#endif
pr = pr? pr+1: file;
fprintf(fp, " [%s:%d]", pr, lno);
}
if(msgmode & MSG2_TYPE)
fprintf(fp, " %s", avrdude_message_type(msglvl));
fprintf(fp, ": ");
} else if(msgmode & MSG2_INDENT1) {
fprintf(fp, "%*s", (int) strlen(progname)+1, "");
} else if(msgmode & MSG2_INDENT2) {
fprintf(fp, "%*s", (int) strlen(progname)+2, "");
}
va_start(ap, format);
rc = vfprintf(fp, format, ap);
va_end(ap);
}
if(msgmode & MSG2_FLUSH)
fflush(fp);
return rc;
}
struct list_walk_cookie
{
FILE *f;
const char *prefix;
};
static LISTID updates = NULL;
static LISTID extended_params = NULL;
static LISTID additional_config_files = NULL;
static PROGRAMMER * pgm;
/*
* global options
*/
int verbose; // Verbose output
int quell_progress; // Quell progress report and un-verbose output
int ovsigck; // 1 = override sig check, 0 = don't
const char *partdesc; // Part id
/*
* usage message
*/
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"
2022-10-23 21:26:07 +00:00
" -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"
2022-10-23 21:26:07 +00:00
" -F Override invalid signature or initialisation check\n"
" -e Perform a chip erase\n"
" -O Perform RC oscillator calibration (see AVR053)\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 anything to the device\n"
" -V Do not verify\n"
" -t Enter terminal mode\n"
" -E <exitspec>[,<exitspec>] List programmer exit specifications\n"
" -x <extended_param> Pass <extended_param> to programmer\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"
2023-01-09 18:27:38 +00:00
"\navrdude version %s, URL: <https://github.com/mariusgreuel/avrdude>\n",
progname, version);
}
static char *via_prog_modes(int pm) {
static char type[1024];
strcpy(type, "?");
if(pm & PM_SPM)
strcat(type, ", bootloader");
if(pm & PM_TPI)
strcat(type, ", TPI");
if(pm & PM_ISP)
strcat(type, ", ISP");
if(pm & PM_PDI)
strcat(type, ", PDI");
if(pm & PM_UPDI)
strcat(type, ", UPDI");
if(pm & PM_HVSP)
strcat(type, ", HVSP");
if(pm & PM_HVPP)
strcat(type, ", HVPP");
if(pm & PM_debugWIRE)
strcat(type, ", debugWIRE");
if(pm & PM_JTAG)
strcat(type, ", JTAG");
if(pm & PM_JTAGmkI)
strcat(type, ", JTAGmkI");
if(pm & PM_XMEGAJTAG)
strcat(type, ", XMEGAJTAG");
if(pm & PM_AVR32JTAG)
strcat(type, ", AVR32JTAG");
if(pm & PM_aWire)
strcat(type, ", aWire");
return type + (type[1] == 0? 0: 3);
}
// Potentially shorten copy of prog description if it's the suggested mode
static void pmshorten(char *desc, const char *modes) {
struct { const char *end, *mode; } pairs[] = {
{" in parallel programming mode", "HVPP"},
{" in PP mode", "HVPP"},
{" in high-voltage serial programming mode", "HVSP"},
{" in HVSP mode", "HVSP"},
{" in ISP mode", "ISP"},
{" in debugWire mode", "debugWIRE"},
{" in AVR32 mode", "aWire"},
{" in PDI mode", "PDI"},
{" in UPDI mode", "UPDI"},
{" in JTAG mode", "JTAG"},
{" in JTAG mode", "JTAGmkI"},
{" in JTAG mode", "XMEGAJTAG"},
{" in JTAG mode", "AVR32JTAG"},
{" for bootloader", "bootloader"},
};
size_t len = strlen(desc);
for(size_t i=0; i<sizeof pairs/sizeof*pairs; i++) {
size_t elen = strlen(pairs[i].end);
if(len > elen && strcasecmp(desc+len-elen, pairs[i].end) == 0 && strcmp(modes, pairs[i].mode) == 0) {
desc[len-elen] = 0;
break;
}
}
}
static void list_programmers(FILE *f, const char *prefix, LISTID programmers, int pm) {
LNODEID ln1;
LNODEID ln2;
PROGRAMMER *pgm;
2022-09-16 18:09:35 +00:00
int maxlen=0, len;
sort_programmers(programmers);
2022-09-16 18:09:35 +00:00
// Compute max length of programmer names
for(ln1 = lfirst(programmers); ln1; ln1 = lnext(ln1)) {
pgm = ldata(ln1);
2022-09-16 18:09:35 +00:00
for(ln2=lfirst(pgm->id); ln2; ln2=lnext(ln2))
if(!pm || !pgm->prog_modes || (pm & pgm->prog_modes)) {
const char *id = ldata(ln2);
if(*id == 0 || *id == '.')
continue;
if((len = strlen(id)) > maxlen)
maxlen = len;
}
}
2022-09-16 18:09:35 +00:00
for(ln1 = lfirst(programmers); ln1; ln1 = lnext(ln1)) {
pgm = ldata(ln1);
for(ln2=lfirst(pgm->id); ln2; ln2=lnext(ln2)) {
// List programmer if pm or prog_modes uninitialised or if they are compatible otherwise
if(!pm || !pgm->prog_modes || (pm & pgm->prog_modes)) {
const char *id = ldata(ln2);
char *desc = cfg_strdup("list_programmers()", pgm->desc);
const char *modes = via_prog_modes(pm & pgm->prog_modes);
if(pm != ~0)
pmshorten(desc, modes);
if(*id == 0 || *id == '.')
continue;
if(verbose)
fprintf(f, "%s%-*s = %-30s [%s:%d]", prefix, maxlen, id, desc, pgm->config_file, pgm->lineno);
else
fprintf(f, "%s%-*s = %-s", prefix, maxlen, id, desc);
if(pm != ~0)
fprintf(f, " via %s", modes);
fprintf(f, "\n");
free(desc);
}
}
}
}
static void list_programmer_types_callback(const char *name, const char *desc,
void *cookie)
{
struct list_walk_cookie *c = (struct list_walk_cookie *)cookie;
fprintf(c->f, "%s%-16s = %-s\n", c->prefix, name, desc);
}
static void list_programmer_types(FILE * f, const char *prefix)
{
struct list_walk_cookie c;
c.f = f;
c.prefix = prefix;
walk_programmer_types(list_programmer_types_callback, &c);
}
static void list_parts(FILE *f, const char *prefix, LISTID avrparts, int pm) {
LNODEID ln1;
AVRPART *p;
2022-09-16 18:09:35 +00:00
int maxlen=0, len;
sort_avrparts(avrparts);
2022-09-16 18:09:35 +00:00
// Compute max length of part names
for(ln1 = lfirst(avrparts); ln1; ln1 = lnext(ln1)) {
p = ldata(ln1);
// List part if pm or prog_modes uninitialised or if they are compatible otherwise
if(!pm || !p->prog_modes || (pm & p->prog_modes)) {
if(verbose < 2 && p->id[0] == '.') // hide ids starting with '.'
2022-09-16 18:09:35 +00:00
continue;
if((len = strlen(p->id)) > maxlen)
maxlen = len;
}
}
2022-09-16 18:09:35 +00:00
for(ln1 = lfirst(avrparts); ln1; ln1 = lnext(ln1)) {
p = ldata(ln1);
// List part if pm or prog_modes uninitialised or if they are compatible otherwise
if(!pm || !p->prog_modes || (pm & p->prog_modes)) {
if(verbose < 2 && p->id[0] == '.') // hide ids starting with '.'
continue;
2022-09-16 18:09:35 +00:00
if(verbose)
fprintf(f, "%s%-*s = %-18s [%s:%d]", prefix, maxlen, p->id, p->desc, p->config_file, p->lineno);
else
2022-09-16 18:09:35 +00:00
fprintf(f, "%s%-*s = %s", prefix, maxlen, p->id, p->desc);
if(pm != ~0)
fprintf(f, " via %s", via_prog_modes(pm & p->prog_modes));
fprintf(f, "\n");
}
}
}
static void exithook(void)
{
if (pgm->teardown)
pgm->teardown(pgm);
}
static void cleanup_main(void)
{
if (updates) {
ldestroy_cb(updates, (void(*)(void*))free_update);
updates = NULL;
}
if (extended_params) {
ldestroy(extended_params);
extended_params = NULL;
}
if (additional_config_files) {
ldestroy(additional_config_files);
additional_config_files = NULL;
}
cleanup_config();
}
static void replace_backslashes(char *s)
{
// Replace all backslashes with forward slashes
Enable stdin verification and display correct number of bytes written/verified Counting the number of bytes written to a memory and/or verified is not trivial owing to potential holes in the input file and to potential trailing 0xff bytes in flash memory that are not written per default (but see -A). The new function memstats(), which is best called just after an input file has been read into mem->buf/mem->tags, computes the right number of bytes written and allows easy computation of the number of bytes verified. This commit also changes the strategy for the default verification after writing to a chip memory, so that the input file only needs reading once thus enabling successful verification of stdin input files. Other, minor changes: - Improving the grammar of AVRDUDE output, eg, 1 byte written instead of 1 bytes written - Better description of the input file structure in terms of its sections, the interval it spans, the number of pages, the number of padding bytes in pages, and the number of actually cut off trailing 0xff bytes for flash - Printing <stdin> or <stdout> instead of - in the -U routines - Option -V no longer needs to be specified before option -U in order to work As an aside this commit also provides useful helper functions for printing plural(), inname(), outname() and interval() all of which return strings fit for printing. $ avrdude -qp ATmega2560 -c usbtiny -U blink-mega2560+lext-test.hex avrdude: AVR device initialized and ready to accept instructions avrdude: Device signature = 0x1e9801 (probably m2560) 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: input file blink-mega2560+lext-test.hex auto detected as Intel Hex avrdude: reading input file blink-mega2560+lext-test.hex for flash with 1346 bytes in 4 sections within [0, 0x3106d] using 7 pages and 446 pad bytes avrdude: writing 1346 bytes flash ... avrdude: 1346 bytes of flash written avrdude: verifying flash memory against blink-mega2560+lext-test.hex avrdude: 1346 bytes of flash verified avrdude done. Thank you. $ avrdude -qp ATmega328P -c usb-bub-ii -U sketch-ending-in-ff.hex 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: input file sketch-ending-in-ff.hex auto detected as Intel Hex avrdude: reading input file sketch-ending-in-ff.hex for flash with 2160 bytes in 1 section within [0, 0x888] using 17 pages and 16 pad bytes, cutting off 25 trailing 0xff bytes avrdude: writing 2160 bytes flash ... avrdude: 2160 bytes of flash written avrdude: verifying flash memory against sketch-ending-in-ff.hex avrdude: 2185 bytes of flash verified avrdude done. Thank you. $ echo "Hello, world..." | avrdude -qp ATmega328P -c ... -U eeprom:w:-:r avrdude: AVR device initialized and ready to accept instructions avrdude: Device signature = 0x1e950f (probably m328p) avrdude: reading input file <stdin> for eeprom avrdude: writing 16 bytes eeprom ... avrdude: 16 bytes of eeprom written avrdude: verifying eeprom memory against <stdin> avrdude: 16 bytes of eeprom verified avrdude done. Thank you.
2022-08-02 22:26:01 +00:00
for (size_t i = 0; i < strlen(s); i++) {
if (s[i] == '\\') {
s[i] = '/';
}
}
}
// Return 2 if string is * or starts with */, 1 if string contains /, 0 otherwise
static int dev_opt(const char *str) {
return
!str? 0:
!strcmp(str, "*") || !strncmp(str, "*/", 2)? 2:
!!strchr(str, '/');
}
static void programmer_not_found(const char *programmer) {
msg_error("\n");
if(programmer && *programmer)
pmsg_error("cannot find programmer id %s\n", programmer);
else {
pmsg_error("no programmer has been specified on the command line or in the\n");
imsg_error("config file(s); specify one using the -c option and try again\n");
}
msg_error("\nValid programmers are:\n");
list_programmers(stderr, " ", programmers, ~0);
msg_error("\n");
}
static void part_not_found(const char *partdesc) {
msg_error("\n");
if(partdesc && *partdesc)
pmsg_error("AVR part %s not found\n", partdesc);
else
pmsg_error("no AVR part has been specified; use -p part\n");
msg_error("\nValid parts are:\n");
list_parts(stderr, " ", part_list, ~0);
msg_error("\n");
}
#if !defined(WIN32)
// Safely concatenate dir/file into dst that has size n
static char *concatpath(char *dst, char *dir, char *file, size_t n) {
// Dir or file empty?
if(!dir || !*dir || !file || !*file)
return NULL;
size_t len = strlen(dir);
// Insufficient space?
if(len + (dir[len-1] != '/') + strlen(file) > n-1)
return NULL;
if(dst != dir)
strcpy(dst, dir);
if(dst[len-1] != '/')
strcat(dst, "/");
strcat(dst, file);
return dst;
}
#endif
/*
* main routine
*/
int main(int argc, char * argv [])
{
int rc; /* general return code checking */
int exitrc; /* exit code for main() */
int i; /* general loop counter */
int ch; /* options flag */
int len; /* length for various strings */
struct avrpart * p; /* which avr part we are programming */
AVRMEM * sig; /* signature data */
struct stat sb;
UPDATE * upd;
LNODEID * ln;
/* options / operating mode variables */
int erase; /* 1=erase chip, 0=don't */
int calibrate; /* 1=calibrate RC oscillator, 0=don't */
char * port; /* device port (/dev/xxx) */
int terminal; /* 1=enter terminal mode, 0=don't */
Use const in PROGRAMMER function arguments where appropriate In order to get meaningful const properties for the PROGRAMMER, AVRPART and AVRMEM arguments, some code needed to be moved around, otherwise a network of "tainted" assignments risked rendering nothing const: - Change void (*enable)(PROGRAMMER *pgm) to void (*enable)(PROGRAMMER *pgm, const AVRPART *p); this allows changes in the PROGRAMMER structure after the part is known. For example, use TPI, UPDI, PDI functions in that programmer appropriate to the part. This used to be done later in the process, eg, in the initialize() function, which "taints" all other programmer functions wrt const and sometimes requires other finessing with flags etc. Much clearer with the modified enable() interface. - Move TPI initpgm-type code from initialize() to enable() --- note that initpgm() does not have the info at the time when it is called whether or not TPI is required - buspirate.c: move pgm->flag to PDATA(pgm)->flag (so legitimate modification of the flag does not change PROGRAMMER structure) - Move AVRPART_INIT_SMC and AVRPART_WRITE bits from the flags field in AVRPART to jtagmkII.c's private data flags32 fiels as FLAGS32_INIT_SMC and FLAGS32_WRITE bits - Move the xbeeResetPin component to private data in stk500.c as this is needed by xbee when it saddles on the stk500 code (previously, the flags component of the part was re-dedicated to this) - Change the way the "chained" private data are used in jtag3.c whilst keeping the PROGRAMMER structure read-only otherwise - In stk500v2.c move the STK600 pgm update from stk500v2_initialize() to stk500v2_enable() so the former keeps the PROGRAMMER structure read-only (for const assertion). - In usbasp change the code from changing PROGRAMMER functions late to dispatching to TPI or regular SPI protocol functions at runtime; reason being the decision whether to use TPI protocol is done at run-time depending on the capability of the attached programmer Also fixes Issue #1071, the treatment of default eecr value.
2022-08-17 15:05:28 +00:00
const char *exitspecs; /* exit specs string from command line */
const char *programmer; /* programmer id */
char sys_config[PATH_MAX]; /* system wide config file */
char usr_config[PATH_MAX]; /* per-user config file */
char executable_abspath[PATH_MAX]; /* absolute path to avrdude executable */
char executable_dirpath[PATH_MAX]; /* absolute path to folder with executable */
bool executable_abspath_found = false; /* absolute path to executable found */
bool sys_config_found = false; /* 'avrdude.conf' file found */
char * e; /* for strtol() error checking */
int baudrate; /* override default programmer baud rate */
Mega-commit to bring in both, the STK500v2 support from Erik Walthinsen, as well as JTAG ICE mkII support (by me). Erik's submission has been cleaned up a little bit, mostly to add his name and the current year to the copyright of the new file, remove trailing white space before importing the files, and fix the minor syntax errors in his avrdude.conf.in additions (missing semicolons). The JTAG ICE mkII support should be considered alpha to beta quality at this point. Few things are still to be done, like defering the hfuse (OCDEN) tweaks until they are really required. Also, for reasons not yet known, the target MCU doesn't start to run after signing off from the ICE, it needs a power-cycle first (at least on my STK500). Note that for the JTAG ICE, I did change a few things in the internal API. Notably I made the serial receive timeout configurable by the backends via an exported variable (done in both the Posix and the Win32 implementation), and I made the serial_recv() function return a -1 instead of bailing out with exit(1) upon encountering a receive timeout (currently only done in the Posix implementation). Both measures together allow me to receive a datastreem from the ICE at 115 kbps on a somewhat lossy PCI multi-UART card that occasionally drops a character. The JTAG ICE mkII protocol has enough of safety layers to allow recovering from these events, but the previous code wasn't prepared for any kind of recovery. The Win32 change for this still has to be done, and the traditional drivers need to be converted to exit(1) upon encountering a timeout (as they're now getting a -1 returned they didn't see before in that case). git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@451 81a1dc3b-b13d-400b-aceb-764788c761c2
2005-05-10 19:17:12 +00:00
double bitclock; /* Specify programmer bit clock (JTAG ICE) */
int ispdelay; /* Specify the delay for ISP clock */
int init_ok; /* Device initialization worked well */
int is_open; /* Device open succeeded */
int ce_delayed; /* Chip erase delayed */
char * logfile; /* Use logfile rather than stderr for diagnostics */
Enable stdin verification and display correct number of bytes written/verified Counting the number of bytes written to a memory and/or verified is not trivial owing to potential holes in the input file and to potential trailing 0xff bytes in flash memory that are not written per default (but see -A). The new function memstats(), which is best called just after an input file has been read into mem->buf/mem->tags, computes the right number of bytes written and allows easy computation of the number of bytes verified. This commit also changes the strategy for the default verification after writing to a chip memory, so that the input file only needs reading once thus enabling successful verification of stdin input files. Other, minor changes: - Improving the grammar of AVRDUDE output, eg, 1 byte written instead of 1 bytes written - Better description of the input file structure in terms of its sections, the interval it spans, the number of pages, the number of padding bytes in pages, and the number of actually cut off trailing 0xff bytes for flash - Printing <stdin> or <stdout> instead of - in the -U routines - Option -V no longer needs to be specified before option -U in order to work As an aside this commit also provides useful helper functions for printing plural(), inname(), outname() and interval() all of which return strings fit for printing. $ avrdude -qp ATmega2560 -c usbtiny -U blink-mega2560+lext-test.hex avrdude: AVR device initialized and ready to accept instructions avrdude: Device signature = 0x1e9801 (probably m2560) 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: input file blink-mega2560+lext-test.hex auto detected as Intel Hex avrdude: reading input file blink-mega2560+lext-test.hex for flash with 1346 bytes in 4 sections within [0, 0x3106d] using 7 pages and 446 pad bytes avrdude: writing 1346 bytes flash ... avrdude: 1346 bytes of flash written avrdude: verifying flash memory against blink-mega2560+lext-test.hex avrdude: 1346 bytes of flash verified avrdude done. Thank you. $ avrdude -qp ATmega328P -c usb-bub-ii -U sketch-ending-in-ff.hex 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: input file sketch-ending-in-ff.hex auto detected as Intel Hex avrdude: reading input file sketch-ending-in-ff.hex for flash with 2160 bytes in 1 section within [0, 0x888] using 17 pages and 16 pad bytes, cutting off 25 trailing 0xff bytes avrdude: writing 2160 bytes flash ... avrdude: 2160 bytes of flash written avrdude: verifying flash memory against sketch-ending-in-ff.hex avrdude: 2185 bytes of flash verified avrdude done. Thank you. $ echo "Hello, world..." | avrdude -qp ATmega328P -c ... -U eeprom:w:-:r avrdude: AVR device initialized and ready to accept instructions avrdude: Device signature = 0x1e950f (probably m328p) avrdude: reading input file <stdin> for eeprom avrdude: writing 16 bytes eeprom ... avrdude: 16 bytes of eeprom written avrdude: verifying eeprom memory against <stdin> avrdude: 16 bytes of eeprom verified avrdude done. Thank you.
2022-08-02 22:26:01 +00:00
enum updateflags uflags = UF_AUTO_ERASE | UF_VERIFY; /* Flags for do_op() */
(void) avr_ustimestamp();
#ifdef _MSC_VER
_set_printf_count_output(1);
#endif
/*
* Set line buffering for file descriptors so we see stdout and stderr
* properly interleaved.
*/
setvbuf(stdout, (char*)NULL, _IOLBF, 0);
setvbuf(stderr, (char*)NULL, _IOLBF, 0);
sys_config[0] = '\0';
progname = strrchr(argv[0], '/');
2022-01-07 12:15:55 +00:00
#if defined (WIN32)
/* take care of backslash as dir sep in W32 */
if (!progname)
progname = strrchr(argv[0], '\\');
2022-01-07 12:15:55 +00:00
#endif /* WIN32 */
if (progname)
progname++;
else
progname = argv[0];
// Remove trailing .exe
if(strlen(progname) > 4 && strcmp(progname+strlen(progname)-4, ".exe") == 0) {
progname = cfg_strdup("main()", progname); // Don't write to argv[0]
progname[strlen(progname)-4] = 0;
}
default_programmer = "";
default_parallel = "";
default_serial = "";
default_spi = "";
default_bitclock = 0.0;
init_config();
atexit(cleanup_main);
updates = lcreat(NULL, 0);
if (updates == NULL) {
pmsg_error("cannot initialize updater list\n");
exit(1);
}
extended_params = lcreat(NULL, 0);
if (extended_params == NULL) {
pmsg_error("cannot initialize extended parameter list\n");
exit(1);
}
additional_config_files = lcreat(NULL, 0);
if (additional_config_files == NULL) {
pmsg_error("cannot initialize additional config files list\n");
exit(1);
}
partdesc = NULL;
port = NULL;
erase = 0;
calibrate = 0;
p = NULL;
ovsigck = 0;
terminal = 0;
quell_progress = 0;
exitspecs = NULL;
pgm = NULL;
programmer = "";
verbose = 0;
baudrate = 0;
Mega-commit to bring in both, the STK500v2 support from Erik Walthinsen, as well as JTAG ICE mkII support (by me). Erik's submission has been cleaned up a little bit, mostly to add his name and the current year to the copyright of the new file, remove trailing white space before importing the files, and fix the minor syntax errors in his avrdude.conf.in additions (missing semicolons). The JTAG ICE mkII support should be considered alpha to beta quality at this point. Few things are still to be done, like defering the hfuse (OCDEN) tweaks until they are really required. Also, for reasons not yet known, the target MCU doesn't start to run after signing off from the ICE, it needs a power-cycle first (at least on my STK500). Note that for the JTAG ICE, I did change a few things in the internal API. Notably I made the serial receive timeout configurable by the backends via an exported variable (done in both the Posix and the Win32 implementation), and I made the serial_recv() function return a -1 instead of bailing out with exit(1) upon encountering a receive timeout (currently only done in the Posix implementation). Both measures together allow me to receive a datastreem from the ICE at 115 kbps on a somewhat lossy PCI multi-UART card that occasionally drops a character. The JTAG ICE mkII protocol has enough of safety layers to allow recovering from these events, but the previous code wasn't prepared for any kind of recovery. The Win32 change for this still has to be done, and the traditional drivers need to be converted to exit(1) upon encountering a timeout (as they're now getting a -1 returned they didn't see before in that case). git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@451 81a1dc3b-b13d-400b-aceb-764788c761c2
2005-05-10 19:17:12 +00:00
bitclock = 0.0;
ispdelay = 0;
is_open = 0;
ce_delayed = 0;
logfile = NULL;
len = strlen(progname) + 2;
for (i=0; i<len; i++)
progbuf[i] = ' ';
progbuf[i] = 0;
/*
* check for no arguments
*/
if (argc == 1) {
usage();
return 0;
}
/*
* process command line arguments
*/
while ((ch = getopt(argc,argv,"?Ab:B:c:C:DeE:Fi:l:np:OP:qstU:uvVx:yY:")) != -1) {
switch (ch) {
case 'b': /* override default programmer baud rate */
baudrate = strtol(optarg, &e, 0);
if ((e == optarg) || (*e != 0)) {
pmsg_error("invalid baud rate specified '%s'\n", optarg);
exit(1);
}
break;
Mega-commit to bring in both, the STK500v2 support from Erik Walthinsen, as well as JTAG ICE mkII support (by me). Erik's submission has been cleaned up a little bit, mostly to add his name and the current year to the copyright of the new file, remove trailing white space before importing the files, and fix the minor syntax errors in his avrdude.conf.in additions (missing semicolons). The JTAG ICE mkII support should be considered alpha to beta quality at this point. Few things are still to be done, like defering the hfuse (OCDEN) tweaks until they are really required. Also, for reasons not yet known, the target MCU doesn't start to run after signing off from the ICE, it needs a power-cycle first (at least on my STK500). Note that for the JTAG ICE, I did change a few things in the internal API. Notably I made the serial receive timeout configurable by the backends via an exported variable (done in both the Posix and the Win32 implementation), and I made the serial_recv() function return a -1 instead of bailing out with exit(1) upon encountering a receive timeout (currently only done in the Posix implementation). Both measures together allow me to receive a datastreem from the ICE at 115 kbps on a somewhat lossy PCI multi-UART card that occasionally drops a character. The JTAG ICE mkII protocol has enough of safety layers to allow recovering from these events, but the previous code wasn't prepared for any kind of recovery. The Win32 change for this still has to be done, and the traditional drivers need to be converted to exit(1) upon encountering a timeout (as they're now getting a -1 returned they didn't see before in that case). git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@451 81a1dc3b-b13d-400b-aceb-764788c761c2
2005-05-10 19:17:12 +00:00
case 'B': /* specify JTAG ICE bit clock period */
bitclock = strtod(optarg, &e);
if (*e != 0) {
/* trailing unit of measure present */
int suffixlen = strlen(e);
switch (suffixlen) {
case 2:
if ((e[0] != 'h' && e[0] != 'H') || e[1] != 'z')
bitclock = 0.0;
else
/* convert from Hz to microseconds */
bitclock = 1E6 / bitclock;
break;
case 3:
if ((e[1] != 'h' && e[1] != 'H') || e[2] != 'z')
bitclock = 0.0;
else {
switch (e[0]) {
case 'M':
case 'm': /* no Millihertz here :) */
bitclock = 1.0 / bitclock;
break;
case 'k':
bitclock = 1E3 / bitclock;
break;
default:
bitclock = 0.0;
break;
}
}
break;
default:
bitclock = 0.0;
break;
}
if (bitclock == 0.0)
pmsg_error("invalid bit clock unit of measure '%s'\n", e);
}
if ((e == optarg) || bitclock == 0.0) {
pmsg_error("invalid bit clock period specified '%s'\n", optarg);
Mega-commit to bring in both, the STK500v2 support from Erik Walthinsen, as well as JTAG ICE mkII support (by me). Erik's submission has been cleaned up a little bit, mostly to add his name and the current year to the copyright of the new file, remove trailing white space before importing the files, and fix the minor syntax errors in his avrdude.conf.in additions (missing semicolons). The JTAG ICE mkII support should be considered alpha to beta quality at this point. Few things are still to be done, like defering the hfuse (OCDEN) tweaks until they are really required. Also, for reasons not yet known, the target MCU doesn't start to run after signing off from the ICE, it needs a power-cycle first (at least on my STK500). Note that for the JTAG ICE, I did change a few things in the internal API. Notably I made the serial receive timeout configurable by the backends via an exported variable (done in both the Posix and the Win32 implementation), and I made the serial_recv() function return a -1 instead of bailing out with exit(1) upon encountering a receive timeout (currently only done in the Posix implementation). Both measures together allow me to receive a datastreem from the ICE at 115 kbps on a somewhat lossy PCI multi-UART card that occasionally drops a character. The JTAG ICE mkII protocol has enough of safety layers to allow recovering from these events, but the previous code wasn't prepared for any kind of recovery. The Win32 change for this still has to be done, and the traditional drivers need to be converted to exit(1) upon encountering a timeout (as they're now getting a -1 returned they didn't see before in that case). git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@451 81a1dc3b-b13d-400b-aceb-764788c761c2
2005-05-10 19:17:12 +00:00
exit(1);
}
break;
case 'i': /* specify isp clock delay */
ispdelay = strtol(optarg, &e,10);
if ((e == optarg) || (*e != 0) || ispdelay == 0) {
pmsg_error("invalid isp clock delay specified '%s'\n", optarg);
exit(1);
}
break;
case 'c': /* programmer id */
programmer = optarg;
break;
case 'C': /* system wide configuration file */
if (optarg[0] == '+') {
ladd(additional_config_files, optarg+1);
} else {
strncpy(sys_config, optarg, PATH_MAX);
sys_config[PATH_MAX-1] = 0;
}
break;
case 'D': /* disable auto erase */
uflags &= ~UF_AUTO_ERASE;
/* fall through */
case 'A': /* explicit disabling of trailing-0xff removal */
disable_trailing_ff_removal();
break;
case 'e': /* perform a chip erase */
erase = 1;
uflags &= ~UF_AUTO_ERASE;
break;
case 'E':
exitspecs = optarg;
break;
case 'F': /* override invalid signature check */
ovsigck = 1;
break;
case 'l':
logfile = optarg;
break;
case 'n':
uflags |= UF_NOWRITE;
break;
case 'O': /* perform RC oscillator calibration */
calibrate = 1;
break;
case 'p' : /* specify AVR part */
partdesc = optarg;
break;
case 'P':
port = optarg;
break;
case 'q' : /* Quell progress output */
quell_progress++ ;
break;
case 't': /* enter terminal mode */
terminal = 1;
break;
case 's':
case 'u':
pmsg_error("\"safemode\" feature no longer supported\n");
break;
case 'U':
upd = parse_op(optarg);
if (upd == NULL) {
pmsg_error("unable to parse update operation '%s'\n", optarg);
exit(1);
}
ladd(updates, upd);
break;
case 'v':
verbose++;
break;
case 'V':
Enable stdin verification and display correct number of bytes written/verified Counting the number of bytes written to a memory and/or verified is not trivial owing to potential holes in the input file and to potential trailing 0xff bytes in flash memory that are not written per default (but see -A). The new function memstats(), which is best called just after an input file has been read into mem->buf/mem->tags, computes the right number of bytes written and allows easy computation of the number of bytes verified. This commit also changes the strategy for the default verification after writing to a chip memory, so that the input file only needs reading once thus enabling successful verification of stdin input files. Other, minor changes: - Improving the grammar of AVRDUDE output, eg, 1 byte written instead of 1 bytes written - Better description of the input file structure in terms of its sections, the interval it spans, the number of pages, the number of padding bytes in pages, and the number of actually cut off trailing 0xff bytes for flash - Printing <stdin> or <stdout> instead of - in the -U routines - Option -V no longer needs to be specified before option -U in order to work As an aside this commit also provides useful helper functions for printing plural(), inname(), outname() and interval() all of which return strings fit for printing. $ avrdude -qp ATmega2560 -c usbtiny -U blink-mega2560+lext-test.hex avrdude: AVR device initialized and ready to accept instructions avrdude: Device signature = 0x1e9801 (probably m2560) 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: input file blink-mega2560+lext-test.hex auto detected as Intel Hex avrdude: reading input file blink-mega2560+lext-test.hex for flash with 1346 bytes in 4 sections within [0, 0x3106d] using 7 pages and 446 pad bytes avrdude: writing 1346 bytes flash ... avrdude: 1346 bytes of flash written avrdude: verifying flash memory against blink-mega2560+lext-test.hex avrdude: 1346 bytes of flash verified avrdude done. Thank you. $ avrdude -qp ATmega328P -c usb-bub-ii -U sketch-ending-in-ff.hex 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: input file sketch-ending-in-ff.hex auto detected as Intel Hex avrdude: reading input file sketch-ending-in-ff.hex for flash with 2160 bytes in 1 section within [0, 0x888] using 17 pages and 16 pad bytes, cutting off 25 trailing 0xff bytes avrdude: writing 2160 bytes flash ... avrdude: 2160 bytes of flash written avrdude: verifying flash memory against sketch-ending-in-ff.hex avrdude: 2185 bytes of flash verified avrdude done. Thank you. $ echo "Hello, world..." | avrdude -qp ATmega328P -c ... -U eeprom:w:-:r avrdude: AVR device initialized and ready to accept instructions avrdude: Device signature = 0x1e950f (probably m328p) avrdude: reading input file <stdin> for eeprom avrdude: writing 16 bytes eeprom ... avrdude: 16 bytes of eeprom written avrdude: verifying eeprom memory against <stdin> avrdude: 16 bytes of eeprom verified avrdude done. Thank you.
2022-08-02 22:26:01 +00:00
uflags &= ~UF_VERIFY;
break;
case 'x':
ladd(extended_params, optarg);
break;
case 'y':
pmsg_error("erase cycle counter no longer supported\n");
break;
case 'Y':
pmsg_error("erase cycle counter no longer supported\n");
break;
case '?': /* help */
usage();
exit(0);
break;
default:
pmsg_error("invalid option -%c\n\n", ch);
usage();
exit(1);
break;
}
}
if (logfile != NULL) {
FILE *newstderr = freopen(logfile, "w", stderr);
if (newstderr == NULL) {
/* Help! There's no stderr to complain to anymore now. */
printf("Cannot create logfile %s: %s\n", logfile, strerror(errno));
return 1;
}
}
/* search for system configuration file unless -C conffile was given */
if (strlen(sys_config) == 0) {
/*
* EXECUTABLE ABSPATH
* ------------------
* Determine the absolute path to avrdude executable. This will be used to
* locate the 'avrdude.conf' file later.
*/
int executable_dirpath_len;
int executable_abspath_len = wai_getExecutablePath(
executable_abspath,
PATH_MAX,
&executable_dirpath_len
);
if (
(executable_abspath_len != -1) &&
(executable_abspath_len != 0) &&
(executable_dirpath_len != -1) &&
(executable_dirpath_len != 0)
) {
// All requirements satisfied, executable path was found
executable_abspath_found = true;
// Make sure the string is null terminated
executable_abspath[executable_abspath_len] = '\0';
replace_backslashes(executable_abspath);
// Define 'executable_dirpath' to be the path to the parent folder of the
// executable.
strcpy(executable_dirpath, executable_abspath);
executable_dirpath[executable_dirpath_len] = '\0';
// Debug output
msg_trace2("executable_abspath = %s\n", executable_abspath);
msg_trace2("executable_abspath_len = %i\n", executable_abspath_len);
msg_trace2("executable_dirpath = %s\n", executable_dirpath);
msg_trace2("executable_dirpath_len = %i\n", executable_dirpath_len);
}
/*
* SYSTEM CONFIG
* -------------
* Determine the location of 'avrdude.conf'. Check in this order:
* 1. <dirpath of executable>/../etc/avrdude.conf
* 2. <dirpath of executable>/avrdude.conf
* 3. CONFIG_DIR/avrdude.conf
*
* When found, write the result into the 'sys_config' variable.
*/
if (executable_abspath_found) {
// 1. Check <dirpath of executable>/../etc/avrdude.conf
strcpy(sys_config, executable_dirpath);
sys_config[PATH_MAX - 1] = '\0';
i = strlen(sys_config);
if (i && (sys_config[i - 1] != '/'))
strcat(sys_config, "/");
strcat(sys_config, "../etc/" SYSTEM_CONF_FILE);
sys_config[PATH_MAX - 1] = '\0';
if (access(sys_config, F_OK) == 0) {
sys_config_found = true;
}
else {
// 2. Check <dirpath of executable>/avrdude.conf
strcpy(sys_config, executable_dirpath);
sys_config[PATH_MAX - 1] = '\0';
i = strlen(sys_config);
if (i && (sys_config[i - 1] != '/'))
strcat(sys_config, "/");
strcat(sys_config, SYSTEM_CONF_FILE);
sys_config[PATH_MAX - 1] = '\0';
if (access(sys_config, F_OK) == 0) {
sys_config_found = true;
}
}
}
if (!sys_config_found) {
// 3. Check CONFIG_DIR/avrdude.conf
2022-01-07 12:15:55 +00:00
#if defined(WIN32)
win_sys_config_set(sys_config);
#else
strcpy(sys_config, CONFIG_DIR);
i = strlen(sys_config);
if (i && (sys_config[i - 1] != '/'))
strcat(sys_config, "/");
strcat(sys_config, SYSTEM_CONF_FILE);
#endif
if (access(sys_config, F_OK) == 0) {
sys_config_found = true;
}
}
}
// Debug output
msg_trace2("sys_config = %s\n", sys_config);
msg_trace2("sys_config_found = %s\n", sys_config_found ? "true" : "false");
msg_trace2("\n");
/*
* USER CONFIG
* -----------
* Determine the location of '.avrduderc'.
*/
2022-01-07 12:15:55 +00:00
#if defined(WIN32)
win_usr_config_set(usr_config);
#else
usr_config[0] = 0;
if(!concatpath(usr_config, getenv("XDG_CONFIG_HOME"), XDG_USER_CONF_FILE, sizeof usr_config))
concatpath(usr_config, getenv("HOME"), ".config/" XDG_USER_CONF_FILE, sizeof usr_config);
if(stat(usr_config, &sb) < 0 || (sb.st_mode & S_IFREG) == 0)
concatpath(usr_config, getenv("HOME"), USER_CONF_FILE, sizeof usr_config);
#endif
if (quell_progress == 0)
terminal_setup_update_progress();
/*
* Print out an identifying string so folks can tell what version
* they are running
*/
msg_notice("\n");
pmsg_notice("Version %s\n", version);
imsg_notice("Copyright the AVRDUDE authors;\n");
imsg_notice("see https://github.com/avrdudes/avrdude/blob/main/AUTHORS\n\n");
if(*sys_config) {
char *real_sys_config = realpath(sys_config, NULL);
if(real_sys_config) {
imsg_notice("System wide configuration file is %s\n", real_sys_config);
} else
pmsg_warning("cannot determine realpath() of config file %s: %s\n", sys_config, strerror(errno));
rc = read_config(real_sys_config);
if (rc) {
pmsg_error("unable to process system wide configuration file %s\n", real_sys_config);
exit(1);
}
free(real_sys_config);
}
if (usr_config[0] != 0) {
imsg_notice("User configuration file is %s\n", usr_config);
rc = stat(usr_config, &sb);
if ((rc < 0) || ((sb.st_mode & S_IFREG) == 0))
imsg_notice("User configuration file does not exist or is not a regular file, skipping\n");
else {
rc = read_config(usr_config);
if (rc) {
pmsg_error("unable to process user configuration file %s\n", usr_config);
exit(1);
}
}
}
if (lsize(additional_config_files) > 0) {
LNODEID ln1;
const char * p = NULL;
for (ln1=lfirst(additional_config_files); ln1; ln1=lnext(ln1)) {
p = ldata(ln1);
imsg_notice("additional configuration file is %s\n", p);
rc = read_config(p);
if (rc) {
pmsg_error("unable to process additional configuration file %s\n", p);
exit(1);
}
}
}
// set bitclock from configuration files unless changed by command line
if (default_bitclock > 0 && bitclock == 0.0) {
bitclock = default_bitclock;
}
if(!(programmer && *programmer) && *default_programmer)
programmer = cache_string(default_programmer);
// Developer options to print parts and/or programmer entries of avrdude.conf
int dev_opt_c = dev_opt(programmer); // -c <wildcard>/[sSArt]
int dev_opt_p = dev_opt(partdesc); // -p <wildcard>/[dsSArcow*t]
if(dev_opt_c || dev_opt_p) { // See -c/h and or -p/h
dev_output_pgm_part(dev_opt_c, programmer, dev_opt_p, partdesc);
exit(0);
}
for(LNODEID ln1 = lfirst(part_list); ln1; ln1 = lnext(ln1)) {
AVRPART *p = ldata(ln1);
for(LNODEID ln2 = lfirst(programmers); ln2; ln2 = lnext(ln2)) {
PROGRAMMER *pgm = ldata(ln2);
int pm = pgm->prog_modes & p->prog_modes;
if(pm & (pm-1))
pmsg_warning("%s and %s share multiple modes (%s)\n",
pgm->id? (char *) ldata(lfirst(pgm->id)): "???", p->desc, via_prog_modes(pm));
}
}
if (partdesc) {
if (strcmp(partdesc, "?") == 0) {
if(programmer && *programmer) {
PROGRAMMER *pgm = locate_programmer(programmers, programmer);
if(!pgm) {
programmer_not_found(programmer);
exit(1);
}
msg_error("\nValid parts for programmer %s are:\n", programmer);
list_parts(stderr, " ", part_list, pgm->prog_modes);
} else {
msg_error("\nValid parts are:\n");
list_parts(stderr, " ", part_list, ~0);
}
msg_error("\n");
exit(1);
}
}
if (programmer) {
if (strcmp(programmer, "?") == 0) {
if(partdesc && *partdesc) {
AVRPART *p = locate_part(part_list, partdesc);
if(!p) {
part_not_found(partdesc);
exit(1);
}
msg_error("\nValid programmers for part %s are:\n", p->desc);
list_programmers(stderr, " ", programmers, p->prog_modes);
} else {
msg_error("\nValid programmers are:\n");
list_programmers(stderr, " ", programmers, ~0);
}
msg_error("\n");
exit(1);
}
if (strcmp(programmer, "?type") == 0) {
msg_error("\nValid programmer types are:\n");
list_programmer_types(stderr, " ");
msg_error("\n");
exit(1);
}
}
msg_notice("\n");
if (!programmer || !*programmer) {
programmer_not_found(NULL);
exit(1);
}
pgm = locate_programmer(programmers, programmer);
if (pgm == NULL) {
programmer_not_found(programmer);
exit(1);
}
if (pgm->initpgm) {
pgm->initpgm(pgm);
} else {
msg_error("\n");
pmsg_error("cannot initialize the programmer\n\n");
exit(1);
}
if (pgm->setup) {
pgm->setup(pgm);
}
if (pgm->teardown) {
atexit(exithook);
}
if (lsize(extended_params) > 0) {
if (pgm->parseextparams == NULL) {
pmsg_error("programmer does not support extended parameters, -x option(s) ignored\n");
} else {
if (pgm->parseextparams(pgm, extended_params) < 0) {
pmsg_error("unable to parse extended parameter list\n");
exit(1);
}
}
}
if (port == NULL) {
switch (pgm->conntype)
{
case CONNTYPE_PARALLEL:
port = cfg_strdup("main()", default_parallel);
break;
case CONNTYPE_SERIAL:
port = cfg_strdup("main()", default_serial);
break;
case CONNTYPE_USB:
port = DEFAULT_USB;
break;
case CONNTYPE_SPI:
#ifdef HAVE_LINUXSPI
Use const in PROGRAMMER function arguments where appropriate In order to get meaningful const properties for the PROGRAMMER, AVRPART and AVRMEM arguments, some code needed to be moved around, otherwise a network of "tainted" assignments risked rendering nothing const: - Change void (*enable)(PROGRAMMER *pgm) to void (*enable)(PROGRAMMER *pgm, const AVRPART *p); this allows changes in the PROGRAMMER structure after the part is known. For example, use TPI, UPDI, PDI functions in that programmer appropriate to the part. This used to be done later in the process, eg, in the initialize() function, which "taints" all other programmer functions wrt const and sometimes requires other finessing with flags etc. Much clearer with the modified enable() interface. - Move TPI initpgm-type code from initialize() to enable() --- note that initpgm() does not have the info at the time when it is called whether or not TPI is required - buspirate.c: move pgm->flag to PDATA(pgm)->flag (so legitimate modification of the flag does not change PROGRAMMER structure) - Move AVRPART_INIT_SMC and AVRPART_WRITE bits from the flags field in AVRPART to jtagmkII.c's private data flags32 fiels as FLAGS32_INIT_SMC and FLAGS32_WRITE bits - Move the xbeeResetPin component to private data in stk500.c as this is needed by xbee when it saddles on the stk500 code (previously, the flags component of the part was re-dedicated to this) - Change the way the "chained" private data are used in jtag3.c whilst keeping the PROGRAMMER structure read-only otherwise - In stk500v2.c move the STK600 pgm update from stk500v2_initialize() to stk500v2_enable() so the former keeps the PROGRAMMER structure read-only (for const assertion). - In usbasp change the code from changing PROGRAMMER functions late to dispatching to TPI or regular SPI protocol functions at runtime; reason being the decision whether to use TPI protocol is done at run-time depending on the capability of the attached programmer Also fixes Issue #1071, the treatment of default eecr value.
2022-08-17 15:05:28 +00:00
port = cfg_strdup("main()", *default_spi? default_spi: "unknown");
#endif
break;
}
}
/*
* open the programmer
*/
if (port[0] == 0) {
msg_error("\n");
pmsg_error("no port has been specified on the command line or in the config file\n");
imsg_error("specify a port using the -P option and try again\n\n");
exit(1);
}
if (verbose) {
imsg_notice("Using Port : %s\n", port);
imsg_notice("Using Programmer : %s\n", programmer);
}
if (baudrate != 0) {
imsg_notice("Overriding Baud Rate : %d\n", baudrate);
pgm->baudrate = baudrate;
}
Mega-commit to bring in both, the STK500v2 support from Erik Walthinsen, as well as JTAG ICE mkII support (by me). Erik's submission has been cleaned up a little bit, mostly to add his name and the current year to the copyright of the new file, remove trailing white space before importing the files, and fix the minor syntax errors in his avrdude.conf.in additions (missing semicolons). The JTAG ICE mkII support should be considered alpha to beta quality at this point. Few things are still to be done, like defering the hfuse (OCDEN) tweaks until they are really required. Also, for reasons not yet known, the target MCU doesn't start to run after signing off from the ICE, it needs a power-cycle first (at least on my STK500). Note that for the JTAG ICE, I did change a few things in the internal API. Notably I made the serial receive timeout configurable by the backends via an exported variable (done in both the Posix and the Win32 implementation), and I made the serial_recv() function return a -1 instead of bailing out with exit(1) upon encountering a receive timeout (currently only done in the Posix implementation). Both measures together allow me to receive a datastreem from the ICE at 115 kbps on a somewhat lossy PCI multi-UART card that occasionally drops a character. The JTAG ICE mkII protocol has enough of safety layers to allow recovering from these events, but the previous code wasn't prepared for any kind of recovery. The Win32 change for this still has to be done, and the traditional drivers need to be converted to exit(1) upon encountering a timeout (as they're now getting a -1 returned they didn't see before in that case). git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@451 81a1dc3b-b13d-400b-aceb-764788c761c2
2005-05-10 19:17:12 +00:00
if (bitclock != 0.0) {
imsg_notice("Setting bit clk period : %.1f\n", bitclock);
pgm->bitclock = bitclock * 1e-6;
Mega-commit to bring in both, the STK500v2 support from Erik Walthinsen, as well as JTAG ICE mkII support (by me). Erik's submission has been cleaned up a little bit, mostly to add his name and the current year to the copyright of the new file, remove trailing white space before importing the files, and fix the minor syntax errors in his avrdude.conf.in additions (missing semicolons). The JTAG ICE mkII support should be considered alpha to beta quality at this point. Few things are still to be done, like defering the hfuse (OCDEN) tweaks until they are really required. Also, for reasons not yet known, the target MCU doesn't start to run after signing off from the ICE, it needs a power-cycle first (at least on my STK500). Note that for the JTAG ICE, I did change a few things in the internal API. Notably I made the serial receive timeout configurable by the backends via an exported variable (done in both the Posix and the Win32 implementation), and I made the serial_recv() function return a -1 instead of bailing out with exit(1) upon encountering a receive timeout (currently only done in the Posix implementation). Both measures together allow me to receive a datastreem from the ICE at 115 kbps on a somewhat lossy PCI multi-UART card that occasionally drops a character. The JTAG ICE mkII protocol has enough of safety layers to allow recovering from these events, but the previous code wasn't prepared for any kind of recovery. The Win32 change for this still has to be done, and the traditional drivers need to be converted to exit(1) upon encountering a timeout (as they're now getting a -1 returned they didn't see before in that case). git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@451 81a1dc3b-b13d-400b-aceb-764788c761c2
2005-05-10 19:17:12 +00:00
}
if (ispdelay != 0) {
imsg_notice("Setting isp clock delay : %3i\n", ispdelay);
pgm->ispdelay = ispdelay;
}
rc = pgm->open(pgm, port);
if (rc < 0) {
pmsg_error("unable to open programmer %s on port %s\n", programmer, port);
exitrc = 1;
pgm->ppidata = 0; /* clear all bits at exit */
goto main_exit;
}
is_open = 1;
if (partdesc == NULL) {
part_not_found(NULL);
exitrc = 1;
goto main_exit;
}
p = locate_part(part_list, partdesc);
if (p == NULL) {
part_not_found(partdesc);
exitrc = 1;
goto main_exit;
}
if (exitspecs != NULL) {
if (pgm->parseexitspecs == NULL) {
pmsg_warning("-E option not supported by this programmer type\n");
exitspecs = NULL;
}
else if (pgm->parseexitspecs(pgm, exitspecs) < 0) {
usage();
exitrc = 1;
goto main_exit;
}
}
Use const in PROGRAMMER function arguments where appropriate In order to get meaningful const properties for the PROGRAMMER, AVRPART and AVRMEM arguments, some code needed to be moved around, otherwise a network of "tainted" assignments risked rendering nothing const: - Change void (*enable)(PROGRAMMER *pgm) to void (*enable)(PROGRAMMER *pgm, const AVRPART *p); this allows changes in the PROGRAMMER structure after the part is known. For example, use TPI, UPDI, PDI functions in that programmer appropriate to the part. This used to be done later in the process, eg, in the initialize() function, which "taints" all other programmer functions wrt const and sometimes requires other finessing with flags etc. Much clearer with the modified enable() interface. - Move TPI initpgm-type code from initialize() to enable() --- note that initpgm() does not have the info at the time when it is called whether or not TPI is required - buspirate.c: move pgm->flag to PDATA(pgm)->flag (so legitimate modification of the flag does not change PROGRAMMER structure) - Move AVRPART_INIT_SMC and AVRPART_WRITE bits from the flags field in AVRPART to jtagmkII.c's private data flags32 fiels as FLAGS32_INIT_SMC and FLAGS32_WRITE bits - Move the xbeeResetPin component to private data in stk500.c as this is needed by xbee when it saddles on the stk500 code (previously, the flags component of the part was re-dedicated to this) - Change the way the "chained" private data are used in jtag3.c whilst keeping the PROGRAMMER structure read-only otherwise - In stk500v2.c move the STK600 pgm update from stk500v2_initialize() to stk500v2_enable() so the former keeps the PROGRAMMER structure read-only (for const assertion). - In usbasp change the code from changing PROGRAMMER functions late to dispatching to TPI or regular SPI protocol functions at runtime; reason being the decision whether to use TPI protocol is done at run-time depending on the capability of the attached programmer Also fixes Issue #1071, the treatment of default eecr value.
2022-08-17 15:05:28 +00:00
if (avr_initmem(p) != 0) {
msg_error("\n");
pmsg_error("unable to initialize memories\n");
exitrc = 1;
goto main_exit;
}
if(verbose) {
if ((strcmp(pgm->type, "avr910") == 0)) {
imsg_notice("avr910_devcode (avrdude.conf) : ");
if(p->avr910_devcode)
msg_notice("0x%02x\n", (uint8_t) p->avr910_devcode);
else
msg_notice("none\n");
}
}
/*
* Now that we know which part we are going to program, locate any -U
* options using the default memory region, fill in the device-dependent
* default region name ("application" for Xmega parts or "flash" otherwise)
* and check for basic problems with memory names or file access with a
* view to exit before programming.
*/
int doexit = 0;
for (ln=lfirst(updates); ln; ln=lnext(ln)) {
upd = ldata(ln);
if (upd->memtype == 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',
upd->filename, mtype);
upd->memtype = cfg_strdup("main()", mtype);
}
rc = update_dryrun(p, upd);
if (rc && rc != LIBAVRDUDE_SOFTFAIL)
doexit = 1;
}
if(doexit) {
exitrc = 1;
goto main_exit;
}
if (calibrate) {
/*
* perform an RC oscillator calibration
* as outlined in appnote AVR053
*/
if (pgm->perform_osccal == 0) {
pmsg_error("programmer does not support RC oscillator calibration\n");
exitrc = 1;
} else {
pmsg_info("performing RC oscillator calibration\n");
exitrc = pgm->perform_osccal(pgm);
}
if (exitrc == 0)
pmsg_info("calibration value is now stored in EEPROM at address 0\n");
goto main_exit;
}
if (verbose && quell_progress < 2) {
avr_display(stderr, p, progbuf, verbose);
msg_notice("\n");
programmer_display(pgm, progbuf);
}
msg_info("\n");
exitrc = 0;
/*
* enable the programmer
*/
Use const in PROGRAMMER function arguments where appropriate In order to get meaningful const properties for the PROGRAMMER, AVRPART and AVRMEM arguments, some code needed to be moved around, otherwise a network of "tainted" assignments risked rendering nothing const: - Change void (*enable)(PROGRAMMER *pgm) to void (*enable)(PROGRAMMER *pgm, const AVRPART *p); this allows changes in the PROGRAMMER structure after the part is known. For example, use TPI, UPDI, PDI functions in that programmer appropriate to the part. This used to be done later in the process, eg, in the initialize() function, which "taints" all other programmer functions wrt const and sometimes requires other finessing with flags etc. Much clearer with the modified enable() interface. - Move TPI initpgm-type code from initialize() to enable() --- note that initpgm() does not have the info at the time when it is called whether or not TPI is required - buspirate.c: move pgm->flag to PDATA(pgm)->flag (so legitimate modification of the flag does not change PROGRAMMER structure) - Move AVRPART_INIT_SMC and AVRPART_WRITE bits from the flags field in AVRPART to jtagmkII.c's private data flags32 fiels as FLAGS32_INIT_SMC and FLAGS32_WRITE bits - Move the xbeeResetPin component to private data in stk500.c as this is needed by xbee when it saddles on the stk500 code (previously, the flags component of the part was re-dedicated to this) - Change the way the "chained" private data are used in jtag3.c whilst keeping the PROGRAMMER structure read-only otherwise - In stk500v2.c move the STK600 pgm update from stk500v2_initialize() to stk500v2_enable() so the former keeps the PROGRAMMER structure read-only (for const assertion). - In usbasp change the code from changing PROGRAMMER functions late to dispatching to TPI or regular SPI protocol functions at runtime; reason being the decision whether to use TPI protocol is done at run-time depending on the capability of the attached programmer Also fixes Issue #1071, the treatment of default eecr value.
2022-08-17 15:05:28 +00:00
pgm->enable(pgm, p);
/*
* turn off all the status leds
*/
pgm->rdy_led(pgm, OFF);
pgm->err_led(pgm, OFF);
pgm->pgm_led(pgm, OFF);
pgm->vfy_led(pgm, OFF);
/*
2022-01-07 10:31:16 +00:00
* initialize the chip in preparation for accepting commands
*/
init_ok = (rc = pgm->initialize(pgm, p)) >= 0;
if (!init_ok) {
pmsg_error("initialization failed, rc=%d\n", rc);
if(rc == -2)
imsg_error("the programmer ISP clock is too fast for the target\n");
else
imsg_error("- double check the connections and try again\n");
imsg_error("- use -B to set lower ISP clock frequency, e.g. -B 125kHz\n");
if (!ovsigck) {
imsg_error("- use -F to override this check\n\n");
exitrc = 1;
goto main_exit;
}
}
/* indicate ready */
pgm->rdy_led(pgm, ON);
pmsg_info("AVR device initialized and ready to accept instructions\n");
/*
* Let's read the signature bytes to make sure there is at least a
* chip on the other end that is responding correctly. A check
* against 0xffffff / 0x000000 should ensure that the signature bytes
* are valid.
*/
if(!(p->prog_modes & PM_aWire)) { // not AVR32
int attempt = 0;
int waittime = 10000; /* 10 ms */
sig_again:
usleep(waittime);
if (init_ok) {
rc = avr_signature(pgm, p);
if (rc != LIBAVRDUDE_SUCCESS) {
if (rc == LIBAVRDUDE_SOFTFAIL && (p->prog_modes & PM_UPDI) && attempt < 1) {
attempt++;
if (pgm->read_sib) {
// Read SIB and compare FamilyID
char sib[AVR_SIBLEN + 1];
pgm->read_sib(pgm, p, sib);
pmsg_notice("System Information Block: %s\n", sib);
pmsg_info("received FamilyID: \"%.*s\"\n", AVR_FAMILYIDLEN, sib);
if (strncmp(p->family_id, sib, AVR_FAMILYIDLEN))
pmsg_error("expected FamilyID: \"%s\"\n", p->family_id);
}
if(erase) {
erase = 0;
if (uflags & UF_NOWRITE) {
pmsg_warning("conflicting -e and -n options specified, NOT erasing chip\n");
} else {
pmsg_info("erasing chip\n");
exitrc = avr_unlock(pgm, p);
if(exitrc)
goto main_exit;
goto sig_again;
}
}
if (!ovsigck) {
imsg_error("double check chip or use -F to override this check\n");
exitrc = 1;
goto main_exit;
}
}
pmsg_error("unable to read signature data, rc=%d\n", rc);
exitrc = 1;
goto main_exit;
}
}
sig = avr_locate_mem(p, "signature");
if (sig == NULL)
pmsg_warning("signature memory not defined for device %s\n", p->desc);
if (sig != NULL) {
int ff, zz;
pmsg_info("device signature = 0x");
ff = zz = 1;
for (i=0; i<sig->size; i++) {
msg_info("%02x", sig->buf[i]);
if (sig->buf[i] != 0xff)
ff = 0;
if (sig->buf[i] != 0x00)
zz = 0;
}
bool signature_matches =
sig->size == 3 &&
sig->buf[0] == p->signature[0] &&
sig->buf[1] == p->signature[1] &&
sig->buf[2] == p->signature[2];
if (quell_progress < 2) {
AVRPART * part;
if((part = locate_part_by_signature(part_list, sig->buf, sig->size)))
msg_info(" (probably %s)", signature_matches ? p->id : part->id);
}
if (ff || zz) {
if (++attempt < 3) {
waittime *= 5;
msg_info(" (retrying)\n");
goto sig_again;
}
msg_info("\n");
pmsg_error("Yikes! Invalid device signature.\n");
if (!ovsigck) {
pmsg_error("expected signature for %s is %02X %02X %02X\n", p->desc,
p->signature[0], p->signature[1], p->signature[2]);
imsg_error("Double check connections and try again, or use -F to override\n");
imsg_error("this check.\n\n");
exitrc = 1;
goto main_exit;
}
} else {
msg_info("\n");
}
if (!signature_matches) {
if (ovsigck) {
pmsg_warning("expected signature for %s is %02X %02X %02X\n", p->desc,
p->signature[0], p->signature[1], p->signature[2]);
} else {
pmsg_error("expected signature for %s is %02X %02X %02X\n", p->desc,
p->signature[0], p->signature[1], p->signature[2]);
imsg_error("double check chip or use -F to override this check\n");
exitrc = 1;
goto main_exit;
}
}
}
}
if (uflags & UF_AUTO_ERASE) {
if ((p->prog_modes & PM_PDI) && pgm->page_erase && lsize(updates) > 0) {
pmsg_info("Note: programmer supports page erase for Xmega devices.\n");
imsg_info("Each page will be erased before programming it, but no chip erase is performed.\n");
imsg_info("To disable page erases, specify the -D option; for a chip-erase, use the -e option.\n");
} else {
AVRMEM * m;
const char *memname = p->prog_modes & PM_PDI? "application": "flash";
uflags &= ~UF_AUTO_ERASE;
for (ln=lfirst(updates); ln; ln=lnext(ln)) {
upd = ldata(ln);
m = avr_locate_mem(p, upd->memtype);
if (m == NULL)
continue;
if ((strcmp(m->desc, memname) == 0) && (upd->op == DEVICE_WRITE)) {
erase = 1;
pmsg_info("Note: %s memory has been specified, an erase cycle will be performed.\n", memname);
imsg_info("To disable this feature, specify the -D option.\n");
break;
}
}
}
}
if (init_ok && erase) {
/*
* erase the chip's flash and eeprom memories, this is required
* before the chip can accept new programming
*/
if (uflags & UF_NOWRITE) {
pmsg_warning("conflicting -e and -n options specified, NOT erasing chip\n");
} else {
2022-11-10 23:18:43 +00:00
pmsg_info("erasing chip\n");
exitrc = avr_chip_erase(pgm, p);
if(exitrc == LIBAVRDUDE_SOFTFAIL) {
imsg_info("delaying chip erase until first -U upload to flash\n");
ce_delayed = 1;
exitrc = 0;
} else if(exitrc)
goto main_exit;
}
}
if (terminal) {
/*
* terminal mode
*/
exitrc = terminal_mode(pgm, p);
}
if (!init_ok) {
/*
* If we came here by the -tF options, bail out now.
*/
exitrc = 1;
goto main_exit;
}
for (ln=lfirst(updates); ln; ln=lnext(ln)) {
upd = ldata(ln);
rc = do_op(pgm, p, upd, uflags);
if (rc && rc != LIBAVRDUDE_SOFTFAIL) {
exitrc = 1;
break;
} else if(rc == 0 && upd->op == DEVICE_WRITE && avr_memtype_is_flash_type(upd->memtype))
ce_delayed = 0; // Redeemed chip erase promise
}
main_exit:
/*
* program complete
*/
if (is_open) {
pgm->powerdown(pgm);
pgm->disable(pgm);
pgm->rdy_led(pgm, OFF);
pgm->close(pgm);
}
msg_info("\n%s done. Thank you.\n\n", progname);
return ce_delayed? 1: exitrc;
}