/* * avrdude - A Downloader/Uploader for AVR device programmers * Copyright (C) 2000-2005 Brian S. Dean * Copyright Joerg Wunsch * * 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 . */ /* $Id$ */ /* * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #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 Specify AVR device\n" " -b Override RS-232 baud rate\n" " -B Specify bit clock period (us)\n" " -C Specify location of configuration file\n" " -c Specify programmer type\n" " -A Disable trailing-0xff removal from file and AVR read\n" " -D Disable auto erase for flash memory; implies -A\n" " -i ISP Clock Delay [in microseconds]\n" " -P 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" " -U :r|w|v:[: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 [,] List programmer exit specifications\n" " -x Pass 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" "\navrdude version %s, URL: \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 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; int maxlen=0, len; sort_programmers(programmers); // Compute max length of programmer names for(ln1 = lfirst(programmers); ln1; ln1 = lnext(ln1)) { pgm = ldata(ln1); 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; } } 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; int maxlen=0, len; sort_avrparts(avrparts); // 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 '.' continue; if((len = strlen(p->id)) > maxlen) maxlen = len; } } 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; if(verbose) fprintf(f, "%s%-*s = %-18s [%s:%d]", prefix, maxlen, p->id, p->desc, p->config_file, p->lineno); else 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 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 */ 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 */ 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 */ enum updateflags uflags = UF_AUTO_ERASE | UF_VERIFY; /* Flags for do_op() */ #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], '/'); #if defined (WIN32) /* take care of backslash as dir sep in W32 */ if (!progname) progname = strrchr(argv[0], '\\'); #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; bitclock = 0.0; ispdelay = 0; is_open = 0; ce_delayed = 0; logfile = NULL; len = strlen(progname) + 2; for (i=0; i/../etc/avrdude.conf * 2. /avrdude.conf * 3. CONFIG_DIR/avrdude.conf * * When found, write the result into the 'sys_config' variable. */ if (executable_abspath_found) { // 1. Check /../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 /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 #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_debug("sys_config = %s\n", sys_config); msg_debug("sys_config_found = %s\n", sys_config_found ? "true" : "false"); msg_debug("\n"); /* * USER CONFIG * ----------- * Determine the location of '.avrduderc'. */ #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 /[sSArt] int dev_opt_p = dev_opt(partdesc); // -p /[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 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; } if (bitclock != 0.0) { imsg_notice("Setting bit clk period : %.1f\n", bitclock); pgm->bitclock = bitclock * 1e-6; } 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; } } 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 */ 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); /* * 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); imsg_error("- double check the connections and try again\n"); imsg_error("- use -B to set lower ISP clock frequency, e.g. -B 200kHz\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; isize; 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) { 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 { 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; }