diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 916b7f1a..2ac4313c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -49,6 +49,7 @@ jobs: libusb-1.0-0-dev libhidapi-dev libftdi1-dev + libreadline-dev texinfo texlive texi2html @@ -110,6 +111,7 @@ jobs: libusb-1.0-0-dev:${{matrix.arch}} libhidapi-dev:${{matrix.arch}} libftdi1-dev:${{matrix.arch}} + libreadline-dev:${{matrix.arch}} - name: Configure run: >- cmake diff --git a/NEWS b/NEWS index 85a65c84..899e9373 100644 --- a/NEWS +++ b/NEWS @@ -58,6 +58,12 @@ Changes since version 7.0: - Make UPDI programmers less verbose during initialization #1084 - Quell mode isn't handled systematically #1114 + - Mixing the progress bar with warning messages #1136 + - Inconsistent terminal output re stdout and stderr #1130 + - Supress the warning for Microchip SNAP #1135 + - ATtiny85 communication problem with default bitclock #1133 + - [Regression] Optiboot for "modern AVRs" no longer works #1120 + - Cannot access EEPROM on some bootloader/part combos #970 * Pull requests: @@ -153,6 +159,16 @@ Changes since version 7.0: - Suppress Teensy USB communication error message on reboot #1122 - Fix UPDI erase when target is locked #1125 - Review and overhaul AVRDUDE's messaging system #1126 + - Look for ~/.config/avrdude/avrdude.rc then ~/.avrduderc #1131 + - Revamp terminal output (progress bar, callback and + stdout/stderr) #1132 + - Detect PICkit4 and SNAP in PIC mode #1138 + - Mention -B in the error message #1139 + - Support optiboot, optiboot_dx and optiboot_x bootloaders for + -c arduino #1140 + - Always use paged access for programmers that serve + bootloaders #1141 + - Add libreadline-dev for Linux github action build #1146 * Internals: diff --git a/build.sh b/build.sh index bbb2f586..879c0a73 100755 --- a/build.sh +++ b/build.sh @@ -53,9 +53,9 @@ case "${ostype}" in # Apple M1 (may be new version of homebrew also) if [ -d /opt/homebrew ] then - build_flags="${build_flags} -D CMAKE_C_FLAGS=-I/opt/homebrew/include -D CMAKE_EXE_LINKER_FLAGS=-L/opt/homebrew/Cellar" + build_flags="${build_flags} -D CMAKE_C_FLAGS=-I/opt/homebrew/include -D CMAKE_EXE_LINKER_FLAGS=-L/opt/homebrew/Cellar -D HAVE_LIBREADLINE:FILEPATH=/opt/homebrew/lib/libreadline.dylib" else - build_flags="${build_flags} -D CMAKE_C_FLAGS=-I/usr/local/include -D CMAKE_EXE_LINKER_FLAGS=-L/usr/local/Cellar" + build_flags="${build_flags} -D CMAKE_C_FLAGS=-I/usr/local/include -D CMAKE_EXE_LINKER_FLAGS=-L/usr/local/Cellar -D HAVE_LIBREADLINE:FILEPATH=/usr/local/lib/libreadline.dylib" fi fi ;; diff --git a/src/avr.c b/src/avr.c index 553e3ec4..9352a2b6 100644 --- a/src/avr.c +++ b/src/avr.c @@ -377,8 +377,9 @@ int avr_read_mem(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, con return avr_mem_hiaddr(mem); } - if (pgm->paged_load != NULL && mem->page_size > 1 && - mem->size % mem->page_size == 0) { + // HW programmers need a page size > 1, bootloader typ only offer paged r/w + if ((pgm->paged_load && mem->page_size > 1 && mem->size % mem->page_size == 0) || + ((pgm->prog_modes & PM_SPM) && avr_has_paged_access(pgm, mem))) { /* * the programmer supports a paged mode read */ @@ -894,7 +895,9 @@ int avr_write_mem(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m, int return i; } - if (pgm->paged_write != NULL && m->page_size > 1) { + // HW programmers need a page size > 1, bootloader typ only offer paged r/w + if ((pgm->paged_load && m->page_size > 1 && m->size % m->page_size == 0) || + ((pgm->prog_modes & PM_SPM) && avr_has_paged_access(pgm, m))) { /* * the programmer supports a paged mode write */ @@ -1036,13 +1039,14 @@ int avr_write_mem(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m, int int avr_signature(const PROGRAMMER *pgm, const AVRPART *p) { int rc; - report_progress (0,1,"Reading"); + if(verbose > 1) + report_progress(0, 1, "Reading"); rc = avr_read(pgm, p, "signature", 0); if (rc < LIBAVRDUDE_SUCCESS) { pmsg_error("unable to read signature data for part %s, rc=%d\n", p->desc, rc); return rc; } - report_progress (1,1,NULL); + report_progress(1, 1, NULL); return LIBAVRDUDE_SUCCESS; } diff --git a/src/avrcache.c b/src/avrcache.c index c573014b..a0fa9082 100644 --- a/src/avrcache.c +++ b/src/avrcache.c @@ -126,6 +126,9 @@ int avr_has_paged_access(const PROGRAMMER *pgm, const AVRMEM *mem) { } +#define fallback_read_byte (pgm->read_byte != avr_read_byte_cached? pgm->read_byte: avr_read_byte_default) +#define fallback_write_byte (pgm->write_byte != avr_write_byte_cached? pgm->write_byte: avr_write_byte_default) + /* * Read the page containing addr from the device into buf * - Caller to ensure buf has mem->page_size bytes @@ -141,14 +144,14 @@ int avr_read_page_default(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM unsigned char *pagecopy = cfg_malloc("avr_read_page_default()", pgsize); if(pgsize == 1) - return pgm->read_byte(pgm, p, mem, addr, buf); + return fallback_read_byte(pgm, p, mem, addr, buf); memcpy(pagecopy, mem->buf + base, pgsize); if((rc = pgm->paged_load(pgm, p, mem, pgsize, base, pgsize)) >= 0) memcpy(buf, mem->buf + base, pgsize); memcpy(mem->buf + base, pagecopy, pgsize); - if(rc < 0) { + if(rc < 0 && pgm->read_byte != avr_read_byte_cached) { rc = LIBAVRDUDE_SUCCESS; for(int i=0; iread_byte(pgm, p, mem, base+i, pagecopy+i) < 0) { @@ -179,7 +182,7 @@ int avr_write_page_default(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM unsigned char *pagecopy = cfg_malloc("avr_write_page_default()", pgsize); if(pgsize == 1) - return pgm->write_byte(pgm, p, mem, addr, *data); + return fallback_write_byte(pgm, p, mem, addr, *data); memcpy(pagecopy, mem->buf + base, pgsize); memcpy(mem->buf + base, data, pgsize); @@ -261,18 +264,25 @@ static int loadCachePage(AVR_Cache *cp, const PROGRAMMER *pgm, const AVRPART *p, static int writeCachePage(AVR_Cache *cp, const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, int base, int nlOnErr) { // Write modified page cont to device; if unsuccessful try bytewise access if(avr_write_page_default(pgm, p, mem, base, cp->cont + base) < 0) { - for(int i=0; i < cp->page_size; i++) - if(cp->cont[base+i] != cp->copy[base+i]) - if(pgm->write_byte(pgm, p, mem, base+i, cp->cont[base+i]) < 0 || - pgm->read_byte(pgm, p, mem, base+i, cp->copy+base+i) < 0) { - report_progress(1, -1, NULL); - if(nlOnErr && quell_progress) - msg_info("\n"); - pmsg_error("writeCachePage() %s access error at addr 0x%04x\n", mem->desc, base+i); - return LIBAVRDUDE_GENERAL_FAILURE; - } + if(pgm->read_byte != avr_read_byte_cached && pgm->write_byte != avr_write_byte_cached) { + for(int i=0; i < cp->page_size; i++) + if(cp->cont[base+i] != cp->copy[base+i]) + if(pgm->write_byte(pgm, p, mem, base+i, cp->cont[base+i]) < 0 || + pgm->read_byte(pgm, p, mem, base+i, cp->copy+base+i) < 0) { + report_progress(1, -1, NULL); + if(nlOnErr && quell_progress) + msg_info("\n"); + pmsg_error("%s access error at addr 0x%04x\n", mem->desc, base+i); + return LIBAVRDUDE_GENERAL_FAILURE; + } - return LIBAVRDUDE_SUCCESS; // Bytewise writes & reads successful + return LIBAVRDUDE_SUCCESS; // Bytewise writes & reads successful + } + report_progress(1, -1, NULL); + if(nlOnErr && quell_progress) + msg_info("\n"); + pmsg_error("write %s page error at addr 0x%04x\n", mem->desc, base); + return LIBAVRDUDE_GENERAL_FAILURE; } // Read page back from device and update copy to what is on device if(avr_read_page_default(pgm, p, mem, base, cp->copy + base) < 0) { @@ -552,7 +562,7 @@ int avr_read_byte_cached(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM * // Use pgm->read_byte() if not EEPROM/flash or no paged access if(!avr_has_paged_access(pgm, mem)) - return pgm->read_byte(pgm, p, mem, addr, value); + return fallback_read_byte(pgm, p, mem, addr, value); // If address is out of range synchronise cache and, if successful, pretend reading a zero if(addr >= (unsigned long) mem->size) { @@ -592,9 +602,9 @@ int avr_read_byte_cached(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM * int avr_write_byte_cached(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, unsigned long addr, unsigned char data) { - // Use pgm->read_byte() if not EEPROM/flash or no paged access + // Use pgm->write_byte() if not EEPROM/flash or no paged access if(!avr_has_paged_access(pgm, mem)) - return pgm->write_byte(pgm, p, mem, addr, data); + return fallback_write_byte(pgm, p, mem, addr, data); // If address is out of range synchronise caches with device and return whether successful if(addr >= (unsigned long) mem->size) @@ -687,7 +697,7 @@ int avr_page_erase_cached(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM return LIBAVRDUDE_GENERAL_FAILURE; if(mem->page_size == 1) { - if(pgm->write_byte(pgm, p, mem, uaddr, 0xff) < 0) + if(fallback_write_byte(pgm, p, mem, uaddr, 0xff) < 0) return LIBAVRDUDE_GENERAL_FAILURE; } else { if(!pgm->page_erase || pgm->page_erase(pgm, p, mem, uaddr) < 0) diff --git a/src/avrdude.1 b/src/avrdude.1 index ba5292ee..a2225a1a 100644 --- a/src/avrdude.1 +++ b/src/avrdude.1 @@ -332,18 +332,20 @@ programmed in high-voltage serial mode. Override the RS-232 connection baud rate specified in the respective programmer's entry of the configuration file. .It Fl B Ar bitclock -Specify the bit clock period for the JTAG interface or the ISP clock (JTAG ICE only). -The value is a floating-point number in microseconds. -Alternatively, the value might be suffixed with "Hz", "kHz", or "MHz", -in order to specify the bit clock frequency, rather than a period. -The default value of the JTAG ICE results in about 1 microsecond bit -clock period, suitable for target MCUs running at 4 MHz clock and -above. -Unlike certain parameters in the STK500, the JTAG ICE resets all its -parameters to default values when the programming software signs -off from the ICE, so for MCUs running at lower clock speeds, this -parameter must be specified on the command-line. +Specify the bit clock period for the JTAG, PDI, TPI, UPDI, or ISP +interface. The value is a floating-point number in microseconds. +Alternatively, the value might be suffixed with "Hz", "kHz" or +"MHz" in order to specify the bit clock frequency rather than a +period. Some programmers default their bit clock value to a 1 +microsecond bit clock period, suitable for target MCUs running at 4 +MHz clock and above. Slower MCUs need a correspondingly higher bit +clock period. Some programmers reset their bit clock value to the +default value when the programming software signs off, whilst others +store the last used bit clock value. It is recommended to always +specify the bit clock if read/write speed is important. You can use the 'default_bitclock' keyword in your +.Pa ${HOME}/.config/avrdude/avrdude.rc +or .Pa ${HOME}/.avrduderc file to assign a default value to keep from having to specify this option on every invocation. @@ -357,6 +359,8 @@ through the use of a config file to make work with different programmers as long as the programmer supports the Atmel AVR serial program method. You can use the 'default_programmer' keyword in your +.Pa ${HOME}/.config/avrdude/avrdude.rc +or .Pa ${HOME}/.avrduderc file to assign a default programmer to keep from having to specify this option on every invocation. @@ -507,6 +511,8 @@ actual connection to a target controller), this option can be used together with .Fl t to continue in terminal mode. +Moreover, the option allows to continue despite failed initialization +of connection between a programmer and a target. .It Fl i Ar delay For bitbang-type programmers, delay for approximately .Ar delay @@ -1320,10 +1326,10 @@ the CS line being managed outside the application. .Sh FILES .Bl -tag -offset indent -width /dev/ppi0XXX .It Pa /dev/ppi0 -default device to be used for communication with the programming +Default device to be used for communication with the programming hardware .It Pa avrdude.conf -programmer and parts configuration file +Programmer and parts configuration file .Pp On Windows systems, this file is looked up in the same directory as the executable file. @@ -1332,14 +1338,22 @@ On all other systems, the file is first looked up in relative to the path of the executable, then in the same directory as the executable itself, and finally in the system default location .Pa ${PREFIX}/etc/avrdude.conf . +.It Pa ${XDG_CONFIG_HOME}/avrdude/avrdude.rc +Local programmer and parts configuration file (per-user overrides); it follows the same syntax as +.Pa avrdude.conf ; +if the +.Pa ${XDG_CONFIG_HOME} +environment variable is not set or empty, the directory +.Pa ${HOME}/.config/ +is used instead. .It Pa ${HOME}/.avrduderc -programmer and parts configuration file (per-user overrides) +Alternative location of the per-user configuration file if above file does not exist .It Pa ~/.inputrc Initialization file for the .Xr readline 3 library -.It Pa ${PREFIX}/share/doc/avrdude/avrdude.pdf -Schematic of programming hardware +.It Pa /doc/avrdude/avrdude.pdf +User manual .El .\" .Sh EXAMPLES .Sh DIAGNOSTICS diff --git a/src/avrdude.conf.in b/src/avrdude.conf.in index 211f2bb4..792b7df7 100644 --- a/src/avrdude.conf.in +++ b/src/avrdude.conf.in @@ -389,7 +389,7 @@ # ATmega169 0x78 # -# Overall avrdude defaults; suitable for ~/.avrduderc +# Overall avrdude defaults; suitable for ~/.config/avrdude/config # default_parallel = "@DEFAULT_PAR_PORT@"; default_serial = "@DEFAULT_SER_PORT@"; @@ -1270,7 +1270,7 @@ programmer id = "stk600"; desc = "Atmel STK600"; type = "stk600"; - prog_modes = PM_TPI | PM_ISP; + prog_modes = PM_TPI | PM_ISP | PM_PDI; connection_type = usb; ; @@ -2294,7 +2294,7 @@ programmer type = "jtagice3_updi"; prog_modes = PM_UPDI; connection_type = usb; - usbpid = 0x217f, 0x2180, 0x2181; + usbpid = 0x2180, 0x217f, 0x2181; hvupdi_support = 1; ; @@ -2308,7 +2308,7 @@ programmer type = "jtagice3_pdi"; prog_modes = PM_PDI; connection_type = usb; - usbpid = 0x217f, 0x2180, 0x2181; + usbpid = 0x2180, 0x217f, 0x2181; ; #------------------------------------------------------------ @@ -2321,7 +2321,7 @@ programmer type = "jtagice3_isp"; prog_modes = PM_ISP; connection_type = usb; - usbpid = 0x217f, 0x2180, 0x2181; + usbpid = 0x2180, 0x217f, 0x2181; ; #------------------------------------------------------------ diff --git a/src/avrdude.h b/src/avrdude.h index d765e9a5..7ee21bf6 100644 --- a/src/avrdude.h +++ b/src/avrdude.h @@ -21,11 +21,14 @@ #ifndef avrdude_h #define avrdude_h +#include + #define SYSTEM_CONF_FILE "avrdude.conf" #if defined(WIN32) #define USER_CONF_FILE "avrdude.rc" #else #define USER_CONF_FILE ".avrduderc" +#define XDG_USER_CONF_FILE "avrdude/avrdude.rc" #endif extern char *progname; // name of program, for messages @@ -36,7 +39,7 @@ extern int verbose; // verbosity level (-v, -vv, ...) extern int quell_progress; // quell progress report -q, reduce effective verbosity level (-qq, -qqq) int avrdude_message(int msglvl, const char *format, ...); -int avrdude_message2(const char *fname, int msgmode, int msglvl, const char *format, ...); +int avrdude_message2(FILE *fp, int lno, const char *file, const char *func, int msgmode, int msglvl, const char *format, ...); #define MSG_EXT_ERROR (-3) // OS-type error, no -v option, can be suppressed with -qqqqq #define MSG_ERROR (-2) // Avrdude error, no -v option, can be suppressed with -qqqq @@ -49,41 +52,45 @@ int avrdude_message2(const char *fname, int msgmode, int msglvl, const char *for #define MSG_TRACE2 5 // Displayed with -vvvvv #define MSG2_PROGNAME 1 // Start by printing progname -#define MSG2_FUNCTION 2 // Print calling function (1st arg) after progname -#define MSG2_TYPE 4 // Print message type after function or progname -#define MSG2_INDENT1 8 // Start by printing indentation of progname+1 blanks -#define MSG2_INDENT2 16 // Start by printing indentation of progname+2 blanks -#define MSG2_FLUSH 32 // Flush before and after printing +#define MSG2_FUNCTION 2 // Print calling function (1st arg) after progname if >= notice +#define MSG2_FILELINE 4 // Print source file and line number after function if >= debug +#define MSG2_TYPE 8 // Print message type after function or progname +#define MSG2_INDENT1 16 // Start by printing indentation of progname+1 blanks +#define MSG2_INDENT2 32 // Start by printing indentation of progname+2 blanks +#define MSG2_FLUSH 64 // Flush before and after printing // Shortcuts -#define msg_ext_error(...) avrdude_message2(__func__, 0, MSG_EXT_ERROR, __VA_ARGS__) -#define msg_error(...) avrdude_message2(__func__, 0, MSG_ERROR, __VA_ARGS__) -#define msg_warning(...) avrdude_message2(__func__, 0, MSG_WARNING, __VA_ARGS__) -#define msg_info(...) avrdude_message2(__func__, 0, MSG_INFO, __VA_ARGS__) -#define msg_notice(...) avrdude_message2(__func__, 0, MSG_NOTICE, __VA_ARGS__) -#define msg_notice2(...) avrdude_message2(__func__, 0, MSG_NOTICE2, __VA_ARGS__) -#define msg_debug(...) avrdude_message2(__func__, 0, MSG_DEBUG, __VA_ARGS__) -#define msg_trace(...) avrdude_message2(__func__, 0, MSG_TRACE, __VA_ARGS__) -#define msg_trace2(...) avrdude_message2(__func__, 0, MSG_TRACE2, __VA_ARGS__) +#define msg_ext_error(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, 0, MSG_EXT_ERROR, __VA_ARGS__) +#define msg_error(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, 0, MSG_ERROR, __VA_ARGS__) +#define msg_warning(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, 0, MSG_WARNING, __VA_ARGS__) +#define msg_info(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, 0, MSG_INFO, __VA_ARGS__) +#define msg_notice(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, 0, MSG_NOTICE, __VA_ARGS__) +#define msg_notice2(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, 0, MSG_NOTICE2, __VA_ARGS__) +#define msg_debug(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, 0, MSG_DEBUG, __VA_ARGS__) +#define msg_trace(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, 0, MSG_TRACE, __VA_ARGS__) +#define msg_trace2(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, 0, MSG_TRACE2, __VA_ARGS__) -#define pmsg_ext_error(...) avrdude_message2(__func__, MSG2_PROGNAME|MSG2_FUNCTION|MSG2_TYPE|MSG2_FLUSH, MSG_EXT_ERROR, __VA_ARGS__) -#define pmsg_error(...) avrdude_message2(__func__, MSG2_PROGNAME|MSG2_FUNCTION|MSG2_TYPE|MSG2_FLUSH, MSG_ERROR, __VA_ARGS__) -#define pmsg_warning(...) avrdude_message2(__func__, MSG2_PROGNAME|MSG2_FUNCTION|MSG2_TYPE|MSG2_FLUSH, MSG_WARNING, __VA_ARGS__) -#define pmsg_info(...) avrdude_message2(__func__, MSG2_PROGNAME|MSG2_FLUSH, MSG_INFO, __VA_ARGS__) -#define pmsg_notice(...) avrdude_message2(__func__, MSG2_PROGNAME|MSG2_FLUSH, MSG_NOTICE, __VA_ARGS__) -#define pmsg_notice2(...) avrdude_message2(__func__, MSG2_PROGNAME|MSG2_FLUSH, MSG_NOTICE2, __VA_ARGS__) -#define pmsg_debug(...) avrdude_message2(__func__, MSG2_PROGNAME|MSG2_FLUSH, MSG_DEBUG, __VA_ARGS__) -#define pmsg_trace(...) avrdude_message2(__func__, MSG2_PROGNAME|MSG2_FLUSH, MSG_TRACE, __VA_ARGS__) -#define pmsg_trace2(...) avrdude_message2(__func__, MSG2_PROGNAME|MSG2_FLUSH, MSG_TRACE2, __VA_ARGS__) +#define pmsg_ext_error(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_PROGNAME|MSG2_FUNCTION|MSG2_FILELINE|MSG2_TYPE|MSG2_FLUSH, MSG_EXT_ERROR, __VA_ARGS__) +#define pmsg_error(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_PROGNAME|MSG2_FUNCTION|MSG2_FILELINE|MSG2_TYPE|MSG2_FLUSH, MSG_ERROR, __VA_ARGS__) +#define pmsg_warning(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_PROGNAME|MSG2_FUNCTION|MSG2_FILELINE|MSG2_TYPE|MSG2_FLUSH, MSG_WARNING, __VA_ARGS__) +#define pmsg_info(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_PROGNAME|MSG2_FLUSH, MSG_INFO, __VA_ARGS__) +#define pmsg_notice(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_PROGNAME|MSG2_FLUSH, MSG_NOTICE, __VA_ARGS__) +#define pmsg_notice2(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_PROGNAME|MSG2_FLUSH, MSG_NOTICE2, __VA_ARGS__) +#define pmsg_debug(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_PROGNAME|MSG2_FLUSH, MSG_DEBUG, __VA_ARGS__) +#define pmsg_trace(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_PROGNAME|MSG2_FLUSH, MSG_TRACE, __VA_ARGS__) +#define pmsg_trace2(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_PROGNAME|MSG2_FLUSH, MSG_TRACE2, __VA_ARGS__) -#define imsg_ext_error(...) avrdude_message2(__func__, MSG2_INDENT1|MSG2_FLUSH, MSG_EXT_ERROR, __VA_ARGS__) -#define imsg_error(...) avrdude_message2(__func__, MSG2_INDENT1|MSG2_FLUSH, MSG_ERROR, __VA_ARGS__) -#define imsg_warning(...) avrdude_message2(__func__, MSG2_INDENT1|MSG2_FLUSH, MSG_WARNING, __VA_ARGS__) -#define imsg_info(...) avrdude_message2(__func__, MSG2_INDENT2|MSG2_FLUSH, MSG_INFO, __VA_ARGS__) -#define imsg_notice(...) avrdude_message2(__func__, MSG2_INDENT2|MSG2_FLUSH, MSG_NOTICE, __VA_ARGS__) -#define imsg_notice2(...) avrdude_message2(__func__, MSG2_INDENT2|MSG2_FLUSH, MSG_NOTICE2, __VA_ARGS__) -#define imsg_debug(...) avrdude_message2(__func__, MSG2_INDENT2|MSG2_FLUSH, MSG_DEBUG, __VA_ARGS__) -#define imsg_trace(...) avrdude_message2(__func__, MSG2_INDENT2|MSG2_FLUSH, MSG_TRACE, __VA_ARGS__) -#define imsg_trace2(...) avrdude_message2(__func__, MSG2_INDENT2|MSG2_FLUSH, MSG_TRACE2, __VA_ARGS__) +#define imsg_ext_error(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_INDENT1|MSG2_FLUSH, MSG_EXT_ERROR, __VA_ARGS__) +#define imsg_error(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_INDENT1|MSG2_FLUSH, MSG_ERROR, __VA_ARGS__) +#define imsg_warning(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_INDENT1|MSG2_FLUSH, MSG_WARNING, __VA_ARGS__) +#define imsg_info(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_INDENT2|MSG2_FLUSH, MSG_INFO, __VA_ARGS__) +#define imsg_notice(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_INDENT2|MSG2_FLUSH, MSG_NOTICE, __VA_ARGS__) +#define imsg_notice2(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_INDENT2|MSG2_FLUSH, MSG_NOTICE2, __VA_ARGS__) +#define imsg_debug(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_INDENT2|MSG2_FLUSH, MSG_DEBUG, __VA_ARGS__) +#define imsg_trace(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_INDENT2|MSG2_FLUSH, MSG_TRACE, __VA_ARGS__) +#define imsg_trace2(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_INDENT2|MSG2_FLUSH, MSG_TRACE2, __VA_ARGS__) + +#define term_out(...) avrdude_message2(stdout, __LINE__, __FILE__, __func__, MSG2_FLUSH, MSG_INFO, __VA_ARGS__) +#define fmsg_out(fp, ...) avrdude_message2(fp, __LINE__, __FILE__, __func__, MSG2_FLUSH, MSG_INFO, __VA_ARGS__) #endif diff --git a/src/avrpart.c b/src/avrpart.c index 49a55dba..cf4fa996 100644 --- a/src/avrpart.c +++ b/src/avrpart.c @@ -498,22 +498,15 @@ void avr_mem_display(const char *prefix, FILE *f, const AVRMEM *m, int i, j; char * optr; - if (m == NULL) { + if (m == NULL || verbose > 2) { fprintf(f, "%s Block Poll Page Polled\n" "%sMemory Type Alias Mode Delay Size Indx Paged Size Size #Pages MinW MaxW ReadBack\n" "%s----------- -------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- ---------\n", prefix, prefix, prefix); } - else { - if (verbose > 2) { - fprintf(f, - "%s Block Poll Page Polled\n" - "%sMemory Type Alias Mode Delay Size Indx Paged Size Size #Pages MinW MaxW ReadBack\n" - "%s----------- -------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- ---------\n", - prefix, prefix, prefix); - } + if (m != NULL) { // Only print memory section if the previous section printed isn't identical if(prev_mem_offset != m->offset || prev_mem_size != m->size || (strcmp(p->family_id, "") == 0)) { prev_mem_offset = m->offset; diff --git a/src/doc/avrdude.texi b/src/doc/avrdude.texi index 1e139234..cb8bd103 100644 --- a/src/doc/avrdude.texi +++ b/src/doc/avrdude.texi @@ -440,19 +440,21 @@ Override the RS-232 connection baud rate specified in the respective programmer's entry of the configuration file. @item -B @var{bitclock} -Specify the bit clock period for the JTAG interface or the ISP clock (JTAG ICE only). -The value is a floating-point number in microseconds. -Alternatively, the value might be suffixed with "Hz", "kHz", or "MHz", -in order to specify the bit clock frequency, rather than a period. -The default value of the JTAG ICE results in about 1 microsecond bit -clock period, suitable for target MCUs running at 4 MHz clock and -above. -Unlike certain parameters in the STK500, the JTAG ICE resets all its -parameters to default values when the programming software signs -off from the ICE, so for MCUs running at lower clock speeds, this -parameter must be specified on the command-line. -It can also be set in the configuration file by using the 'default_bitclock' -keyword. +Specify the bit clock period for the JTAG, PDI, TPI, UPDI, or ISP +interface. The value is a floating-point number in microseconds. +Alternatively, the value might be suffixed with "Hz", "kHz" or +"MHz" in order to specify the bit clock frequency rather than a +period. Some programmers default their bit clock value to a 1 +microsecond bit clock period, suitable for target MCUs running at 4 +MHz clock and above. Slower MCUs need a correspondingly higher bit +clock period. Some programmers reset their bit clock value to the +default value when the programming software signs off, whilst +others store the last used bit clock value. It is recommended to +always specify the bit clock if read/write speed is important. You +can use the 'default_bitclock' keyword in your +@code{~/.config/avrdude/avrdude.rc} or @code{~/.avrduderc} +configuration file to assign a default value to keep from having to +specify this option on every invocation. @item -c @var{programmer-id} Specify the programmer to be used. AVRDUDE knows about several common @@ -598,6 +600,8 @@ Also, for programmers like the Atmel STK500 and STK600 which can adjust parameters local to the programming tool (independent of an actual connection to a target controller), this option can be used together with @option{-t} to continue in terminal mode. +Moreover, the option allows to continue despite failed initialization +of connection between a programmer and a target. @item -i @var{delay} For bitbang-type programmers, delay for approximately @@ -1714,21 +1718,24 @@ AVRDUDE reads a configuration file upon startup which describes all of the parts and programmers that it knows about. The advantage of this is that if you have a chip that is not currently supported by AVRDUDE, you can add it to the configuration file without waiting for a new release -of AVRDUDE. Likewise, if you have a parallel port programmer that is -not supported by AVRDUDE, chances are good that you can copy and -existing programmer definition, and with only a few changes, make your -programmer work with AVRDUDE. +of AVRDUDE. Likewise, if you have a parallel port programmer that is +not supported, chances are that you can copy an +existing programmer definition and, with only a few changes, make your +programmer work. AVRDUDE first looks for a system wide configuration file in a platform dependent location. On Unix, this is usually -@code{/usr/local/etc/avrdude.conf}, while on Windows it is usually in the -same location as the executable file. The name of this file can be -changed using the @option{-C} command line option. After the system wide -configuration file is parsed, AVRDUDE looks for a per-user configuration +@code{/usr/local/etc/avrdude.conf}, whilst on Windows it is usually in the +same location as the executable file. The full name of this file can be +specified using the @option{-C} command line option. After parsing the system wide +configuration file, AVRDUDE looks for a per-user configuration file to augment or override the system wide defaults. On Unix, the -per-user file is @code{.avrduderc} within the user's home directory. On -Windows, this file is the @code{avrdude.rc} file located in the same -directory as the executable. +per-user file is @code{$@{XDG_CONFIG_HOME@}/avrdude/avrdude.rc}, whereas +if @code{$@{XDG_CONFIG_HOME@}} is either not set or empty, +@code{$@{HOME@}/.config/} is used instead. If that does not exists +@code{.avrduderc} within the user's home directory is used. On Windows, +this file is the @code{avrdude.rc} file located in the same directory as +the executable. @menu * AVRDUDE Defaults:: @@ -3044,14 +3051,15 @@ See also: @url{http://www.libusb.org/ticket/6} @item Problem: after flashing a firmware that reduces the target's clock speed (e.g. through the @code{CLKPR} register), further ISP connection -attempts fail. +attempts fail. Or a programmer cannot initialize communication with +a brand new chip. Solution: Even though ISP starts with pulling @var{/RESET} low, the -target continues to run at the internal clock speed as defined by the -firmware running before. Therefore, the ISP clock speed must be -reduced appropriately (to less than 1/4 of the internal clock speed) -using the -B option before the ISP initialization sequence will -succeed. +target continues to run at the internal clock speed either as defined by +the firmware running before or as set by the factory. Therefore, the +ISP clock speed must be reduced appropriately (to less than 1/4 of the +internal clock speed) using the -B option before the ISP initialization +sequence will succeed. As that slows down the entire subsequent ISP session, it might make sense to just issue a @emph{chip erase} using the slow ISP clock diff --git a/src/flip2.c b/src/flip2.c index 50275f46..84609576 100644 --- a/src/flip2.c +++ b/src/flip2.c @@ -121,6 +121,8 @@ enum flip2_mem_unit { FLIP2_MEM_UNIT_EXT_MEM_DF = 0x10 }; +#ifdef HAVE_LIBUSB + /* EXPORTED PROGRAMMER FUNCTION PROTOTYPES */ static int flip2_open(PROGRAMMER *pgm, const char *port_spec); @@ -146,8 +148,6 @@ static void flip2_setup(PROGRAMMER * pgm); static void flip2_teardown(PROGRAMMER * pgm); /* INTERNAL PROGRAMMER FUNCTION PROTOTYPES */ -#ifdef HAVE_LIBUSB -// The internal ones are made conditional, as they're not defined further down #ifndef HAVE_LIBUSB static void flip2_show_info(struct flip2 *flip2); diff --git a/src/jtag3.c b/src/jtag3.c index e3e39fbe..c5a48bf6 100644 --- a/src/jtag3.c +++ b/src/jtag3.c @@ -103,7 +103,7 @@ static int jtag3_read_byte(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM static int jtag3_write_byte(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, unsigned long addr, unsigned char data); static int jtag3_set_sck_period(const PROGRAMMER *pgm, double v); -void jtag3_print_parms1(const PROGRAMMER *pgm, const char *p); +void jtag3_print_parms1(const PROGRAMMER *pgm, const char *p, FILE *fp); static int jtag3_paged_write(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m, unsigned int page_size, unsigned int addr, unsigned int n_bytes); @@ -1077,7 +1077,7 @@ static int jtag3_initialize(const PROGRAMMER *pgm, const AVRPART *p) { if (PDATA(pgm)->set_sck(pgm, parm) < 0) return -1; } - jtag3_print_parms1(pgm, progbuf); + jtag3_print_parms1(pgm, progbuf, stderr); if (conn == PARM3_CONN_JTAG) { pmsg_notice2("jtag3_initialize(): " @@ -1504,6 +1504,30 @@ int jtag3_open_common(PROGRAMMER *pgm, const char *port) { } #endif if (rv < 0) { + // Check if SNAP or PICkit4 is in PIC mode + for(LNODEID ln=lfirst(pgm->id); ln; ln=lnext(ln)) { + if (matches(ldata(ln), "snap")) { + pinfo.usbinfo.vid = USB_VENDOR_MICROCHIP; + pinfo.usbinfo.pid = USB_DEVICE_SNAP_PIC_MODE; + int pic_mode = serial_open(port, pinfo, &pgm->fd); + if(pic_mode >= 0) { + msg_error("\n"); + pmsg_error("MPLAB SNAP in PIC mode detected!\n"); + imsg_error("Use MPLAB X or Microchip Studio to switch to AVR mode\n\n"); + return -1; + } + } else if(matches(ldata(ln), "pickit4")) { + pinfo.usbinfo.vid = USB_VENDOR_MICROCHIP; + pinfo.usbinfo.pid = USB_DEVICE_PICKIT4_PIC_MODE; + int pic_mode = serial_open(port, pinfo, &pgm->fd); + if(pic_mode >= 0) { + msg_error("\n"); + pmsg_error("PICkit4 in PIC mode detected!\n"); + imsg_error("Use MPLAB X or Microchip Studio to switch to AVR mode\n\n"); + return -1; + } + } + } pmsg_error("did not find any device matching VID 0x%04x and PID list: ", (unsigned) pinfo.usbinfo.vid); int notfirst = 0; @@ -2333,12 +2357,12 @@ static void jtag3_display(const PROGRAMMER *pgm, const char *p) { } -void jtag3_print_parms1(const PROGRAMMER *pgm, const char *p) { +void jtag3_print_parms1(const PROGRAMMER *pgm, const char *p, FILE *fp) { unsigned char buf[3]; if (jtag3_getparm(pgm, SCOPE_GENERAL, 1, PARM3_VTARGET, buf, 2) < 0) return; - msg_info("%sVtarget %s: %.2f V\n", p, + fmsg_out(fp, "%sVtarget %s: %.2f V\n", p, verbose? "": " ", b2_to_u16(buf)/1000.0); // Print features unique to the Power Debugger @@ -2350,7 +2374,7 @@ void jtag3_print_parms1(const PROGRAMMER *pgm, const char *p) { if (jtag3_getparm(pgm, SCOPE_GENERAL, 1, PARM3_VADJUST, buf, 2) < 0) return; analog_raw_data = b2_to_u16(buf); - msg_info("%sVout set %s: %.2f V\n", p, + fmsg_out(fp, "%sVout set %s: %.2f V\n", p, verbose? "": " ", analog_raw_data / 1000.0); // Read measured generator voltage value (VOUT) @@ -2362,7 +2386,7 @@ void jtag3_print_parms1(const PROGRAMMER *pgm, const char *p) { else { if (analog_raw_data & 0x0800) analog_raw_data |= 0xF000; - msg_info("%sVout measured %s: %.02f V\n", p, + fmsg_out(fp, "%sVout measured %s: %.02f V\n", p, verbose? "": " ", ((float) analog_raw_data / -200.0)); } @@ -2375,7 +2399,7 @@ void jtag3_print_parms1(const PROGRAMMER *pgm, const char *p) { else { if (analog_raw_data & 0x0800) analog_raw_data |= 0xF000; - msg_info("%sCh A voltage %s: %.03f V\n", p, + fmsg_out(fp, "%sCh A voltage %s: %.03f V\n", p, verbose? "": " ", ((float) analog_raw_data / -200.0)); } @@ -2386,7 +2410,7 @@ void jtag3_print_parms1(const PROGRAMMER *pgm, const char *p) { if (buf[0] != 0x90) pmsg_error("invalid PARM3_ANALOG_A_CURRENT data packet format\n"); else - msg_info("%sCh A current %s: %.3f mA\n", p, + fmsg_out(fp, "%sCh A current %s: %.3f mA\n", p, verbose? "": " ", (float) analog_raw_data * 0.003472); // Read channel B voltage @@ -2398,7 +2422,7 @@ void jtag3_print_parms1(const PROGRAMMER *pgm, const char *p) { else { if (analog_raw_data & 0x0800) analog_raw_data |= 0xF000; - msg_info("%sCh B voltage %s: %.03f V\n", p, + fmsg_out(fp, "%sCh B voltage %s: %.03f V\n", p, verbose? "": " ", (float) analog_raw_data / -200.0); } @@ -2411,7 +2435,7 @@ void jtag3_print_parms1(const PROGRAMMER *pgm, const char *p) { else { if (analog_raw_data & 0x0800) analog_raw_data |= 0xF000; - msg_info("%sCh B current %s: %.3f mA\n", p, + fmsg_out(fp, "%sCh B current %s: %.3f mA\n", p, verbose? "": " ", (float) analog_raw_data * 0.555556); } break; @@ -2422,33 +2446,33 @@ void jtag3_print_parms1(const PROGRAMMER *pgm, const char *p) { return; if (b2_to_u16(buf) > 0) { - msg_info("%sJTAG clock megaAVR/program : %u kHz\n", p, b2_to_u16(buf)); + fmsg_out(fp, "%sJTAG clock megaAVR/program : %u kHz\n", p, b2_to_u16(buf)); } if (jtag3_getparm(pgm, SCOPE_AVR, 1, PARM3_CLK_MEGA_DEBUG, buf, 2) < 0) return; if (b2_to_u16(buf) > 0) { - msg_info("%sJTAG clock megaAVR/debug : %u kHz\n", p, b2_to_u16(buf)); + fmsg_out(fp, "%sJTAG clock megaAVR/debug : %u kHz\n", p, b2_to_u16(buf)); } if (jtag3_getparm(pgm, SCOPE_AVR, 1, PARM3_CLK_XMEGA_JTAG, buf, 2) < 0) return; if (b2_to_u16(buf) > 0) { - msg_info("%sJTAG clock Xmega : %u kHz\n", p, b2_to_u16(buf)); + fmsg_out(fp, "%sJTAG clock Xmega : %u kHz\n", p, b2_to_u16(buf)); } if (jtag3_getparm(pgm, SCOPE_AVR, 1, PARM3_CLK_XMEGA_PDI, buf, 2) < 0) return; if (b2_to_u16(buf) > 0) { - msg_info("%sPDI/UPDI clock Xmega/megaAVR : %u kHz\n", p, b2_to_u16(buf)); + fmsg_out(fp, "%sPDI/UPDI clock Xmega/megaAVR : %u kHz\n", p, b2_to_u16(buf)); } } -static void jtag3_print_parms(const PROGRAMMER *pgm) { - jtag3_print_parms1(pgm, ""); +static void jtag3_print_parms(const PROGRAMMER *pgm, FILE *fp) { + jtag3_print_parms1(pgm, "", fp); } static unsigned char jtag3_memtype(const PROGRAMMER *pgm, const AVRPART *p, unsigned long addr) { diff --git a/src/jtag3.h b/src/jtag3.h index 945ddcb2..7ee95b5b 100644 --- a/src/jtag3.h +++ b/src/jtag3.h @@ -38,7 +38,7 @@ int jtag3_setparm(const PROGRAMMER *pgm, unsigned char scope, unsigned char *value, unsigned char length); int jtag3_command(const PROGRAMMER *pgm, unsigned char *cmd, unsigned int cmdlen, unsigned char **resp, const char *descr); -void jtag3_print_parms1(const PROGRAMMER *pgm, const char *p); +void jtag3_print_parms1(const PROGRAMMER *pgm, const char *p, FILE *fp); int jtag3_set_vtarget(const PROGRAMMER *pgm, double voltage); extern const char jtag3_desc[]; extern const char jtag3_dw_desc[]; diff --git a/src/jtagmkI.c b/src/jtagmkI.c index 796a9cb3..9c3be6dd 100644 --- a/src/jtagmkI.c +++ b/src/jtagmkI.c @@ -104,7 +104,7 @@ static int jtagmkI_getparm(const PROGRAMMER *pgm, unsigned char parm, unsigned char * value); static int jtagmkI_setparm(const PROGRAMMER *pgm, unsigned char parm, unsigned char value); -static void jtagmkI_print_parms1(const PROGRAMMER *pgm, const char *p); +static void jtagmkI_print_parms1(const PROGRAMMER *pgm, const char *p, FILE *fp); static int jtagmkI_resync(const PROGRAMMER *pgm, int maxtries, int signon); @@ -1170,13 +1170,13 @@ static void jtagmkI_display(const PROGRAMMER *pgm, const char *p) { msg_info("%sICE HW version: 0x%02x\n", p, hw); msg_info("%sICE FW version: 0x%02x\n", p, fw); - jtagmkI_print_parms1(pgm, p); + jtagmkI_print_parms1(pgm, p, stderr); return; } -static void jtagmkI_print_parms1(const PROGRAMMER *pgm, const char *p) { +static void jtagmkI_print_parms1(const PROGRAMMER *pgm, const char *p, FILE *fp) { unsigned char vtarget, jtag_clock; const char *clkstr; double clk; @@ -1211,15 +1211,15 @@ static void jtagmkI_print_parms1(const PROGRAMMER *pgm, const char *p) { clk = 1e6; } - msg_info("%sVtarget : %.1f V\n", p, 6.25 * (unsigned)vtarget / 255.0); - msg_info("%sJTAG clock : %s (%.1f us)\n", p, clkstr, 1.0e6 / clk); + fmsg_out(fp, "%sVtarget : %.1f V\n", p, 6.25 * (unsigned)vtarget / 255.0); + fmsg_out(fp, "%sJTAG clock : %s (%.1f us)\n", p, clkstr, 1.0e6 / clk); return; } -static void jtagmkI_print_parms(const PROGRAMMER *pgm) { - jtagmkI_print_parms1(pgm, ""); +static void jtagmkI_print_parms(const PROGRAMMER *pgm, FILE *fp) { + jtagmkI_print_parms1(pgm, "", fp); } const char jtagmkI_desc[] = "Atmel JTAG ICE mkI"; diff --git a/src/jtagmkII.c b/src/jtagmkII.c index 9e3f1bbb..2f6425cf 100644 --- a/src/jtagmkII.c +++ b/src/jtagmkII.c @@ -144,7 +144,7 @@ static int jtagmkII_reset(const PROGRAMMER *pgm, unsigned char flags); static int jtagmkII_set_sck_period(const PROGRAMMER *pgm, double v); static int jtagmkII_setparm(const PROGRAMMER *pgm, unsigned char parm, unsigned char * value); -static void jtagmkII_print_parms1(const PROGRAMMER *pgm, const char *p); +static void jtagmkII_print_parms1(const PROGRAMMER *pgm, const char *p, FILE *fp); static int jtagmkII_paged_write(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m, unsigned int page_size, unsigned int addr, unsigned int n_bytes); @@ -2508,13 +2508,13 @@ static void jtagmkII_display(const PROGRAMMER *pgm, const char *p) { PDATA(pgm)->serno[0], PDATA(pgm)->serno[1], PDATA(pgm)->serno[2], PDATA(pgm)->serno[3], PDATA(pgm)->serno[4], PDATA(pgm)->serno[5]); - jtagmkII_print_parms1(pgm, p); + jtagmkII_print_parms1(pgm, p, stderr); return; } -static void jtagmkII_print_parms1(const PROGRAMMER *pgm, const char *p) { +static void jtagmkII_print_parms1(const PROGRAMMER *pgm, const char *p, FILE *fp) { unsigned char vtarget[4], jtag_clock[4]; char clkbuf[20]; double clk; @@ -2522,7 +2522,7 @@ static void jtagmkII_print_parms1(const PROGRAMMER *pgm, const char *p) { if (jtagmkII_getparm(pgm, PAR_OCD_VTARGET, vtarget) < 0) return; - msg_info("%sVtarget : %.1f V\n", p, b2_to_u16(vtarget) / 1000.0); + fmsg_out(fp, "%sVtarget : %.1f V\n", p, b2_to_u16(vtarget) / 1000.0); if ((pgm->flag & PGM_FL_IS_JTAG)) { if (jtagmkII_getparm(pgm, PAR_OCD_JTAG_CLK, jtag_clock) < 0) @@ -2541,15 +2541,15 @@ static void jtagmkII_print_parms1(const PROGRAMMER *pgm, const char *p) { sprintf(clkbuf, "%.1f kHz", 5.35e3 / (double)jtag_clock[0]); clk = 5.35e6 / (double)jtag_clock[0]; - msg_info("%sJTAG clock : %s (%.1f us)\n", p, clkbuf, 1.0e6 / clk); + fmsg_out(fp, "%sJTAG clock : %s (%.1f us)\n", p, clkbuf, 1.0e6 / clk); } } return; } -static void jtagmkII_print_parms(const PROGRAMMER *pgm) { - jtagmkII_print_parms1(pgm, ""); +static void jtagmkII_print_parms(const PROGRAMMER *pgm, FILE *fp) { + jtagmkII_print_parms1(pgm, "", fp); } static unsigned char jtagmkII_memtype(const PROGRAMMER *pgm, const AVRPART *p, unsigned long addr) { diff --git a/src/libavrdude.h b/src/libavrdude.h index b63dcd27..f4f2146d 100644 --- a/src/libavrdude.h +++ b/src/libavrdude.h @@ -783,7 +783,8 @@ typedef struct programmer_t { unsigned long addr, unsigned char *value); int (*read_sig_bytes) (const struct programmer_t *pgm, const AVRPART *p, const AVRMEM *m); int (*read_sib) (const struct programmer_t *pgm, const AVRPART *p, char *sib); - void (*print_parms) (const struct programmer_t *pgm); + int (*term_keep_alive)(const struct programmer_t *pgm, const AVRPART *p); + void (*print_parms) (const struct programmer_t *pgm, FILE *fp); int (*set_vtarget) (const struct programmer_t *pgm, double v); int (*set_varef) (const struct programmer_t *pgm, unsigned int chan, double v); int (*set_fosc) (const struct programmer_t *pgm, double v); diff --git a/src/main.c b/src/main.c index 73b0a25c..d1d0ebca 100644 --- a/src/main.c +++ b/src/main.c @@ -87,36 +87,48 @@ static const char *avrdude_message_type(int msglvl) { } } -int avrdude_message2(const char *fname, int msgmode, int msglvl, const char *format, ...) { +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 - if ((quell_progress < 2? verbose: verbose+1-quell_progress) >= msglvl) { + // 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(stderr, "%s", progname); + fprintf(fp, "%s", progname); if(verbose >= MSG_NOTICE && (msgmode & MSG2_FUNCTION)) - fprintf(stderr, " %s()", fname); + 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(stderr, " %s", avrdude_message_type(msglvl)); - fprintf(stderr, ": "); + fprintf(fp, " %s", avrdude_message_type(msglvl)); + fprintf(fp, ": "); } else if(msgmode & MSG2_INDENT1) { - fprintf(stderr, "%*s", (int) strlen(progname)+1, ""); + fprintf(fp, "%*s", (int) strlen(progname)+1, ""); } else if(msgmode & MSG2_INDENT2) { - fprintf(stderr, "%*s", (int) strlen(progname)+2, ""); + fprintf(fp, "%*s", (int) strlen(progname)+2, ""); } va_start(ap, format); - rc = vfprintf(stderr, format, ap); + rc = vfprintf(fp, format, ap); va_end(ap); } if(msgmode & MSG2_FLUSH) - fflush(stderr); + fflush(fp); return rc; } @@ -155,14 +167,14 @@ static void usage(void) "Options:\n" " -p Specify AVR device\n" " -b Override RS-232 baud rate\n" - " -B Specify JTAG/STK500v2 bit clock period (us)\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 check\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" @@ -425,6 +437,32 @@ static void exit_part_not_found(const char *partdesc) { } +#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 */ @@ -465,10 +503,6 @@ int main(int argc, char * argv []) char * logfile; /* Use logfile rather than stderr for diagnostics */ enum updateflags uflags = UF_AUTO_ERASE | UF_VERIFY; /* Flags for do_op() */ -#if !defined(WIN32) - char * homedir; -#endif - #ifdef _MSC_VER _set_printf_count_output(1); #endif @@ -856,14 +890,10 @@ int main(int argc, char * argv []) win_usr_config_set(usr_config); #else usr_config[0] = 0; - homedir = getenv("HOME"); - if (homedir != NULL) { - strcpy(usr_config, homedir); - i = strlen(usr_config); - if (i && (usr_config[i - 1] != '/')) - strcat(usr_config, "/"); - strcat(usr_config, USER_CONF_FILE); - } + 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) @@ -1190,9 +1220,10 @@ int main(int argc, char * argv []) 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("double check connections and try again or use -F to override\n"); - imsg_error("this check\n\n"); + imsg_error("- use -F to override this check\n\n"); exitrc = 1; goto main_exit; } diff --git a/src/pgm.c b/src/pgm.c index b1836e00..ccded0cc 100644 --- a/src/pgm.c +++ b/src/pgm.c @@ -140,6 +140,7 @@ PROGRAMMER *pgm_new(void) { pgm->write_setup = NULL; pgm->read_sig_bytes = NULL; pgm->read_sib = NULL; + pgm->term_keep_alive= NULL; pgm->print_parms = NULL; pgm->set_vtarget = NULL; pgm->set_varef = NULL; diff --git a/src/stk500.c b/src/stk500.c index fecd8525..7f26691a 100644 --- a/src/stk500.c +++ b/src/stk500.c @@ -47,7 +47,7 @@ static int stk500_getparm(const PROGRAMMER *pgm, unsigned parm, unsigned *value); static int stk500_setparm(const PROGRAMMER *pgm, unsigned parm, unsigned value); -static void stk500_print_parms1(const PROGRAMMER *pgm, const char *p); +static void stk500_print_parms1(const PROGRAMMER *pgm, const char *p, FILE *fp); static int stk500_send(const PROGRAMMER *pgm, unsigned char *buf, size_t len) { @@ -625,6 +625,12 @@ static void stk500_disable(const PROGRAMMER *pgm) { } static void stk500_enable(PROGRAMMER *pgm, const AVRPART *p) { + AVRMEM *mem; + if(pgm->prog_modes & PM_SPM) // For bootloaders (eg, arduino) + if(!(p->prog_modes & (PM_UPDI | PM_PDI | PM_aWire))) // Classic parts, eg, optiboot with word addresses + if((mem = avr_locate_mem(p, "eeprom"))) + if(mem->page_size == 1) // Increase pagesize if it is 1 + mem->page_size = 16; return; } @@ -666,27 +672,56 @@ static void stk500_close(PROGRAMMER * pgm) } -static int stk500_loadaddr(const PROGRAMMER *pgm, const AVRMEM *mem, const unsigned int addr) { +// Address is byte address; a_div == 2: send word address; a_div == 1: send byte address +static int stk500_loadaddr(const PROGRAMMER *pgm, const AVRMEM *mem, unsigned int addr, int a_div) { unsigned char buf[16]; int tries; unsigned char ext_byte; - OPCODE * lext; + + addr /= a_div; tries = 0; retry: tries++; - /* To support flash > 64K words the correct Extended Address Byte is needed */ - lext = mem->op[AVR_OP_LOAD_EXT_ADDR]; - if (lext != NULL) { - ext_byte = (addr >> 16) & 0xff; - if (ext_byte != PDATA(pgm)->ext_addr_byte) { - /* Either this is the first addr load, or a different 64K word section */ - memset(buf, 0, 4); - avr_set_bits(lext, buf); - avr_set_addr(lext, buf, addr); - stk500_cmd(pgm, buf, buf); - PDATA(pgm)->ext_addr_byte = ext_byte; + // Support large flash by sending the correct extended address byte when needed + + if(pgm->prog_modes & PM_SPM) { // Bootloaders, eg, optiboot, optiboot_dx, optiboot_x + if(mem->size/a_div > 64*1024) { // Extended addressing needed + ext_byte = (addr >> 16) & 0xff; + if(ext_byte != PDATA(pgm)->ext_addr_byte) { // First addr load or a different 64k section + buf[0] = 0x4d; // Protocol bytes that bootloaders expect + buf[1] = 0x00; + buf[2] = ext_byte; + buf[3] = 0x00; + if(stk500_cmd(pgm, buf, buf) == 0) + PDATA(pgm)->ext_addr_byte = ext_byte; + } + /* + * Ensure next paged r/w will load ext addr again if page sits just below a 64k boundary + * + * Some bootloaders increment their copy of ext_addr_byte in that situation, eg, when they + * use elpm rx,Z+ to read a byte from flash or spm Z+ to write to flash whilst they keep + * ext_addr_byte in RAMPZ, which in turn gets incremented by Z+ at 64k page boundaries. So, + * if an upload with automated verify finishes just below 64k, AVRDUDE still holds + * ext_addr_byte at the current 64k segment whilst its copy in the bootloader has been + * auto-incremented. Verifying the code from start exposes the discrepancy. + */ + if((addr & 0xffff0000) != ((addr+mem->page_size/a_div) & 0xffff0000)) + PDATA(pgm)->ext_addr_byte = 0xff; + } + } else { // Programmer *not* for bootloaders? Original stk500v1 protocol! + OPCODE *lext = mem->op[AVR_OP_LOAD_EXT_ADDR]; + + if(lext) { + ext_byte = (addr >> 16) & 0xff; + if(ext_byte != PDATA(pgm)->ext_addr_byte) { // First addr load or a different 64k section + memset(buf, 0, 4); // Part's load_ext_addr command is typically 4d 00 ext_addr 00 + avr_set_bits(lext, buf); + avr_set_addr(lext, buf, addr); + if(stk500_cmd(pgm, buf, buf) == 0) + PDATA(pgm)->ext_addr_byte = ext_byte; + } } } @@ -724,6 +759,29 @@ static int stk500_loadaddr(const PROGRAMMER *pgm, const AVRMEM *mem, const unsig } +static int set_memtype_a_div(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m, int *memtypep, int *a_divp) { + if(avr_mem_is_flash_type(m)) { + *memtypep = 'F'; + if(!(pgm->prog_modes & PM_SPM)) // Programmer *not* for bootloaders: original stk500v1 protocol + *a_divp = m->op[AVR_OP_LOADPAGE_LO] || m->op[AVR_OP_READ_LO]? 2: 1; + else if(!(p->prog_modes & (PM_UPDI | PM_PDI | PM_aWire))) + *a_divp = 2; // Bootloader where part is a "classic" part (eg, optiboot) + else + *a_divp = 1; // Bootloader where part is Xmega or "new" families (optiboot_x, optiboot_dx) + return 0; + } + + if(avr_mem_is_eeprom_type(m)) { + *memtypep = 'E'; + // Word addr for bootloaders where part is a "classic" part (eg, optiboot, arduinoisp, ...), byte addr otherwise + *a_divp = (pgm->prog_modes & PM_SPM) && !(p->prog_modes & (PM_UPDI | PM_PDI))? 2: 1; + return 0; + } + + return -1; +} + + static int stk500_paged_write(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m, unsigned int page_size, unsigned int addr, unsigned int n_bytes) @@ -736,25 +794,12 @@ static int stk500_paged_write(const PROGRAMMER *pgm, const AVRPART *p, const AVR unsigned int n; unsigned int i; - if (strcmp(m->desc, "flash") == 0) { - memtype = 'F'; - a_div = 2; - } else if (strcmp(m->desc, "eeprom") == 0) { - memtype = 'E'; - /* - * The STK original 500 v1 protocol actually expects a_div = 1, but the - * v1.x FW of the STK500 kit has been superseded by v2 FW in the mid - * 2000s. Since optiboot, arduino as ISP and others assume a_div = 2, - * better use that. See https://github.com/avrdudes/avrdude/issues/967 - */ - a_div = 2; - } else { + if(set_memtype_a_div(pgm, p, m, &memtype, &a_div) < 0) return -2; - } n = addr + n_bytes; #if 0 - msg_info( + msg_debug( "n_bytes = %d\n" "n = %u\n" "a_div = %d\n" @@ -775,7 +820,7 @@ static int stk500_paged_write(const PROGRAMMER *pgm, const AVRPART *p, const AVR tries = 0; retry: tries++; - stk500_loadaddr(pgm, m, addr/a_div); + stk500_loadaddr(pgm, m, addr, a_div); /* build command block and avoid multiple send commands as it leads to a crash of the silabs usb serial driver on mac os x */ @@ -830,21 +875,8 @@ static int stk500_paged_load(const PROGRAMMER *pgm, const AVRPART *p, const AVRM unsigned int n; int block_size; - if (strcmp(m->desc, "flash") == 0) { - memtype = 'F'; - a_div = 2; - } else if (strcmp(m->desc, "eeprom") == 0) { - memtype = 'E'; - /* - * The STK original 500 v1 protocol actually expects a_div = 1, but the - * v1.x FW of the STK500 kit has been superseded by v2 FW in the mid - * 2000s. Since optiboot, arduino as ISP and others assume a_div = 2, - * better use that. See https://github.com/avrdudes/avrdude/issues/967 - */ - a_div = 2; - } else { + if(set_memtype_a_div(pgm, p, m, &memtype, &a_div) < 0) return -2; - } n = addr + n_bytes; for (; addr < n; addr += block_size) { @@ -861,7 +893,7 @@ static int stk500_paged_load(const PROGRAMMER *pgm, const AVRPART *p, const AVRM tries = 0; retry: tries++; - stk500_loadaddr(pgm, m, addr/a_div); + stk500_loadaddr(pgm, m, addr, a_div); buf[0] = Cmnd_STK_READ_PAGE; buf[1] = (block_size >> 8) & 0xff; buf[2] = block_size & 0xff; @@ -1160,13 +1192,13 @@ static void stk500_display(const PROGRAMMER *pgm, const char *p) { msg_info("%sTopcard : %s\n", p, n); } if(strcmp(pgm->type, "Arduino") != 0) - stk500_print_parms1(pgm, p); + stk500_print_parms1(pgm, p, stderr); return; } -static void stk500_print_parms1(const PROGRAMMER *pgm, const char *p) { +static void stk500_print_parms1(const PROGRAMMER *pgm, const char *p, FILE *fp) { unsigned vtarget, vadjust, osc_pscale, osc_cmatch, sck_duration; stk500_getparm(pgm, Parm_STK_VTARGET, &vtarget); @@ -1175,11 +1207,11 @@ static void stk500_print_parms1(const PROGRAMMER *pgm, const char *p) { stk500_getparm(pgm, Parm_STK_OSC_CMATCH, &osc_cmatch); stk500_getparm(pgm, Parm_STK_SCK_DURATION, &sck_duration); - msg_info("%sVtarget : %.1f V\n", p, vtarget / 10.0); - msg_info("%sVaref : %.1f V\n", p, vadjust / 10.0); - msg_info("%sOscillator : ", p); + fmsg_out(fp, "%sVtarget : %.1f V\n", p, vtarget / 10.0); + fmsg_out(fp, "%sVaref : %.1f V\n", p, vadjust / 10.0); + fmsg_out(fp, "%sOscillator : ", p); if (osc_pscale == 0) - msg_info("Off\n"); + fmsg_out(fp, "Off\n"); else { int prescale = 1; double f = STK500_XTAL / 2; @@ -1203,16 +1235,16 @@ static void stk500_print_parms1(const PROGRAMMER *pgm, const char *p) { unit = "kHz"; } else unit = "Hz"; - msg_info("%.3f %s\n", f, unit); + fmsg_out(fp, "%.3f %s\n", f, unit); } - msg_info("%sSCK period : %.1f us\n", p, sck_duration * 8.0e6 / STK500_XTAL + 0.05); + fmsg_out(fp, "%sSCK period : %.1f us\n", p, sck_duration * 8.0e6 / STK500_XTAL + 0.05); return; } -static void stk500_print_parms(const PROGRAMMER *pgm) { - stk500_print_parms1(pgm, ""); +static void stk500_print_parms(const PROGRAMMER *pgm, FILE *fp) { + stk500_print_parms1(pgm, "", fp); } static void stk500_setup(PROGRAMMER * pgm) diff --git a/src/stk500v2.c b/src/stk500v2.c index 042041a2..edf26cae 100644 --- a/src/stk500v2.c +++ b/src/stk500v2.c @@ -262,7 +262,7 @@ static int stk500v2_setparm(const PROGRAMMER *pgm, unsigned char parm, unsigned static int stk500v2_getparm2(const PROGRAMMER *pgm, unsigned char parm, unsigned int *value); static int stk500v2_setparm2(const PROGRAMMER *pgm, unsigned char parm, unsigned int value); static int stk500v2_setparm_real(const PROGRAMMER *pgm, unsigned char parm, unsigned char value); -static void stk500v2_print_parms1(const PROGRAMMER *pgm, const char *p); +static void stk500v2_print_parms1(const PROGRAMMER *pgm, const char *p, FILE *fp); static int stk500v2_paged_load(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m, unsigned int page_size, unsigned int addr, unsigned int n_bytes); @@ -3075,7 +3075,7 @@ static void stk500v2_display(const PROGRAMMER *pgm, const char *p) { stk500v2_getparm2(pgm, PARAM2_EC_ID_TABLE_REV, &rev); msg_info("%sEC_ID table rev : %d\n", p, rev); } - stk500v2_print_parms1(pgm, p); + stk500v2_print_parms1(pgm, p, stderr); return; } @@ -3095,7 +3095,7 @@ f_to_kHz_MHz(double f, const char **unit) return f; } -static void stk500v2_print_parms1(const PROGRAMMER *pgm, const char *p) { +static void stk500v2_print_parms1(const PROGRAMMER *pgm, const char *p, FILE *fp) { unsigned char vtarget = 0, vadjust = 0, osc_pscale = 0, osc_cmatch = 0, sck_duration =0; //XXX 0 is not correct, check caller unsigned int sck_stk600, clock_conf, dac, oct, varef; unsigned char vtarget_jtag[4]; @@ -3110,8 +3110,7 @@ static void stk500v2_print_parms1(const PROGRAMMER *pgm, const char *p) { pgmcp->cookie = PDATA(pgm)->chained_pdata; jtagmkII_getparm(pgmcp, PAR_OCD_VTARGET, vtarget_jtag); pgm_free(pgmcp); - msg_info("%sVtarget : %.1f V\n", p, - b2_to_u16(vtarget_jtag) / 1000.0); + fmsg_out(fp, "%sVtarget : %.1f V\n", p, b2_to_u16(vtarget_jtag) / 1000.0); } else if (PDATA(pgm)->pgmtype == PGMTYPE_JTAGICE3) { PROGRAMMER *pgmcp = pgm_dup(pgm); pgmcp->cookie = PDATA(pgm)->chained_pdata; @@ -3119,11 +3118,11 @@ static void stk500v2_print_parms1(const PROGRAMMER *pgm, const char *p) { // Copy pgm->id contents over to pgmcp->id for(LNODEID ln=lfirst(pgm->id); ln; ln=lnext(ln)) ladd(pgmcp->id, cfg_strdup("stk500v2_print_parms1()", ldata(ln))); - jtag3_print_parms1(pgmcp, p); + jtag3_print_parms1(pgmcp, p, fp); pgm_free(pgmcp); } else { stk500v2_getparm(pgm, PARAM_VTARGET, &vtarget); - msg_info("%sVtarget : %.1f V\n", p, vtarget / 10.0); + fmsg_out(fp, "%sVtarget : %.1f V\n", p, vtarget / 10.0); } switch (PDATA(pgm)->pgmtype) { @@ -3132,12 +3131,12 @@ static void stk500v2_print_parms1(const PROGRAMMER *pgm, const char *p) { stk500v2_getparm(pgm, PARAM_VADJUST, &vadjust); stk500v2_getparm(pgm, PARAM_OSC_PSCALE, &osc_pscale); stk500v2_getparm(pgm, PARAM_OSC_CMATCH, &osc_cmatch); - msg_info("%sSCK period : %.1f us\n", p, + fmsg_out(fp, "%sSCK period : %.1f us\n", p, stk500v2_sck_to_us(pgm, sck_duration)); - msg_info("%sVaref : %.1f V\n", p, vadjust / 10.0); - msg_info("%sOscillator : ", p); + fmsg_out(fp, "%sVaref : %.1f V\n", p, vadjust / 10.0); + fmsg_out(fp, "%sOscillator : ", p); if (osc_pscale == 0) - msg_info("Off\n"); + fmsg_out(fp, "Off\n"); else { prescale = 1; f = STK500V2_XTAL / 2; @@ -3153,14 +3152,14 @@ static void stk500v2_print_parms1(const PROGRAMMER *pgm, const char *p) { f /= prescale; f /= (osc_cmatch + 1); f = f_to_kHz_MHz(f, &unit); - msg_info("%.3f %s\n", f, unit); + fmsg_out(fp, "%.3f %s\n", f, unit); } break; case PGMTYPE_AVRISP_MKII: case PGMTYPE_JTAGICE_MKII: stk500v2_getparm(pgm, PARAM_SCK_DURATION, &sck_duration); - msg_info("%sSCK period : %.2f us\n", p, + fmsg_out(fp, "%sSCK period : %.2f us\n", p, (float) 1000000 / avrispmkIIfreqs[sck_duration]); break; @@ -3172,7 +3171,7 @@ static void stk500v2_print_parms1(const PROGRAMMER *pgm, const char *p) { if (stk500v2_jtag3_send(pgm, cmd, 1) >= 0 && stk500v2_jtag3_recv(pgm, cmd, 4) >= 2) { unsigned int sck = cmd[1] | (cmd[2] << 8); - msg_info("%sSCK period : %.2f us\n", p, + fmsg_out(fp, "%sSCK period : %.2f us\n", p, (float)(1E6 / (1000.0 * sck))); } } @@ -3180,23 +3179,23 @@ static void stk500v2_print_parms1(const PROGRAMMER *pgm, const char *p) { case PGMTYPE_STK600: stk500v2_getparm2(pgm, PARAM2_AREF0, &varef); - msg_info("%sVaref 0 : %.2f V\n", p, varef / 100.0); + fmsg_out(fp, "%sVaref 0 : %.2f V\n", p, varef / 100.0); stk500v2_getparm2(pgm, PARAM2_AREF1, &varef); - msg_info("%sVaref 1 : %.2f V\n", p, varef / 100.0); + fmsg_out(fp, "%sVaref 1 : %.2f V\n", p, varef / 100.0); stk500v2_getparm2(pgm, PARAM2_SCK_DURATION, &sck_stk600); - msg_info("%sSCK period : %.2f us\n", p, + fmsg_out(fp, "%sSCK period : %.2f us\n", p, (float) (sck_stk600 + 1) / 8.0); stk500v2_getparm2(pgm, PARAM2_CLOCK_CONF, &clock_conf); oct = (clock_conf & 0xf000) >> 12u; dac = (clock_conf & 0x0ffc) >> 2u; f = pow(2, (double)oct) * 2078.0 / (2 - (double)dac / 1024.0); f = f_to_kHz_MHz(f, &unit); - msg_info("%sOscillator : %.3f %s\n", + fmsg_out(fp, "%sOscillator : %.3f %s\n", p, f, unit); break; default: - msg_info("%sSCK period : %.1f us\n", p, + fmsg_out(fp, "%sSCK period : %.1f us\n", p, sck_duration * 8.0e6 / STK500V2_XTAL + 0.05); break; } @@ -3205,8 +3204,8 @@ static void stk500v2_print_parms1(const PROGRAMMER *pgm, const char *p) { } -static void stk500v2_print_parms(const PROGRAMMER *pgm) { - stk500v2_print_parms1(pgm, ""); +static void stk500v2_print_parms(const PROGRAMMER *pgm, FILE *fp) { + stk500v2_print_parms1(pgm, "", fp); } static int stk500v2_perform_osccal(const PROGRAMMER *pgm) { diff --git a/src/term.c b/src/term.c index 321722f7..cd0cdc16 100644 --- a/src/term.c +++ b/src/term.c @@ -33,10 +33,21 @@ #include #if defined(HAVE_LIBREADLINE) -# include -# include +#include +#include + +#ifdef _MSC_VER +#include "msvc/unistd.h" +#else +#include #endif +#ifdef WIN32 +#include +#endif +#endif + + #include "avrdude.h" #include "term.h" @@ -114,7 +125,7 @@ static int nexttok(char *buf, char **tok, char **next) { n = q; uint8_t quotes = 0; while (*n && (!isspace(*n) || quotes)) { - // poor man's quote and escape processing + // Poor man's quote and escape processing if (*n == '"' || *n == '\'') quotes++; else if(*n == '\\' && n[1]) @@ -173,7 +184,7 @@ static int chardump_line(char *buffer, unsigned char *p, int n, int pad) { int i; unsigned char b[128]; - // sanity check + // Sanity check n = n < 1? 1: n > sizeof b? sizeof b: n; memcpy(b, p, n); @@ -202,7 +213,7 @@ static int hexdump_buf(FILE *f, int startaddr, unsigned char *buf, int len) { n = len; hexdump_line(dst1, p, n, 48); chardump_line(dst2, p, n, 16); - fprintf(f, "%04x %s |%s|\n", addr, dst1, dst2); + term_out("%04x %s |%s|\n", addr, dst1, dst2); len -= n; addr += n; p += n; @@ -214,7 +225,7 @@ static int hexdump_buf(FILE *f, int startaddr, unsigned char *buf, int len) { static int cmd_dump(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { if (argc < 2 || argc > 4) { - terminal_message(MSG_INFO, + msg_error( "Usage: %s \n" " %s ...\n" " %s \n" @@ -229,8 +240,7 @@ static int cmd_dump(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { char *memtype = argv[1]; AVRMEM *mem = avr_locate_mem(p, memtype); if (mem == NULL) { - terminal_message(MSG_INFO, "%s (dump): %s memory type not defined for part %s\n", - progname, memtype, p->desc); + pmsg_error("(dump) %s memory type not defined for part %s\n", memtype, p->desc); return -1; } int maxsize = mem->size; @@ -242,12 +252,10 @@ static int cmd_dump(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { if (argc >= 3 && strcmp(argv[2], "...") != 0) { addr = strtoul(argv[2], &end_ptr, 0); if (*end_ptr || (end_ptr == argv[2])) { - terminal_message(MSG_INFO, "%s (dump): can't parse address %s\n", - progname, argv[2]); + pmsg_error("(dump) cannot parse address %s\n", argv[2]); return -1; } else if (addr < 0 || addr >= maxsize) { - terminal_message(MSG_INFO, "%s (dump): %s address 0x%05x is out of range [0, 0x%05x]\n", - progname, mem->desc, addr, maxsize-1); + pmsg_error("(dump) %s address 0x%05x is out of range [0, 0x%05x]\n", mem->desc, addr, maxsize-1); return -1; } } @@ -263,8 +271,7 @@ static int cmd_dump(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { } else if (argc == 4) { len = strtol(argv[3], &end_ptr, 0); if (*end_ptr || (end_ptr == argv[3])) { - terminal_message(MSG_INFO, "%s (dump): can't parse length %s\n", - progname, argv[3]); + pmsg_error("(dump) cannot parse length %s\n", argv[3]); return -1; } } else { @@ -288,7 +295,7 @@ static int cmd_dump(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { uint8_t *buf = malloc(len); if (buf == NULL) { - terminal_message(MSG_INFO, "%s (dump): out of memory\n", progname); + pmsg_error("(dump) out of memory\n"); return -1; } @@ -297,11 +304,9 @@ static int cmd_dump(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { int rc = pgm->read_byte_cached(pgm, p, mem, addr + i, &buf[i]); if (rc != 0) { report_progress(1, -1, NULL); - terminal_message(MSG_INFO, "%s (dump): error reading %s address 0x%05lx of part %s\n", - progname, mem->desc, (long) addr + i, p->desc); + pmsg_error("(dump) error reading %s address 0x%05lx of part %s\n", mem->desc, (long) addr + i, p->desc); if (rc == -1) - terminal_message(MSG_INFO, "%*sread operation not supported on memory type %s\n", - (int) strlen(progname)+9, "", mem->desc); + imsg_error("%*sread operation not supported on memory type %s\n", 7, "", mem->desc); return -1; } report_progress(i, len, NULL); @@ -309,7 +314,7 @@ static int cmd_dump(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { report_progress(1, 1, NULL); hexdump_buf(stdout, addr, buf, len); - fprintf(stdout, "\n"); + term_out("\n"); free(buf); @@ -365,7 +370,7 @@ static int is_mantissa_only(char *p) { static int cmd_write(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { if (argc < 4) { - terminal_message(MSG_INFO, + msg_error( "Usage: write [,] {[,]}\n" " write [,] {[,]} ...\n" "\n" @@ -399,14 +404,13 @@ static int cmd_write(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { } int i; - uint8_t write_mode; // Operation mode, "standard" or "fill" - uint8_t start_offset; // Which argc argument - int len; // Number of bytes to write to memory - char *memtype = argv[1]; // Memory name string + uint8_t write_mode; // Operation mode, "standard" or "fill" + uint8_t start_offset; // Which argc argument + int len; // Number of bytes to write to memory + char *memtype = argv[1]; // Memory name string AVRMEM *mem = avr_locate_mem(p, memtype); if (mem == NULL) { - terminal_message(MSG_INFO, "%s (write): %s memory type not defined for part %s\n", - progname, memtype, p->desc); + pmsg_error("(write) %s memory type not defined for part %s\n", memtype, p->desc); return -1; } int maxsize = mem->size; @@ -414,21 +418,19 @@ static int cmd_write(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { char *end_ptr; int addr = strtoul(argv[2], &end_ptr, 0); if (*end_ptr || (end_ptr == argv[2])) { - terminal_message(MSG_INFO, "%s (write): can't parse address %s\n", - progname, argv[2]); + pmsg_error("(write) cannot parse address %s\n", argv[2]); return -1; } if (addr < 0 || addr >= maxsize) { - terminal_message(MSG_INFO, "%s (write): %s address 0x%05x is out of range [0, 0x%05x]\n", - progname, mem->desc, addr, maxsize-1); + pmsg_error("(write) %s address 0x%05x is out of range [0, 0x%05x]\n", mem->desc, addr, maxsize-1); return -1; } // Allocate a buffer guaranteed to be large enough uint8_t *buf = calloc(mem->size + 8 + maxstrlen(argc-3, argv+3)+1, sizeof(uint8_t)); if (buf == NULL) { - terminal_message(MSG_INFO, "%s (write): out of memory\n", progname); + pmsg_error("(write) out of memory\n"); return -1; } @@ -438,8 +440,7 @@ static int cmd_write(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { start_offset = 4; len = strtoul(argv[3], &end_ptr, 0); if (*end_ptr || (end_ptr == argv[3])) { - terminal_message(MSG_INFO, "%s (write ...): can't parse length %s\n", - progname, argv[3]); + pmsg_error("(write ...) cannot parse length %s\n", argv[3]); free(buf); return -1; } @@ -471,8 +472,8 @@ static int cmd_write(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { }; if(sizeof(long long) != sizeof(int64_t) || (data.a[0]^data.a[7]) != 1) - terminal_message(MSG_INFO, "%s (write): assumption on data types not met? " - "Check source and recompile\n", progname); + pmsg_error("(write) assumption on data types not met? " + "Check source and recompile\n"); bool is_big_endian = data.a[7]; for (i = start_offset; i < len + start_offset; i++) { @@ -518,7 +519,7 @@ static int cmd_write(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { bool is_out_of_range = 0; int nhexdigs = p-argi-2; - if(is_signed) { // Is input in range for int64_t? + if(is_signed) { // Is input in range for int64_t? errno = 0; (void) strtoll(argi, NULL, 0); is_outside_int64_t = errno == ERANGE; } @@ -566,9 +567,8 @@ static int cmd_write(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { } if(is_outside_int64_t || is_out_of_range) - terminal_message(MSG_INFO, "%s (write): %s out of int%d_t range, " - "interpreted as %d-byte %lld; consider 'U' suffix\n", - progname, argi, data.size*8, data.size, data.ll); + pmsg_error("(write) %s out of int%d_t range, " + "interpreted as %d-byte %lld; consider 'U' suffix\n", argi, data.size*8, data.size, (long long int) data.ll); } } } @@ -583,8 +583,8 @@ static int cmd_write(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { data.f = strtof(argi, &end_ptr); if (end_ptr != argi && toupper(*end_ptr) == 'F' && end_ptr[1] == 0) data.size = 4; - if (end_ptr != argi && *end_ptr == 0) // no suffix defaults to float but ... - // ... do not accept valid mantissa-only floats that are integer rejects (eg, 078 or ULL overflows) + if (end_ptr != argi && *end_ptr == 0) // No suffix defaults to float but ... + // ... do not accept valid mantissa-only floats that are integer rejects (eg, 078 or ULL overflows) if (!is_mantissa_only(argi)) data.size = 4; } @@ -593,29 +593,27 @@ static int cmd_write(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { if ((*argi == '\'' && argi[arglen-1] == '\'') || (*argi == '\"' && argi[arglen-1] == '\"')) { char *s = calloc(arglen-1, 1); if (s == NULL) { - terminal_message(MSG_INFO, "%s (write str): out of memory\n", progname); + pmsg_error("(write str) out of memory\n"); free(buf); return -1; } // Strip start and end quotes, and unescape C string strncpy(s, argi+1, arglen-2); cfg_unescape(s, s); - if (*argi == '\'') { // Single C-style character + if (*argi == '\'') { // Single C-style character if(*s && s[1]) - terminal_message(MSG_INFO, "%s (write): only using first character of %s\n", - progname, argi); + pmsg_error("(write) only using first character of %s\n", argi); data.ll = *s; data.size = 1; free(s); - } else { // C-style string + } else { // C-style string data.str_ptr = s; } } } if(!data.size && !data.str_ptr) { - terminal_message(MSG_INFO, "%s (write): can't parse data %s\n", - progname, argi); + pmsg_error("(write) cannot parse data %s\n", argi); free(buf); return -1; } @@ -644,8 +642,8 @@ static int cmd_write(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { data.bytes_grown = 0; if ((addr + len + data.bytes_grown) > maxsize) { - terminal_message(MSG_INFO, "%s (write): selected address and # bytes exceed " - "range for %s memory\n", progname, memtype); + pmsg_error("(write) selected address and # bytes exceed " + "range for %s memory\n", memtype); free(buf); return -1; } @@ -653,11 +651,11 @@ static int cmd_write(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { if(data.str_ptr) free(data.str_ptr); - terminal_message(MSG_NOTICE, "Info: writing %d bytes starting from address 0x%02lx", + pmsg_notice2("(write) writing %d bytes starting from address 0x%02lx", len + data.bytes_grown, (long) addr); if (write_mode == WRITE_MODE_FILL) - terminal_message(MSG_NOTICE, "; remaining space filled with %s", argv[argc - 2]); - terminal_message(MSG_NOTICE, "\n"); + msg_notice2("; remaining space filled with %s", argv[argc - 2]); + msg_notice2("\n"); pgm->err_led(pgm, OFF); bool werror = false; @@ -665,19 +663,16 @@ static int cmd_write(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { for (i = 0; i < len + data.bytes_grown; i++) { int rc = pgm->write_byte_cached(pgm, p, mem, addr+i, buf[i]); if (rc) { - terminal_message(MSG_INFO, "%s (write): error writing 0x%02x at 0x%05lx, rc=%d\n", - progname, buf[i], (long) addr+i, (int) rc); + pmsg_error("(write) error writing 0x%02x at 0x%05lx, rc=%d\n", buf[i], (long) addr+i, (int) rc); if (rc == -1) - terminal_message(MSG_INFO, "%*swrite operation not supported on memory type %s\n", - (int) strlen(progname)+10, "", mem->desc); + imsg_error("%*swrite operation not supported on memory type %s\n", 8, "", mem->desc); werror = true; } uint8_t b; rc = pgm->read_byte_cached(pgm, p, mem, addr+i, &b); if (b != buf[i]) { - terminal_message(MSG_INFO, "%s (write): error writing 0x%02x at 0x%05lx cell=0x%02x\n", - progname, buf[i], (long) addr+i, b); + pmsg_error("(write) error writing 0x%02x at 0x%05lx cell=0x%02x\n", buf[i], (long) addr+i, b); werror = true; } @@ -713,14 +708,13 @@ static int cmd_send(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { int len; if (spi_mode && (pgm->spi == NULL)) { - terminal_message(MSG_INFO, "%s (send): the %s programmer does not support direct SPI transfers\n", - progname, pgm->type); + pmsg_error("(send) the %s programmer does not support direct SPI transfers\n", pgm->type); return -1; } if ((argc > 5) || ((argc < 5) && (!spi_mode))) { - terminal_message(MSG_INFO, spi_mode? + msg_error(spi_mode? "Usage: send [ [ []]]\n": "Usage: send \n"); return -1; @@ -733,8 +727,7 @@ static int cmd_send(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { for (i=1; ichip_erase_cached(pgm, p); @@ -771,20 +762,18 @@ static int cmd_erase(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { static int cmd_pgerase(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { if(argc < 3) { - terminal_message(MSG_INFO, "Usage: pgerase \n"); + msg_error("Usage: pgerase \n"); return -1; } char *memtype = argv[1]; AVRMEM *mem = avr_locate_mem(p, memtype); if(!mem) { - terminal_message(MSG_INFO, "%s (pgerase): %s memory type not defined for part %s\n", - progname, memtype, p->desc); + pmsg_error("(pgerase) %s memory type not defined for part %s\n", memtype, p->desc); return -1; } if(!avr_has_paged_access(pgm, mem)) { - terminal_message(MSG_INFO, "%s (pgerase): %s memory cannot be paged addressed by %s\n", - progname, memtype, ldata(lfirst(pgm->id))); + pmsg_error("(pgerase) %s memory cannot be paged addressed by %s\n", memtype, (char *) ldata(lfirst(pgm->id))); return -1; } @@ -793,21 +782,17 @@ static int cmd_pgerase(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { char *end_ptr; int addr = strtoul(argv[2], &end_ptr, 0); if(*end_ptr || (end_ptr == argv[2])) { - terminal_message(MSG_INFO, "%s (pgerase): can't parse address %s\n", - progname, argv[2]); + pmsg_error("(pgerase) cannot parse address %s\n", argv[2]); return -1; } if (addr < 0 || addr >= maxsize) { - terminal_message(MSG_INFO, "%s (pgerase): %s address 0x%05x is out of range [0, 0x%05x]\n", - progname, mem->desc, addr, maxsize-1); + pmsg_error("(pgerase) %s address 0x%05x is out of range [0, 0x%05x]\n", mem->desc, addr, maxsize-1); return -1; } - // terminal_message(MSG_INFO, "%s: %s page erase 0x%05x\n", progname, mem->desc, addr & ~(mem->page_size-1)); if(pgm->page_erase_cached(pgm, p, mem, (unsigned int) addr) < 0) { - terminal_message(MSG_INFO, "%s (pgerase): unable to erase %s page at 0x%05x\n", - progname, mem->desc, addr); + pmsg_error("(pgerase) unable to erase %s page at 0x%05x\n", mem->desc, addr); return -1; } @@ -816,9 +801,9 @@ static int cmd_pgerase(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { static int cmd_part(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { - fprintf(stdout, "\n"); + term_out("\n"); avr_display(stdout, p, "", 0); - fprintf(stdout, "\n"); + term_out("\n"); return 0; } @@ -831,20 +816,18 @@ static int cmd_sig(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { rc = avr_signature(pgm, p); if (rc != 0) { - terminal_message(MSG_INFO, "%s (sig): error reading signature data, rc=%d\n", - progname, rc); + pmsg_error("(sig) error reading signature data, rc=%d\n", rc); } m = avr_locate_mem(p, "signature"); if (m == NULL) { - terminal_message(MSG_INFO, "%s (sig): signature data not defined for device %s\n", - progname, p->desc); + pmsg_error("(sig) signature data not defined for device %s\n", p->desc); } else { - fprintf(stdout, "Device signature = 0x"); + term_out("Device signature = 0x"); for (i=0; isize; i++) - fprintf(stdout, "%02x", m->buf[i]); - fprintf(stdout, "\n\n"); + term_out("%02x", m->buf[i]); + term_out("\n\n"); } return 0; @@ -861,8 +844,8 @@ static int cmd_quit(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { static int cmd_parms(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { - pgm->print_parms(pgm); - terminal_message(MSG_INFO, "\n"); + pgm->print_parms(pgm, stdout); + term_out("\n"); return 0; } @@ -873,18 +856,16 @@ static int cmd_vtarg(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { char *endp; if (argc != 2) { - terminal_message(MSG_INFO, "Usage: vtarg \n"); + msg_error("Usage: vtarg \n"); return -1; } v = strtod(argv[1], &endp); if (endp == argv[1]) { - terminal_message(MSG_INFO, "%s (vtarg): can't parse voltage %s\n", - progname, argv[1]); + pmsg_error("(vtarg) cannot parse voltage %s\n", argv[1]); return -1; } if ((rc = pgm->set_vtarget(pgm, v)) != 0) { - terminal_message(MSG_INFO, "%s (vtarg): unable to set V[target] (rc = %d)\n", - progname, rc); + pmsg_error("(vtarg) unable to set V[target] (rc = %d)\n", rc); return -3; } return 0; @@ -897,7 +878,7 @@ static int cmd_fosc(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { char *endp; if (argc != 2) { - terminal_message(MSG_INFO, "Usage: fosc [M|k] | off\n"); + msg_error("Usage: fosc [M|k] | off\n"); return -1; } v = strtod(argv[1], &endp); @@ -905,8 +886,7 @@ static int cmd_fosc(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { if (strcmp(argv[1], "off") == 0) v = 0.0; else { - terminal_message(MSG_INFO, "%s (fosc): can't parse frequency %s\n", - progname, argv[1]); + pmsg_error("(fosc) cannot parse frequency %s\n", argv[1]); return -1; } } @@ -915,8 +895,7 @@ static int cmd_fosc(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { else if (*endp == 'k' || *endp == 'K') v *= 1e3; if ((rc = pgm->set_fosc(pgm, v)) != 0) { - terminal_message(MSG_INFO, "%s (fosc): unable to set oscillator frequency (rc = %d)\n", - progname, rc); + pmsg_error("(fosc) unable to set oscillator frequency (rc = %d)\n", rc); return -3; } return 0; @@ -929,19 +908,17 @@ static int cmd_sck(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { char *endp; if (argc != 2) { - terminal_message(MSG_INFO, "Usage: sck \n"); + msg_error("Usage: sck \n"); return -1; } v = strtod(argv[1], &endp); if (endp == argv[1]) { - terminal_message(MSG_INFO, "%s (sck): can't parse period %s\n", - progname, argv[1]); + pmsg_error("(sck) cannot parse period %s\n", argv[1]); return -1; } - v *= 1e-6; /* Convert from microseconds to seconds. */ + v *= 1e-6; // Convert from microseconds to seconds if ((rc = pgm->set_sck_period(pgm, v)) != 0) { - terminal_message(MSG_INFO, "%s (sck): unable to set SCK period (rc = %d)\n", - progname, rc); + pmsg_error("(sck) unable to set SCK period (rc = %d)\n", rc); return -3; } return 0; @@ -955,34 +932,30 @@ static int cmd_varef(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { char *endp; if (argc != 2 && argc != 3) { - terminal_message(MSG_INFO, "Usage: varef [channel] \n"); + msg_error("Usage: varef [channel] \n"); return -1; } if (argc == 2) { chan = 0; v = strtod(argv[1], &endp); if (endp == argv[1]) { - terminal_message(MSG_INFO, "%s (varef): can't parse voltage %s\n", - progname, argv[1]); + pmsg_error("(varef) cannot parse voltage %s\n", argv[1]); return -1; } } else { chan = strtoul(argv[1], &endp, 10); if (endp == argv[1]) { - terminal_message(MSG_INFO, "%s (varef): can't parse channel %s\n", - progname, argv[1]); + pmsg_error("(varef) cannot parse channel %s\n", argv[1]); return -1; } v = strtod(argv[2], &endp); if (endp == argv[2]) { - terminal_message(MSG_INFO, "%s (varef): can't parse voltage %s\n", - progname, argv[2]); + pmsg_error("(varef) cannot parse voltage %s\n", argv[2]); return -1; } } if ((rc = pgm->set_varef(pgm, chan, v)) != 0) { - terminal_message(MSG_INFO, "%s (varef): unable to set V[aref] (rc = %d)\n", - progname, rc); + pmsg_error("(varef) unable to set V[aref] (rc = %d)\n", rc); return -3; } return 0; @@ -992,19 +965,19 @@ static int cmd_varef(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { static int cmd_help(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { int i; - fprintf(stdout, "Valid commands:\n"); + term_out("Valid commands:\n"); for (i=0; i]\n"); + msg_error("Usage: verbose []\n"); return -1; } if (argc == 1) { - terminal_message(MSG_INFO, "Verbosity level: %d\n", verbose); + msg_error("Verbosity level: %d\n", verbose); return 0; } nverb = strtol(argv[1], &endp, 0); if (endp == argv[1] || *endp) { - terminal_message(MSG_INFO, "%s (verbose): can't parse verbosity level %s\n", - progname, argv[1]); + pmsg_error("(verbose) cannot parse verbosity level %s\n", argv[1]); return -1; } if (nverb < 0) { - terminal_message(MSG_INFO, "%s: verbosity level must not be negative: %d\n", - progname, nverb); + pmsg_error("(verbose) level must not be negative: %d\n", nverb); return -1; } verbose = nverb; - terminal_message(MSG_INFO, "New verbosity level: %d\n", verbose); + term_out("New verbosity level: %d\n", verbose); return 0; } @@ -1055,26 +1026,24 @@ static int cmd_quell(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { char *endp; if (argc != 1 && argc != 2) { - terminal_message(MSG_INFO, "Usage: quell []\n"); + msg_error("Usage: quell []\n"); return -1; } if (argc == 1) { - terminal_message(MSG_INFO, "Quell level: %d\n", quell_progress); + msg_error("Quell level: %d\n", quell_progress); return 0; } nquell = strtol(argv[1], &endp, 0); if (endp == argv[1] || *endp) { - terminal_message(MSG_INFO, "%s (quell): can't parse quell level %s\n", - progname, argv[1]); + pmsg_error("(quell) cannot parse quell level %s\n", argv[1]); return -1; } if (nquell < 0) { - terminal_message(MSG_INFO, "%s: quell level must not be negative: %d\n", - progname, nquell); + pmsg_error("(quell) level must not be negative: %d\n", nquell); return -1; } quell_progress = nquell; - terminal_message(MSG_INFO, "New quell level: %d\n", quell_progress); + term_out("New quell level: %d\n", quell_progress); if(quell_progress > 0) update_progress = NULL; @@ -1195,8 +1164,7 @@ static int do_cmd(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { return cmd[i].func(pgm, p, argc, argv); if (len && strncasecmp(argv[0], cmd[i].name, len)==0) { if (hold != -1) { - terminal_message(MSG_INFO, "%s (cmd): command %s is ambiguous\n", - progname, argv[0]); + pmsg_error("(cmd) command %s is ambiguous\n", argv[0]); return -1; } hold = i; @@ -1206,104 +1174,177 @@ static int do_cmd(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { if (hold != -1) return cmd[hold].func(pgm, p, argc, argv); - terminal_message(MSG_INFO, "%s (cmd): invalid command %s\n", - progname, argv[0]); + pmsg_error("(cmd) invalid command %s\n", argv[0]); return -1; } char *terminal_get_input(const char *prompt) { -#if defined(HAVE_LIBREADLINE) && !defined(WIN32) - char *input; - input = readline(prompt); - if ((input != NULL) && (strlen(input) >= 1)) - add_history(input); - - return input; -#else char input[256]; - fprintf(stdout, "%s", prompt); - if (fgets(input, sizeof(input), stdin)) - { - /* FIXME: readline strips the '\n', should this too? */ - return strdup(input); + + term_out("%s", prompt); + if(fgets(input, sizeof(input), stdin)) { + int len = strlen(input); + if(len > 0 && input[len-1] == '\n') + input[len-1] = 0; + return cfg_strdup(__func__, input); } - else - return NULL; -#endif + + return NULL; } -int terminal_mode(PROGRAMMER *pgm, AVRPART *p) { - char *cmdbuf; - char *q; - int rc; - int argc; - char **argv; +static int process_line(char *cmdbuf, PROGRAMMER *pgm, struct avrpart *p) { + int argc, rc; + char **argv = NULL, *q; - rc = 0; - while ((cmdbuf = terminal_get_input("avrdude> ")) != NULL) { - /* - * find the start of the command, skipping any white space - */ - q = cmdbuf; - while (*q && isspace((unsigned char) *q)) - q++; + // Find the start of the command, skipping any white space + q = cmdbuf; + while(*q && isspace((unsigned char) *q)) + q++; - /* skip blank lines and comments */ - if (!*q || (*q == '#')) - continue; + // Skip blank lines and comments + if (!*q || (*q == '#')) + return 0; - /* tokenize command line */ - argc = tokenize(q, &argv); - if (argc < 0) { - free(cmdbuf); - return argc; - } + // Tokenize command line + argc = tokenize(q, &argv); + + if(!argv) + return -1; #if !defined(HAVE_LIBREADLINE) || defined(WIN32) || defined(__APPLE__) - fprintf(stdout, ">>> "); + term_out(">>> "); for (int i=0; i 0) { - rc = 0; - break; + // Run the command + rc = do_cmd(pgm, p, argc, argv); + free(argv); + + return rc; +} + + + +#if defined(HAVE_LIBREADLINE) + +static PROGRAMMER *term_pgm; +static struct avrpart *term_p; + +static int term_running; + +// Any character in standard input available (without sleeping)? +static int readytoread() { +#ifdef WIN32 + HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE); + + while(1) { + INPUT_RECORD input[1] = { 0 }; + DWORD dwNumberOfEventsRead = 0; + + if(!PeekConsoleInputA(hStdin, input, ARRAYSIZE(input), &dwNumberOfEventsRead)) { + DWORD dwError = GetLastError(); + + // Stdin redirected from a pipe or file (FIXME: reading from a pipe may sleep) + if(dwError == ERROR_INVALID_HANDLE) + return 1; + + pmsg_warning("PeekConsoleInputA() failed with error code %u\n", (unsigned int) dwError); + return -1; + } + + if(dwNumberOfEventsRead <= 0) // Nothing in the input buffer + return 0; + + // Filter out all the events that readline does not handle ... + if((input[0].EventType & KEY_EVENT) != 0 && input[0].Event.KeyEvent.bKeyDown) + return 1; + + // Drain other events not handled by readline + if(!ReadConsoleInputA(hStdin, input, ARRAYSIZE(input), &dwNumberOfEventsRead)) { + pmsg_warning("ReadConsoleInputA() failed with error code %u\n", (unsigned int) GetLastError()); + return -1; } - free(cmdbuf); } +#else + struct timeval tv = { 0L, 0L }; + fd_set fds; + FD_ZERO(&fds); + FD_SET(0, &fds); - pgm->flush_cache(pgm, p); + return select(1, &fds, NULL, NULL, &tv) > 0; +#endif +} - return rc; +// Callback processes commands whenever readline() has finished +void term_gotline(char *cmdstr) { + if(cmdstr) { + if(*cmdstr) { + add_history(cmdstr); + // only quit/abort returns a value > 0 + if(process_line(cmdstr, term_pgm, term_p) > 0) + term_running = 0; + } + free(cmdstr); + } else { + // call quit at end of file or terminal ^D + term_out("\n"); + cmd_quit(term_pgm, term_p, 0, NULL); + term_running = 0; + } } -int terminal_message(const int msglvl, const char *format, ...) { +int terminal_mode(PROGRAMMER *pgm, struct avrpart *p) { + term_pgm = pgm; // For callback routine + term_p = p; + + rl_callback_handler_install("avrdude> ", term_gotline); + + term_running = 1; + for(int n=1; term_running; n++) { + if(n%16 == 0) { // Every 100 ms (16*6.25 us) reset bootloader watchdog timer + if(pgm->term_keep_alive) + pgm->term_keep_alive(pgm, NULL); + } + usleep(6250); + if(readytoread() > 0 && term_running) + rl_callback_read_char(); + } + + rl_callback_handler_remove(); + + return pgm->flush_cache(pgm, p); +} + +#else + + +int terminal_mode(PROGRAMMER *pgm, struct avrpart *p) { + char *cmdbuf; int rc = 0; - va_list ap; - fflush(stdout); fflush(stderr); - if (verbose >= msglvl) { - va_start(ap, format); - rc = vfprintf(stderr, format, ap); - va_end(ap); + while((cmdbuf = terminal_get_input("avrdude> "))) { + int rc = process_line(cmdbuf, pgm, p); + free(cmdbuf); + if(rc > 0) + break; } - fflush(stderr); - return rc; + if(rc <= 0) + cmd_quit(pgm, p, 0, NULL); + return pgm->flush_cache(pgm, p); } +#endif static void update_progress_tty(int percent, double etime, const char *hdr, int finish) { static char *header; - static int last, done; + static int last, done = 1; int i; setvbuf(stderr, (char *) NULL, _IONBF, 0); @@ -1330,7 +1371,7 @@ static void update_progress_tty(int percent, double etime, const char *hdr, int hashes[i/2] = '#'; hashes[50] = 0; - msg_info("\r%s | %s | %d%% %0.2fs", header, hashes, showperc, etime); + msg_info("\r%s | %s | %d%% %0.2f s ", header, hashes, showperc, etime); if(percent == 100) { if(finish) msg_info("\n\n"); @@ -1343,7 +1384,7 @@ static void update_progress_tty(int percent, double etime, const char *hdr, int } static void update_progress_no_tty(int percent, double etime, const char *hdr, int finish) { - static int last, done; + static int last, done = 1; setvbuf(stderr, (char *) NULL, _IONBF, 0); diff --git a/src/term.h b/src/term.h index a89927ea..61c4916c 100644 --- a/src/term.h +++ b/src/term.h @@ -35,7 +35,6 @@ typedef enum { int terminal_mode(PROGRAMMER * pgm, struct avrpart * p); char * terminal_get_input(const char *prompt); void terminal_setup_update_progress(); -int terminal_message(const int msglvl, const char *format, ...); #ifdef __cplusplus } diff --git a/src/update.c b/src/update.c index e1a272c6..13580536 100644 --- a/src/update.c +++ b/src/update.c @@ -335,11 +335,11 @@ int update_is_readable(const char *fn) { static void ioerror(const char *iotype, UPDATE *upd) { int errnocp = errno; - pmsg_ext_error("file %s is not %s", update_outname(upd->filename), iotype); + pmsg_ext_error("file %s is not %s: ", update_outname(upd->filename), iotype); if(errnocp) - msg_ext_error("memstats(): %s", strerror(errnocp)); + msg_ext_error("%s", strerror(errnocp)); else if(upd->filename && *upd->filename) - msg_ext_error(" (not a regular or character file?)"); + msg_ext_error("(not a regular or character file?)"); msg_ext_error("\n"); } @@ -456,7 +456,8 @@ int do_op(PROGRAMMER * pgm, struct avrpart * p, UPDATE * upd, enum updateflags f } pmsg_info("reading %s%s memory ...\n", mem->desc, alias_mem_desc); - report_progress(0, 1, "Reading"); + if(mem->size > 32 || verbose > 1) + report_progress(0, 1, "Reading"); rc = avr_read(pgm, p, upd->memtype, 0); report_progress(1, 1, NULL); @@ -511,7 +512,8 @@ int do_op(PROGRAMMER * pgm, struct avrpart * p, UPDATE * upd, enum updateflags f update_plural(fs.nbytes), mem->desc, alias_mem_desc); if (!(flags & UF_NOWRITE)) { - report_progress(0, 1, "Writing"); + if(mem->size > 32 || verbose > 1) + report_progress(0, 1, "Writing"); rc = avr_write(pgm, p, upd->memtype, size, (flags & UF_AUTO_ERASE) != 0); report_progress(1, 1, NULL); } else { @@ -569,7 +571,8 @@ int do_op(PROGRAMMER * pgm, struct avrpart * p, UPDATE * upd, enum updateflags f pmsg_notice2("reading on-chip %s%s data ...\n", mem->desc, alias_mem_desc); } - report_progress (0,1,"Reading"); + if(mem->size > 32 || verbose > 1) + report_progress (0,1,"Reading"); rc = avr_read(pgm, p, upd->memtype, v); report_progress (1,1,NULL); if (rc < 0) { diff --git a/src/usb_hidapi.c b/src/usb_hidapi.c index b6dc3d33..c9fa258e 100644 --- a/src/usb_hidapi.c +++ b/src/usb_hidapi.c @@ -65,78 +65,70 @@ static int usbhid_open(const char *port, union pinfo pinfo, union filedescriptor * right-to-left, so only the least significant nibbles need to be * specified. */ - if ((serno = strchr(port, ':')) != NULL) - { - /* first, drop all colons there if any */ - cp2 = ++serno; + if ((serno = strchr(port, ':')) != NULL) { + /* First, drop all colons there if any */ + cp2 = ++serno; - while ((cp2 = strchr(cp2, ':')) != NULL) - { - x = strlen(cp2) - 1; - memmove(cp2, cp2 + 1, x); - cp2[x] = '\0'; - } + while ((cp2 = strchr(cp2, ':')) != NULL) { + x = strlen(cp2) - 1; + memmove(cp2, cp2 + 1, x); + cp2[x] = '\0'; + } - if (strlen(serno) > 12) - { - pmsg_error("invalid serial number %s\n", serno); - return -1; - } + if (strlen(serno) > 12) { + pmsg_error("invalid serial number %s\n", serno); + return -1; + } - wchar_t wserno[15]; - mbstowcs(wserno, serno, 15); - size_t serlen = strlen(serno); + wchar_t wserno[15]; + mbstowcs(wserno, serno, 15); + size_t serlen = strlen(serno); - /* - * Now, try finding all devices matching VID:PID, and compare - * their serial numbers against the requested one. - */ - struct hid_device_info *list, *walk; - list = hid_enumerate(pinfo.usbinfo.vid, pinfo.usbinfo.pid); - if (list == NULL) - return -1; + /* + * Now, try finding all devices matching VID:PID, and compare + * their serial numbers against the requested one. + */ + struct hid_device_info *list, *walk; + list = hid_enumerate(pinfo.usbinfo.vid, pinfo.usbinfo.pid); + if (list == NULL) { + pmsg_error("No USB HID devices found\n"); + return -1; + } - walk = list; - while (walk) + walk = list; + while (walk) { + pmsg_notice("usbhid_open(): found %ls, serno: %ls\n", walk->product_string, walk->serial_number); + size_t slen = wcslen(walk->serial_number); + if (slen >= serlen && wcscmp(walk->serial_number + slen - serlen, wserno) == 0) { - pmsg_notice("usbhid_open(): found %ls, serno: %ls\n", walk->product_string, walk->serial_number); - size_t slen = wcslen(walk->serial_number); - if (slen >= serlen && - wcscmp(walk->serial_number + slen - serlen, wserno) == 0) - { - /* found matching serial number */ - break; - } - pmsg_debug("usbhid_open(): serial number does not match\n"); - walk = walk->next; + /* Found matching serial number */ + break; } - if (walk == NULL) - { - pmsg_error("no matching device found\n"); - hid_free_enumeration(list); - return -1; - } - pmsg_debug("usbhid_open(): opening path %s\n", walk->path); - dev = hid_open_path(walk->path); + pmsg_debug("usbhid_open(): serial number does not match\n"); + walk = walk->next; + } + if (walk == NULL) { + pmsg_error("no matching device found\n"); hid_free_enumeration(list); - if (dev == NULL) - { - pmsg_error("found device, but hid_open_path() failed\n"); - return -1; - } + return -1; } - else + pmsg_debug("usbhid_open(): opening path %s\n", walk->path); + dev = hid_open_path(walk->path); + hid_free_enumeration(list); + if (dev == NULL) { + pmsg_error("found device, but hid_open_path() failed\n"); + return -1; + } + } else { + /* No serial number requested, pass straight to hid_open() */ + dev = hid_open(pinfo.usbinfo.vid, pinfo.usbinfo.pid, NULL); + if (dev == NULL) { - /* - * No serial number requested, pass straight to hid_open() - */ - dev = hid_open(pinfo.usbinfo.vid, pinfo.usbinfo.pid, NULL); - if (dev == NULL) - { - pmsg_error("no device found\n"); - return -1; - } + pmsg_warning("USB device with VID: 0x%04x and PID: 0x%04x not found\n", + pinfo.usbinfo.vid, pinfo.usbinfo.pid); + return -1; } + } fd->usb.handle = dev; @@ -166,39 +158,38 @@ static int usbhid_open(const char *port, union pinfo pinfo, union filedescriptor * be incremented by one, as the report ID will be omitted by the * hidapi library. */ - if (pinfo.usbinfo.vid == USB_VENDOR_ATMEL) - { - pmsg_debug("usbhid_open(): probing for max packet size\n"); - memset(usbbuf, 0, sizeof usbbuf); - usbbuf[0] = 0; /* no HID reports used */ - usbbuf[1] = 0; /* DAP_Info */ - usbbuf[2] = 0xFF; /* get max. packet size */ + if (pinfo.usbinfo.vid == USB_VENDOR_ATMEL) { + pmsg_debug("usbhid_open(): probing for max packet size\n"); + memset(usbbuf, 0, sizeof usbbuf); + usbbuf[0] = 0; /* no HID reports used */ + usbbuf[1] = 0; /* DAP_Info */ + usbbuf[2] = 0xFF; /* get max. packet size */ - hid_write(dev, usbbuf, 65); - fd->usb.max_xfer = 64; /* first guess */ + hid_write(dev, usbbuf, 65); + fd->usb.max_xfer = 64; /* first guess */ - memset(usbbuf, 0, sizeof usbbuf); - int res = hid_read_timeout(dev, usbbuf, 10 /* bytes */, 50 /* milliseconds */); - if (res == 0) { - /* no timely response, assume 512 byte size */ - hid_write(dev, usbbuf, (512 - 64) + 1); - fd->usb.max_xfer = 512; - res = hid_read_timeout(dev, usbbuf, 10, 50); - } - if (res <= 0) { - pmsg_error("no response from device\n"); - hid_close(dev); - return -1; - } - if (usbbuf[0] != 0 || usbbuf[1] != 2) { - pmsg_error("unexpected reply to DAP_Info: 0x%02x 0x%02x\n", - usbbuf[0], usbbuf[1]); - } else { - fd->usb.max_xfer = usbbuf[2] + (usbbuf[3] << 8); - pmsg_debug("usbhid_open(): setting max_xfer from DAP_Info response to %d\n", - fd->usb.max_xfer); - } + memset(usbbuf, 0, sizeof usbbuf); + int res = hid_read_timeout(dev, usbbuf, 10 /* bytes */, 50 /* milliseconds */); + if (res == 0) { + /* No timely response, assume 512 byte size */ + hid_write(dev, usbbuf, (512 - 64) + 1); + fd->usb.max_xfer = 512; + res = hid_read_timeout(dev, usbbuf, 10, 50); } + if (res <= 0) { + pmsg_error("no response from device\n"); + hid_close(dev); + return -1; + } + if (usbbuf[0] != 0 || usbbuf[1] != 2) { + pmsg_error("unexpected reply to DAP_Info: 0x%02x 0x%02x\n", + usbbuf[0], usbbuf[1]); + } else { + fd->usb.max_xfer = usbbuf[2] + (usbbuf[3] << 8); + pmsg_debug("usbhid_open(): setting max_xfer from DAP_Info response to %d\n", + fd->usb.max_xfer); + } + } if (fd->usb.max_xfer > USBDEV_MAX_XFER_3) { pmsg_error("unexpected max size %d, reducing to %d\n", fd->usb.max_xfer, USBDEV_MAX_XFER_3); @@ -208,8 +199,7 @@ static int usbhid_open(const char *port, union pinfo pinfo, union filedescriptor return 0; } -static void usbhid_close(union filedescriptor *fd) -{ +static void usbhid_close(union filedescriptor *fd) { hid_device *udev = (hid_device *)fd->usb.handle; if (udev == NULL) @@ -219,22 +209,20 @@ static void usbhid_close(union filedescriptor *fd) } -static int usbhid_send(const union filedescriptor *fd, const unsigned char *bp, size_t mlen) -{ +static int usbhid_send(const union filedescriptor *fd, const unsigned char *bp, size_t mlen) { hid_device *udev = (hid_device *)fd->usb.handle; int rv; int i = mlen; const unsigned char * p = bp; unsigned char usbbuf[USBDEV_MAX_XFER_3 + 1]; - int tx_size; if (udev == NULL) return -1; tx_size = (mlen < USBDEV_MAX_XFER_3)? mlen: USBDEV_MAX_XFER_3; - usbbuf[0] = 0; /* no report ID used */ + usbbuf[0] = 0; /* No report ID used */ memcpy(usbbuf + 1, bp, tx_size); rv = hid_write(udev, usbbuf, tx_size + 1); if (rv < 0) { @@ -244,30 +232,26 @@ static int usbhid_send(const union filedescriptor *fd, const unsigned char *bp, if (rv != tx_size + 1) pmsg_error("short write to USB: %d bytes out of %d written\n", rv, tx_size + 1); - if (verbose > 4) - { - pmsg_trace2("sent: "); + if (verbose > 4) { + pmsg_trace2("sent: "); - while (i) { - unsigned char c = *p; - if (isprint(c)) { - msg_trace2("%c ", c); - } - else { - msg_trace2(". "); - } - msg_trace2("[%02x] ", c); + while (i) { + unsigned char c = *p; + if (isprint(c)) + msg_trace2("%c ", c); + else + msg_trace2(". "); + msg_trace2("[%02x] ", c); - p++; - i--; - } - msg_trace2("\n"); + p++; + i--; + } + msg_trace2("\n"); } return 0; } -static int usbhid_recv(const union filedescriptor *fd, unsigned char *buf, size_t nbytes) -{ +static int usbhid_recv(const union filedescriptor *fd, unsigned char *buf, size_t nbytes) { hid_device *udev = (hid_device *)fd->usb.handle; int i, rv; unsigned char * p = buf; @@ -279,31 +263,26 @@ static int usbhid_recv(const union filedescriptor *fd, unsigned char *buf, size_ if (i != nbytes) pmsg_error("short read, read only %d out of %lu bytes\n", i, (unsigned long) nbytes); - if (verbose > 4) - { - pmsg_trace2("recv: "); + if (verbose > 4) { + pmsg_trace2("recv: "); - while (i) { - unsigned char c = *p; - if (isprint(c)) { - msg_trace2("%c ", c); - } - else { - msg_trace2(". "); - } - msg_trace2("[%02x] ", c); + while (i) { + unsigned char c = *p; + if (isprint(c)) + msg_trace2("%c ", c); + else + msg_trace2(". "); + msg_trace2("[%02x] ", c); - p++; - i--; - } - msg_trace2("\n"); + p++; + i--; + } + msg_trace2("\n"); } - return rv; } -static int usbhid_drain(const union filedescriptor *fd, int display) -{ +static int usbhid_drain(const union filedescriptor *fd, int display) { /* * There is not much point in trying to flush any data * on an USB endpoint, as the endpoint is supposed to @@ -321,8 +300,7 @@ static int usbhid_drain(const union filedescriptor *fd, int display) /* * Device descriptor. */ -struct serial_device usbhid_serdev = -{ +struct serial_device usbhid_serdev = { .open = usbhid_open, .close = usbhid_close, .send = usbhid_send, diff --git a/src/usbdevs.h b/src/usbdevs.h index 0dbdb482..f801e01b 100644 --- a/src/usbdevs.h +++ b/src/usbdevs.h @@ -25,19 +25,28 @@ #ifndef usbdevs_h #define usbdevs_h -#define USB_VENDOR_ATMEL 1003 -#define USB_DEVICE_JTAGICEMKII 0x2103 -#define USB_DEVICE_AVRISPMKII 0x2104 -#define USB_DEVICE_STK600 0x2106 -#define USB_DEVICE_AVRDRAGON 0x2107 -#define USB_DEVICE_JTAGICE3 0x2110 -#define USB_DEVICE_XPLAINEDPRO 0x2111 -#define USB_DEVICE_JTAG3_EDBG 0x2140 -#define USB_DEVICE_ATMEL_ICE 0x2141 +#define USB_VENDOR_ATMEL 0x03EB +#define USB_VENDOR_MICROCHIP 0x04D8 -#define USB_VENDOR_FTDI 0x0403 -#define USB_DEVICE_FT2232 0x6010 -#define USB_DEVICE_FT245 0x6001 +#define USB_DEVICE_JTAGICEMKII 0x2103 +#define USB_DEVICE_AVRISPMKII 0x2104 +#define USB_DEVICE_STK600 0x2106 +#define USB_DEVICE_AVRDRAGON 0x2107 +#define USB_DEVICE_JTAGICE3 0x2110 +#define USB_DEVICE_XPLAINEDPRO 0x2111 +#define USB_DEVICE_JTAG3_EDBG 0x2140 +#define USB_DEVICE_ATMEL_ICE 0x2141 +#define USB_DEVICE_POWERDEBUGGER 0x2144 +#define USB_DEVICE_XPLAINEDMINI 0x2145 +#define USB_DEVICE_PKOBN 0x2175 +#define USB_DEVICE_PICKIT4_AVR_MODE 0x2177 +#define USB_DEVICE_PICKIT4_PIC_MODE 0x9012 +#define USB_DEVICE_SNAP_AVR_MODE 0x2180 +#define USB_DEVICE_SNAP_PIC_MODE 0x9018 + +#define USB_VENDOR_FTDI 0x0403 +#define USB_DEVICE_FT2232 0x6010 +#define USB_DEVICE_FT245 0x6001 #define USBASP_SHARED_VID 0x16C0 /* VOTI */ #define USBASP_SHARED_PID 0x05DC /* Obdev's free shared PID */