Merge branch 'avrdudes:main' into Xplained_Pro_PDI

This commit is contained in:
mcuee 2022-10-24 07:57:55 +08:00 committed by GitHub
commit f2a413d2dc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 789 additions and 617 deletions

View File

@ -49,6 +49,7 @@ jobs:
libusb-1.0-0-dev libusb-1.0-0-dev
libhidapi-dev libhidapi-dev
libftdi1-dev libftdi1-dev
libreadline-dev
texinfo texinfo
texlive texlive
texi2html texi2html
@ -110,6 +111,7 @@ jobs:
libusb-1.0-0-dev:${{matrix.arch}} libusb-1.0-0-dev:${{matrix.arch}}
libhidapi-dev:${{matrix.arch}} libhidapi-dev:${{matrix.arch}}
libftdi1-dev:${{matrix.arch}} libftdi1-dev:${{matrix.arch}}
libreadline-dev:${{matrix.arch}}
- name: Configure - name: Configure
run: >- run: >-
cmake cmake

16
NEWS
View File

@ -58,6 +58,12 @@ Changes since version 7.0:
- Make UPDI programmers less verbose during initialization - Make UPDI programmers less verbose during initialization
#1084 #1084
- Quell mode isn't handled systematically #1114 - 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: * Pull requests:
@ -153,6 +159,16 @@ Changes since version 7.0:
- Suppress Teensy USB communication error message on reboot #1122 - Suppress Teensy USB communication error message on reboot #1122
- Fix UPDI erase when target is locked #1125 - Fix UPDI erase when target is locked #1125
- Review and overhaul AVRDUDE's messaging system #1126 - 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: * Internals:

View File

@ -53,9 +53,9 @@ case "${ostype}" in
# Apple M1 (may be new version of homebrew also) # Apple M1 (may be new version of homebrew also)
if [ -d /opt/homebrew ] if [ -d /opt/homebrew ]
then 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 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
fi fi
;; ;;

View File

@ -377,8 +377,9 @@ int avr_read_mem(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, con
return avr_mem_hiaddr(mem); return avr_mem_hiaddr(mem);
} }
if (pgm->paged_load != NULL && mem->page_size > 1 && // HW programmers need a page size > 1, bootloader typ only offer paged r/w
mem->size % mem->page_size == 0) { 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 * 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; 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 * 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 avr_signature(const PROGRAMMER *pgm, const AVRPART *p) {
int rc; int rc;
report_progress (0,1,"Reading"); if(verbose > 1)
report_progress(0, 1, "Reading");
rc = avr_read(pgm, p, "signature", 0); rc = avr_read(pgm, p, "signature", 0);
if (rc < LIBAVRDUDE_SUCCESS) { if (rc < LIBAVRDUDE_SUCCESS) {
pmsg_error("unable to read signature data for part %s, rc=%d\n", p->desc, rc); pmsg_error("unable to read signature data for part %s, rc=%d\n", p->desc, rc);
return rc; return rc;
} }
report_progress (1,1,NULL); report_progress(1, 1, NULL);
return LIBAVRDUDE_SUCCESS; return LIBAVRDUDE_SUCCESS;
} }

View File

@ -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 * Read the page containing addr from the device into buf
* - Caller to ensure buf has mem->page_size bytes * - 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); unsigned char *pagecopy = cfg_malloc("avr_read_page_default()", pgsize);
if(pgsize == 1) 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); memcpy(pagecopy, mem->buf + base, pgsize);
if((rc = pgm->paged_load(pgm, p, mem, pgsize, base, pgsize)) >= 0) if((rc = pgm->paged_load(pgm, p, mem, pgsize, base, pgsize)) >= 0)
memcpy(buf, mem->buf + base, pgsize); memcpy(buf, mem->buf + base, pgsize);
memcpy(mem->buf + base, pagecopy, pgsize); memcpy(mem->buf + base, pagecopy, pgsize);
if(rc < 0) { if(rc < 0 && pgm->read_byte != avr_read_byte_cached) {
rc = LIBAVRDUDE_SUCCESS; rc = LIBAVRDUDE_SUCCESS;
for(int i=0; i<pgsize; i++) { for(int i=0; i<pgsize; i++) {
if(pgm->read_byte(pgm, p, mem, base+i, pagecopy+i) < 0) { if(pgm->read_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); unsigned char *pagecopy = cfg_malloc("avr_write_page_default()", pgsize);
if(pgsize == 1) 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(pagecopy, mem->buf + base, pgsize);
memcpy(mem->buf + base, data, 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) { 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 // Write modified page cont to device; if unsuccessful try bytewise access
if(avr_write_page_default(pgm, p, mem, base, cp->cont + base) < 0) { if(avr_write_page_default(pgm, p, mem, base, cp->cont + base) < 0) {
for(int i=0; i < cp->page_size; i++) if(pgm->read_byte != avr_read_byte_cached && pgm->write_byte != avr_write_byte_cached) {
if(cp->cont[base+i] != cp->copy[base+i]) for(int i=0; i < cp->page_size; i++)
if(pgm->write_byte(pgm, p, mem, base+i, cp->cont[base+i]) < 0 || if(cp->cont[base+i] != cp->copy[base+i])
pgm->read_byte(pgm, p, mem, base+i, cp->copy+base+i) < 0) { if(pgm->write_byte(pgm, p, mem, base+i, cp->cont[base+i]) < 0 ||
report_progress(1, -1, NULL); pgm->read_byte(pgm, p, mem, base+i, cp->copy+base+i) < 0) {
if(nlOnErr && quell_progress) report_progress(1, -1, NULL);
msg_info("\n"); if(nlOnErr && quell_progress)
pmsg_error("writeCachePage() %s access error at addr 0x%04x\n", mem->desc, base+i); msg_info("\n");
return LIBAVRDUDE_GENERAL_FAILURE; 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 // 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) { 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 // Use pgm->read_byte() if not EEPROM/flash or no paged access
if(!avr_has_paged_access(pgm, mem)) 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 address is out of range synchronise cache and, if successful, pretend reading a zero
if(addr >= (unsigned long) mem->size) { 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, int avr_write_byte_cached(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem,
unsigned long addr, unsigned char data) { 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)) 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 address is out of range synchronise caches with device and return whether successful
if(addr >= (unsigned long) mem->size) 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; return LIBAVRDUDE_GENERAL_FAILURE;
if(mem->page_size == 1) { 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; return LIBAVRDUDE_GENERAL_FAILURE;
} else { } else {
if(!pgm->page_erase || pgm->page_erase(pgm, p, mem, uaddr) < 0) if(!pgm->page_erase || pgm->page_erase(pgm, p, mem, uaddr) < 0)

View File

@ -332,18 +332,20 @@ programmed in high-voltage serial mode.
Override the RS-232 connection baud rate specified in the respective Override the RS-232 connection baud rate specified in the respective
programmer's entry of the configuration file. programmer's entry of the configuration file.
.It Fl B Ar bitclock .It Fl B Ar bitclock
Specify the bit clock period for the JTAG interface or the ISP clock (JTAG ICE only). Specify the bit clock period for the JTAG, PDI, TPI, UPDI, or ISP
The value is a floating-point number in microseconds. interface. The value is a floating-point number in microseconds.
Alternatively, the value might be suffixed with "Hz", "kHz", or "MHz", Alternatively, the value might be suffixed with "Hz", "kHz" or
in order to specify the bit clock frequency, rather than a period. "MHz" in order to specify the bit clock frequency rather than a
The default value of the JTAG ICE results in about 1 microsecond bit period. Some programmers default their bit clock value to a 1
clock period, suitable for target MCUs running at 4 MHz clock and microsecond bit clock period, suitable for target MCUs running at 4
above. MHz clock and above. Slower MCUs need a correspondingly higher bit
Unlike certain parameters in the STK500, the JTAG ICE resets all its clock period. Some programmers reset their bit clock value to the
parameters to default values when the programming software signs default value when the programming software signs off, whilst others
off from the ICE, so for MCUs running at lower clock speeds, this store the last used bit clock value. It is recommended to always
parameter must be specified on the command-line. specify the bit clock if read/write speed is important.
You can use the 'default_bitclock' keyword in your You can use the 'default_bitclock' keyword in your
.Pa ${HOME}/.config/avrdude/avrdude.rc
or
.Pa ${HOME}/.avrduderc .Pa ${HOME}/.avrduderc
file to assign a default value to keep from having to specify this file to assign a default value to keep from having to specify this
option on every invocation. 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 work with different programmers as long as the programmer supports the
Atmel AVR serial program method. You can use the 'default_programmer' Atmel AVR serial program method. You can use the 'default_programmer'
keyword in your keyword in your
.Pa ${HOME}/.config/avrdude/avrdude.rc
or
.Pa ${HOME}/.avrduderc .Pa ${HOME}/.avrduderc
file to assign a default programmer to keep from having to specify file to assign a default programmer to keep from having to specify
this option on every invocation. this option on every invocation.
@ -507,6 +511,8 @@ actual connection to a target controller), this option can be used
together with together with
.Fl t .Fl t
to continue in terminal mode. 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 .It Fl i Ar delay
For bitbang-type programmers, delay for approximately For bitbang-type programmers, delay for approximately
.Ar delay .Ar delay
@ -1320,10 +1326,10 @@ the CS line being managed outside the application.
.Sh FILES .Sh FILES
.Bl -tag -offset indent -width /dev/ppi0XXX .Bl -tag -offset indent -width /dev/ppi0XXX
.It Pa /dev/ppi0 .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 hardware
.It Pa avrdude.conf .It Pa avrdude.conf
programmer and parts configuration file Programmer and parts configuration file
.Pp .Pp
On Windows systems, this file is looked up in the same directory as the On Windows systems, this file is looked up in the same directory as the
executable file. 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 relative to the path of the executable, then in the same directory as
the executable itself, and finally in the system default location the executable itself, and finally in the system default location
.Pa ${PREFIX}/etc/avrdude.conf . .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 .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 .It Pa ~/.inputrc
Initialization file for the Initialization file for the
.Xr readline 3 .Xr readline 3
library library
.It Pa ${PREFIX}/share/doc/avrdude/avrdude.pdf .It Pa <prefix>/doc/avrdude/avrdude.pdf
Schematic of programming hardware User manual
.El .El
.\" .Sh EXAMPLES .\" .Sh EXAMPLES
.Sh DIAGNOSTICS .Sh DIAGNOSTICS

View File

@ -389,7 +389,7 @@
# ATmega169 0x78 # ATmega169 0x78
# #
# Overall avrdude defaults; suitable for ~/.avrduderc # Overall avrdude defaults; suitable for ~/.config/avrdude/config
# #
default_parallel = "@DEFAULT_PAR_PORT@"; default_parallel = "@DEFAULT_PAR_PORT@";
default_serial = "@DEFAULT_SER_PORT@"; default_serial = "@DEFAULT_SER_PORT@";
@ -1270,7 +1270,7 @@ programmer
id = "stk600"; id = "stk600";
desc = "Atmel STK600"; desc = "Atmel STK600";
type = "stk600"; type = "stk600";
prog_modes = PM_TPI | PM_ISP; prog_modes = PM_TPI | PM_ISP | PM_PDI;
connection_type = usb; connection_type = usb;
; ;
@ -2294,7 +2294,7 @@ programmer
type = "jtagice3_updi"; type = "jtagice3_updi";
prog_modes = PM_UPDI; prog_modes = PM_UPDI;
connection_type = usb; connection_type = usb;
usbpid = 0x217f, 0x2180, 0x2181; usbpid = 0x2180, 0x217f, 0x2181;
hvupdi_support = 1; hvupdi_support = 1;
; ;
@ -2308,7 +2308,7 @@ programmer
type = "jtagice3_pdi"; type = "jtagice3_pdi";
prog_modes = PM_PDI; prog_modes = PM_PDI;
connection_type = usb; connection_type = usb;
usbpid = 0x217f, 0x2180, 0x2181; usbpid = 0x2180, 0x217f, 0x2181;
; ;
#------------------------------------------------------------ #------------------------------------------------------------
@ -2321,7 +2321,7 @@ programmer
type = "jtagice3_isp"; type = "jtagice3_isp";
prog_modes = PM_ISP; prog_modes = PM_ISP;
connection_type = usb; connection_type = usb;
usbpid = 0x217f, 0x2180, 0x2181; usbpid = 0x2180, 0x217f, 0x2181;
; ;
#------------------------------------------------------------ #------------------------------------------------------------

View File

@ -21,11 +21,14 @@
#ifndef avrdude_h #ifndef avrdude_h
#define avrdude_h #define avrdude_h
#include <stdio.h>
#define SYSTEM_CONF_FILE "avrdude.conf" #define SYSTEM_CONF_FILE "avrdude.conf"
#if defined(WIN32) #if defined(WIN32)
#define USER_CONF_FILE "avrdude.rc" #define USER_CONF_FILE "avrdude.rc"
#else #else
#define USER_CONF_FILE ".avrduderc" #define USER_CONF_FILE ".avrduderc"
#define XDG_USER_CONF_FILE "avrdude/avrdude.rc"
#endif #endif
extern char *progname; // name of program, for messages 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) extern int quell_progress; // quell progress report -q, reduce effective verbosity level (-qq, -qqq)
int avrdude_message(int msglvl, const char *format, ...); 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_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 #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 MSG_TRACE2 5 // Displayed with -vvvvv
#define MSG2_PROGNAME 1 // Start by printing progname #define MSG2_PROGNAME 1 // Start by printing progname
#define MSG2_FUNCTION 2 // Print calling function (1st arg) after progname #define MSG2_FUNCTION 2 // Print calling function (1st arg) after progname if >= notice
#define MSG2_TYPE 4 // Print message type after function or progname #define MSG2_FILELINE 4 // Print source file and line number after function if >= debug
#define MSG2_INDENT1 8 // Start by printing indentation of progname+1 blanks #define MSG2_TYPE 8 // Print message type after function or progname
#define MSG2_INDENT2 16 // Start by printing indentation of progname+2 blanks #define MSG2_INDENT1 16 // Start by printing indentation of progname+1 blanks
#define MSG2_FLUSH 32 // Flush before and after printing #define MSG2_INDENT2 32 // Start by printing indentation of progname+2 blanks
#define MSG2_FLUSH 64 // Flush before and after printing
// Shortcuts // Shortcuts
#define msg_ext_error(...) avrdude_message2(__func__, 0, MSG_EXT_ERROR, __VA_ARGS__) #define msg_ext_error(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, 0, MSG_EXT_ERROR, __VA_ARGS__)
#define msg_error(...) avrdude_message2(__func__, 0, MSG_ERROR, __VA_ARGS__) #define msg_error(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, 0, MSG_ERROR, __VA_ARGS__)
#define msg_warning(...) avrdude_message2(__func__, 0, MSG_WARNING, __VA_ARGS__) #define msg_warning(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, 0, MSG_WARNING, __VA_ARGS__)
#define msg_info(...) avrdude_message2(__func__, 0, MSG_INFO, __VA_ARGS__) #define msg_info(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, 0, MSG_INFO, __VA_ARGS__)
#define msg_notice(...) avrdude_message2(__func__, 0, MSG_NOTICE, __VA_ARGS__) #define msg_notice(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, 0, MSG_NOTICE, __VA_ARGS__)
#define msg_notice2(...) avrdude_message2(__func__, 0, MSG_NOTICE2, __VA_ARGS__) #define msg_notice2(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, 0, MSG_NOTICE2, __VA_ARGS__)
#define msg_debug(...) avrdude_message2(__func__, 0, MSG_DEBUG, __VA_ARGS__) #define msg_debug(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, 0, MSG_DEBUG, __VA_ARGS__)
#define msg_trace(...) avrdude_message2(__func__, 0, MSG_TRACE, __VA_ARGS__) #define msg_trace(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, 0, MSG_TRACE, __VA_ARGS__)
#define msg_trace2(...) avrdude_message2(__func__, 0, MSG_TRACE2, __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_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(__func__, MSG2_PROGNAME|MSG2_FUNCTION|MSG2_TYPE|MSG2_FLUSH, MSG_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(__func__, MSG2_PROGNAME|MSG2_FUNCTION|MSG2_TYPE|MSG2_FLUSH, MSG_WARNING, __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(__func__, MSG2_PROGNAME|MSG2_FLUSH, MSG_INFO, __VA_ARGS__) #define pmsg_info(...) avrdude_message2(stderr, __LINE__, __FILE__, __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_notice(...) avrdude_message2(stderr, __LINE__, __FILE__, __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_notice2(...) avrdude_message2(stderr, __LINE__, __FILE__, __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_debug(...) avrdude_message2(stderr, __LINE__, __FILE__, __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_trace(...) avrdude_message2(stderr, __LINE__, __FILE__, __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_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_ext_error(...) avrdude_message2(stderr, __LINE__, __FILE__, __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_error(...) avrdude_message2(stderr, __LINE__, __FILE__, __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_warning(...) avrdude_message2(stderr, __LINE__, __FILE__, __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_info(...) avrdude_message2(stderr, __LINE__, __FILE__, __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_notice(...) avrdude_message2(stderr, __LINE__, __FILE__, __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_notice2(...) avrdude_message2(stderr, __LINE__, __FILE__, __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_debug(...) avrdude_message2(stderr, __LINE__, __FILE__, __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_trace(...) avrdude_message2(stderr, __LINE__, __FILE__, __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_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 #endif

View File

@ -498,22 +498,15 @@ void avr_mem_display(const char *prefix, FILE *f, const AVRMEM *m,
int i, j; int i, j;
char * optr; char * optr;
if (m == NULL) { if (m == NULL || verbose > 2) {
fprintf(f, fprintf(f,
"%s Block Poll Page Polled\n" "%s Block Poll Page Polled\n"
"%sMemory Type Alias Mode Delay Size Indx Paged Size Size #Pages MinW MaxW ReadBack\n" "%sMemory Type Alias Mode Delay Size Indx Paged Size Size #Pages MinW MaxW ReadBack\n"
"%s----------- -------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- ---------\n", "%s----------- -------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- ---------\n",
prefix, prefix, prefix); 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 // 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)) { if(prev_mem_offset != m->offset || prev_mem_size != m->size || (strcmp(p->family_id, "") == 0)) {
prev_mem_offset = m->offset; prev_mem_offset = m->offset;

View File

@ -440,19 +440,21 @@ Override the RS-232 connection baud rate specified in the respective
programmer's entry of the configuration file. programmer's entry of the configuration file.
@item -B @var{bitclock} @item -B @var{bitclock}
Specify the bit clock period for the JTAG interface or the ISP clock (JTAG ICE only). Specify the bit clock period for the JTAG, PDI, TPI, UPDI, or ISP
The value is a floating-point number in microseconds. interface. The value is a floating-point number in microseconds.
Alternatively, the value might be suffixed with "Hz", "kHz", or "MHz", Alternatively, the value might be suffixed with "Hz", "kHz" or
in order to specify the bit clock frequency, rather than a period. "MHz" in order to specify the bit clock frequency rather than a
The default value of the JTAG ICE results in about 1 microsecond bit period. Some programmers default their bit clock value to a 1
clock period, suitable for target MCUs running at 4 MHz clock and microsecond bit clock period, suitable for target MCUs running at 4
above. MHz clock and above. Slower MCUs need a correspondingly higher bit
Unlike certain parameters in the STK500, the JTAG ICE resets all its clock period. Some programmers reset their bit clock value to the
parameters to default values when the programming software signs default value when the programming software signs off, whilst
off from the ICE, so for MCUs running at lower clock speeds, this others store the last used bit clock value. It is recommended to
parameter must be specified on the command-line. always specify the bit clock if read/write speed is important. You
It can also be set in the configuration file by using the 'default_bitclock' can use the 'default_bitclock' keyword in your
keyword. @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} @item -c @var{programmer-id}
Specify the programmer to be used. AVRDUDE knows about several common 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 adjust parameters local to the programming tool (independent of an
actual connection to a target controller), this option can be used actual connection to a target controller), this option can be used
together with @option{-t} to continue in terminal mode. 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} @item -i @var{delay}
For bitbang-type programmers, delay for approximately 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 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 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 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 of AVRDUDE. Likewise, if you have a parallel port programmer that is
not supported by AVRDUDE, chances are good that you can copy and not supported, chances are that you can copy an
existing programmer definition, and with only a few changes, make your existing programmer definition and, with only a few changes, make your
programmer work with AVRDUDE. programmer work.
AVRDUDE first looks for a system wide configuration file in a platform AVRDUDE first looks for a system wide configuration file in a platform
dependent location. On Unix, this is usually dependent location. On Unix, this is usually
@code{/usr/local/etc/avrdude.conf}, while on Windows it is usually in the @code{/usr/local/etc/avrdude.conf}, whilst on Windows it is usually in the
same location as the executable file. The name of this file can be same location as the executable file. The full name of this file can be
changed using the @option{-C} command line option. After the system wide specified using the @option{-C} command line option. After parsing the system wide
configuration file is parsed, AVRDUDE looks for a per-user configuration configuration file, AVRDUDE looks for a per-user configuration
file to augment or override the system wide defaults. On Unix, the 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 per-user file is @code{$@{XDG_CONFIG_HOME@}/avrdude/avrdude.rc}, whereas
Windows, this file is the @code{avrdude.rc} file located in the same if @code{$@{XDG_CONFIG_HOME@}} is either not set or empty,
directory as the executable. @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 @menu
* AVRDUDE Defaults:: * AVRDUDE Defaults::
@ -3044,14 +3051,15 @@ See also: @url{http://www.libusb.org/ticket/6}
@item @item
Problem: after flashing a firmware that reduces the target's clock Problem: after flashing a firmware that reduces the target's clock
speed (e.g. through the @code{CLKPR} register), further ISP connection 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 Solution: Even though ISP starts with pulling @var{/RESET} low, the
target continues to run at the internal clock speed as defined by the target continues to run at the internal clock speed either as defined by
firmware running before. Therefore, the ISP clock speed must be the firmware running before or as set by the factory. Therefore, the
reduced appropriately (to less than 1/4 of the internal clock speed) ISP clock speed must be reduced appropriately (to less than 1/4 of the
using the -B option before the ISP initialization sequence will internal clock speed) using the -B option before the ISP initialization
succeed. sequence will succeed.
As that slows down the entire subsequent ISP session, it might make 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 sense to just issue a @emph{chip erase} using the slow ISP clock

View File

@ -121,6 +121,8 @@ enum flip2_mem_unit {
FLIP2_MEM_UNIT_EXT_MEM_DF = 0x10 FLIP2_MEM_UNIT_EXT_MEM_DF = 0x10
}; };
#ifdef HAVE_LIBUSB
/* EXPORTED PROGRAMMER FUNCTION PROTOTYPES */ /* EXPORTED PROGRAMMER FUNCTION PROTOTYPES */
static int flip2_open(PROGRAMMER *pgm, const char *port_spec); 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); static void flip2_teardown(PROGRAMMER * pgm);
/* INTERNAL PROGRAMMER FUNCTION PROTOTYPES */ /* 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); static void flip2_show_info(struct flip2 *flip2);

View File

@ -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, static int jtag3_write_byte(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem,
unsigned long addr, unsigned char data); unsigned long addr, unsigned char data);
static int jtag3_set_sck_period(const PROGRAMMER *pgm, double v); 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, static int jtag3_paged_write(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m,
unsigned int page_size, unsigned int page_size,
unsigned int addr, unsigned int n_bytes); 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) if (PDATA(pgm)->set_sck(pgm, parm) < 0)
return -1; return -1;
} }
jtag3_print_parms1(pgm, progbuf); jtag3_print_parms1(pgm, progbuf, stderr);
if (conn == PARM3_CONN_JTAG) if (conn == PARM3_CONN_JTAG)
{ {
pmsg_notice2("jtag3_initialize(): " pmsg_notice2("jtag3_initialize(): "
@ -1504,6 +1504,30 @@ int jtag3_open_common(PROGRAMMER *pgm, const char *port) {
} }
#endif #endif
if (rv < 0) { 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: ", pmsg_error("did not find any device matching VID 0x%04x and PID list: ",
(unsigned) pinfo.usbinfo.vid); (unsigned) pinfo.usbinfo.vid);
int notfirst = 0; 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]; unsigned char buf[3];
if (jtag3_getparm(pgm, SCOPE_GENERAL, 1, PARM3_VTARGET, buf, 2) < 0) if (jtag3_getparm(pgm, SCOPE_GENERAL, 1, PARM3_VTARGET, buf, 2) < 0)
return; 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); verbose? "": " ", b2_to_u16(buf)/1000.0);
// Print features unique to the Power Debugger // 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) if (jtag3_getparm(pgm, SCOPE_GENERAL, 1, PARM3_VADJUST, buf, 2) < 0)
return; return;
analog_raw_data = b2_to_u16(buf); 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); verbose? "": " ", analog_raw_data / 1000.0);
// Read measured generator voltage value (VOUT) // Read measured generator voltage value (VOUT)
@ -2362,7 +2386,7 @@ void jtag3_print_parms1(const PROGRAMMER *pgm, const char *p) {
else { else {
if (analog_raw_data & 0x0800) if (analog_raw_data & 0x0800)
analog_raw_data |= 0xF000; 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)); verbose? "": " ", ((float) analog_raw_data / -200.0));
} }
@ -2375,7 +2399,7 @@ void jtag3_print_parms1(const PROGRAMMER *pgm, const char *p) {
else { else {
if (analog_raw_data & 0x0800) if (analog_raw_data & 0x0800)
analog_raw_data |= 0xF000; 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)); 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) if (buf[0] != 0x90)
pmsg_error("invalid PARM3_ANALOG_A_CURRENT data packet format\n"); pmsg_error("invalid PARM3_ANALOG_A_CURRENT data packet format\n");
else 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); verbose? "": " ", (float) analog_raw_data * 0.003472);
// Read channel B voltage // Read channel B voltage
@ -2398,7 +2422,7 @@ void jtag3_print_parms1(const PROGRAMMER *pgm, const char *p) {
else { else {
if (analog_raw_data & 0x0800) if (analog_raw_data & 0x0800)
analog_raw_data |= 0xF000; 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); verbose? "": " ", (float) analog_raw_data / -200.0);
} }
@ -2411,7 +2435,7 @@ void jtag3_print_parms1(const PROGRAMMER *pgm, const char *p) {
else { else {
if (analog_raw_data & 0x0800) if (analog_raw_data & 0x0800)
analog_raw_data |= 0xF000; 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); verbose? "": " ", (float) analog_raw_data * 0.555556);
} }
break; break;
@ -2422,33 +2446,33 @@ void jtag3_print_parms1(const PROGRAMMER *pgm, const char *p) {
return; return;
if (b2_to_u16(buf) > 0) { 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) if (jtag3_getparm(pgm, SCOPE_AVR, 1, PARM3_CLK_MEGA_DEBUG, buf, 2) < 0)
return; return;
if (b2_to_u16(buf) > 0) { 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) if (jtag3_getparm(pgm, SCOPE_AVR, 1, PARM3_CLK_XMEGA_JTAG, buf, 2) < 0)
return; return;
if (b2_to_u16(buf) > 0) { 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) if (jtag3_getparm(pgm, SCOPE_AVR, 1, PARM3_CLK_XMEGA_PDI, buf, 2) < 0)
return; return;
if (b2_to_u16(buf) > 0) { 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) { static void jtag3_print_parms(const PROGRAMMER *pgm, FILE *fp) {
jtag3_print_parms1(pgm, ""); jtag3_print_parms1(pgm, "", fp);
} }
static unsigned char jtag3_memtype(const PROGRAMMER *pgm, const AVRPART *p, unsigned long addr) { static unsigned char jtag3_memtype(const PROGRAMMER *pgm, const AVRPART *p, unsigned long addr) {

View File

@ -38,7 +38,7 @@ int jtag3_setparm(const PROGRAMMER *pgm, unsigned char scope,
unsigned char *value, unsigned char length); unsigned char *value, unsigned char length);
int jtag3_command(const PROGRAMMER *pgm, unsigned char *cmd, unsigned int cmdlen, int jtag3_command(const PROGRAMMER *pgm, unsigned char *cmd, unsigned int cmdlen,
unsigned char **resp, const char *descr); 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); int jtag3_set_vtarget(const PROGRAMMER *pgm, double voltage);
extern const char jtag3_desc[]; extern const char jtag3_desc[];
extern const char jtag3_dw_desc[]; extern const char jtag3_dw_desc[];

View File

@ -104,7 +104,7 @@ static int jtagmkI_getparm(const PROGRAMMER *pgm, unsigned char parm,
unsigned char * value); unsigned char * value);
static int jtagmkI_setparm(const PROGRAMMER *pgm, unsigned char parm, static int jtagmkI_setparm(const PROGRAMMER *pgm, unsigned char parm,
unsigned char value); 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); 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 HW version: 0x%02x\n", p, hw);
msg_info("%sICE FW version: 0x%02x\n", p, fw); msg_info("%sICE FW version: 0x%02x\n", p, fw);
jtagmkI_print_parms1(pgm, p); jtagmkI_print_parms1(pgm, p, stderr);
return; 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; unsigned char vtarget, jtag_clock;
const char *clkstr; const char *clkstr;
double clk; double clk;
@ -1211,15 +1211,15 @@ static void jtagmkI_print_parms1(const PROGRAMMER *pgm, const char *p) {
clk = 1e6; clk = 1e6;
} }
msg_info("%sVtarget : %.1f V\n", p, 6.25 * (unsigned)vtarget / 255.0); fmsg_out(fp, "%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, "%sJTAG clock : %s (%.1f us)\n", p, clkstr, 1.0e6 / clk);
return; return;
} }
static void jtagmkI_print_parms(const PROGRAMMER *pgm) { static void jtagmkI_print_parms(const PROGRAMMER *pgm, FILE *fp) {
jtagmkI_print_parms1(pgm, ""); jtagmkI_print_parms1(pgm, "", fp);
} }
const char jtagmkI_desc[] = "Atmel JTAG ICE mkI"; const char jtagmkI_desc[] = "Atmel JTAG ICE mkI";

View File

@ -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_set_sck_period(const PROGRAMMER *pgm, double v);
static int jtagmkII_setparm(const PROGRAMMER *pgm, unsigned char parm, static int jtagmkII_setparm(const PROGRAMMER *pgm, unsigned char parm,
unsigned char * value); 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, static int jtagmkII_paged_write(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m,
unsigned int page_size, unsigned int page_size,
unsigned int addr, unsigned int n_bytes); 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[0], PDATA(pgm)->serno[1], PDATA(pgm)->serno[2],
PDATA(pgm)->serno[3], PDATA(pgm)->serno[4], PDATA(pgm)->serno[5]); PDATA(pgm)->serno[3], PDATA(pgm)->serno[4], PDATA(pgm)->serno[5]);
jtagmkII_print_parms1(pgm, p); jtagmkII_print_parms1(pgm, p, stderr);
return; 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]; unsigned char vtarget[4], jtag_clock[4];
char clkbuf[20]; char clkbuf[20];
double clk; 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) if (jtagmkII_getparm(pgm, PAR_OCD_VTARGET, vtarget) < 0)
return; 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 ((pgm->flag & PGM_FL_IS_JTAG)) {
if (jtagmkII_getparm(pgm, PAR_OCD_JTAG_CLK, jtag_clock) < 0) 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]); sprintf(clkbuf, "%.1f kHz", 5.35e3 / (double)jtag_clock[0]);
clk = 5.35e6 / (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; return;
} }
static void jtagmkII_print_parms(const PROGRAMMER *pgm) { static void jtagmkII_print_parms(const PROGRAMMER *pgm, FILE *fp) {
jtagmkII_print_parms1(pgm, ""); jtagmkII_print_parms1(pgm, "", fp);
} }
static unsigned char jtagmkII_memtype(const PROGRAMMER *pgm, const AVRPART *p, unsigned long addr) { static unsigned char jtagmkII_memtype(const PROGRAMMER *pgm, const AVRPART *p, unsigned long addr) {

View File

@ -783,7 +783,8 @@ typedef struct programmer_t {
unsigned long addr, unsigned char *value); unsigned long addr, unsigned char *value);
int (*read_sig_bytes) (const struct programmer_t *pgm, const AVRPART *p, const AVRMEM *m); 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); 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_vtarget) (const struct programmer_t *pgm, double v);
int (*set_varef) (const struct programmer_t *pgm, unsigned int chan, 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); int (*set_fosc) (const struct programmer_t *pgm, double v);

View File

@ -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; int rc = 0;
va_list ap; va_list ap;
if(msglvl <= MSG_ERROR) // Serious error? Freee progress bars (if any)
report_progress(1, -1, NULL);
if(msgmode & MSG2_FLUSH) { if(msgmode & MSG2_FLUSH) {
fflush(stdout); fflush(stdout);
fflush(stderr); fflush(stderr);
} }
// Reduce effective verbosity level by number of -q above one // Reduce effective verbosity level by number of -q above one when printing to stderr
if ((quell_progress < 2? verbose: verbose+1-quell_progress) >= msglvl) { if ((quell_progress < 2 || fp != stderr? verbose: verbose+1-quell_progress) >= msglvl) {
if(msgmode & MSG2_PROGNAME) { if(msgmode & MSG2_PROGNAME) {
fprintf(stderr, "%s", progname); fprintf(fp, "%s", progname);
if(verbose >= MSG_NOTICE && (msgmode & MSG2_FUNCTION)) 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) if(msgmode & MSG2_TYPE)
fprintf(stderr, " %s", avrdude_message_type(msglvl)); fprintf(fp, " %s", avrdude_message_type(msglvl));
fprintf(stderr, ": "); fprintf(fp, ": ");
} else if(msgmode & MSG2_INDENT1) { } else if(msgmode & MSG2_INDENT1) {
fprintf(stderr, "%*s", (int) strlen(progname)+1, ""); fprintf(fp, "%*s", (int) strlen(progname)+1, "");
} else if(msgmode & MSG2_INDENT2) { } else if(msgmode & MSG2_INDENT2) {
fprintf(stderr, "%*s", (int) strlen(progname)+2, ""); fprintf(fp, "%*s", (int) strlen(progname)+2, "");
} }
va_start(ap, format); va_start(ap, format);
rc = vfprintf(stderr, format, ap); rc = vfprintf(fp, format, ap);
va_end(ap); va_end(ap);
} }
if(msgmode & MSG2_FLUSH) if(msgmode & MSG2_FLUSH)
fflush(stderr); fflush(fp);
return rc; return rc;
} }
@ -155,14 +167,14 @@ static void usage(void)
"Options:\n" "Options:\n"
" -p <partno> Specify AVR device\n" " -p <partno> Specify AVR device\n"
" -b <baudrate> Override RS-232 baud rate\n" " -b <baudrate> Override RS-232 baud rate\n"
" -B <bitclock> Specify JTAG/STK500v2 bit clock period (us)\n" " -B <bitclock> Specify bit clock period (us)\n"
" -C <config-file> Specify location of configuration file\n" " -C <config-file> Specify location of configuration file\n"
" -c <programmer> Specify programmer type\n" " -c <programmer> Specify programmer type\n"
" -A Disable trailing-0xff removal from file and AVR read\n" " -A Disable trailing-0xff removal from file and AVR read\n"
" -D Disable auto erase for flash memory; implies -A\n" " -D Disable auto erase for flash memory; implies -A\n"
" -i <delay> ISP Clock Delay [in microseconds]\n" " -i <delay> ISP Clock Delay [in microseconds]\n"
" -P <port> Specify connection port\n" " -P <port> Specify connection port\n"
" -F Override invalid signature check\n" " -F Override invalid signature or initialisation check\n"
" -e Perform a chip erase\n" " -e Perform a chip erase\n"
" -O Perform RC oscillator calibration (see AVR053)\n" " -O Perform RC oscillator calibration (see AVR053)\n"
" -U <memtype>:r|w|v:<filename>[:format]\n" " -U <memtype>:r|w|v:<filename>[: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 * main routine
*/ */
@ -465,10 +503,6 @@ int main(int argc, char * argv [])
char * logfile; /* Use logfile rather than stderr for diagnostics */ char * logfile; /* Use logfile rather than stderr for diagnostics */
enum updateflags uflags = UF_AUTO_ERASE | UF_VERIFY; /* Flags for do_op() */ enum updateflags uflags = UF_AUTO_ERASE | UF_VERIFY; /* Flags for do_op() */
#if !defined(WIN32)
char * homedir;
#endif
#ifdef _MSC_VER #ifdef _MSC_VER
_set_printf_count_output(1); _set_printf_count_output(1);
#endif #endif
@ -856,14 +890,10 @@ int main(int argc, char * argv [])
win_usr_config_set(usr_config); win_usr_config_set(usr_config);
#else #else
usr_config[0] = 0; usr_config[0] = 0;
homedir = getenv("HOME"); if(!concatpath(usr_config, getenv("XDG_CONFIG_HOME"), XDG_USER_CONF_FILE, sizeof usr_config))
if (homedir != NULL) { concatpath(usr_config, getenv("HOME"), ".config/" XDG_USER_CONF_FILE, sizeof usr_config);
strcpy(usr_config, homedir); if(stat(usr_config, &sb) < 0 || (sb.st_mode & S_IFREG) == 0)
i = strlen(usr_config); concatpath(usr_config, getenv("HOME"), USER_CONF_FILE, sizeof usr_config);
if (i && (usr_config[i - 1] != '/'))
strcat(usr_config, "/");
strcat(usr_config, USER_CONF_FILE);
}
#endif #endif
if (quell_progress == 0) if (quell_progress == 0)
@ -1190,9 +1220,10 @@ int main(int argc, char * argv [])
init_ok = (rc = pgm->initialize(pgm, p)) >= 0; init_ok = (rc = pgm->initialize(pgm, p)) >= 0;
if (!init_ok) { if (!init_ok) {
pmsg_error("initialization failed, rc=%d\n", rc); 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) { if (!ovsigck) {
imsg_error("double check connections and try again or use -F to override\n"); imsg_error("- use -F to override this check\n\n");
imsg_error("this check\n\n");
exitrc = 1; exitrc = 1;
goto main_exit; goto main_exit;
} }

View File

@ -140,6 +140,7 @@ PROGRAMMER *pgm_new(void) {
pgm->write_setup = NULL; pgm->write_setup = NULL;
pgm->read_sig_bytes = NULL; pgm->read_sig_bytes = NULL;
pgm->read_sib = NULL; pgm->read_sib = NULL;
pgm->term_keep_alive= NULL;
pgm->print_parms = NULL; pgm->print_parms = NULL;
pgm->set_vtarget = NULL; pgm->set_vtarget = NULL;
pgm->set_varef = NULL; pgm->set_varef = NULL;

View File

@ -47,7 +47,7 @@
static int stk500_getparm(const PROGRAMMER *pgm, unsigned parm, unsigned *value); static int stk500_getparm(const PROGRAMMER *pgm, unsigned parm, unsigned *value);
static int stk500_setparm(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) { 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) { 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; 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]; unsigned char buf[16];
int tries; int tries;
unsigned char ext_byte; unsigned char ext_byte;
OPCODE * lext;
addr /= a_div;
tries = 0; tries = 0;
retry: retry:
tries++; tries++;
/* To support flash > 64K words the correct Extended Address Byte is needed */ // Support large flash by sending the correct extended address byte when needed
lext = mem->op[AVR_OP_LOAD_EXT_ADDR];
if (lext != NULL) { if(pgm->prog_modes & PM_SPM) { // Bootloaders, eg, optiboot, optiboot_dx, optiboot_x
ext_byte = (addr >> 16) & 0xff; if(mem->size/a_div > 64*1024) { // Extended addressing needed
if (ext_byte != PDATA(pgm)->ext_addr_byte) { ext_byte = (addr >> 16) & 0xff;
/* Either this is the first addr load, or a different 64K word section */ if(ext_byte != PDATA(pgm)->ext_addr_byte) { // First addr load or a different 64k section
memset(buf, 0, 4); buf[0] = 0x4d; // Protocol bytes that bootloaders expect
avr_set_bits(lext, buf); buf[1] = 0x00;
avr_set_addr(lext, buf, addr); buf[2] = ext_byte;
stk500_cmd(pgm, buf, buf); buf[3] = 0x00;
PDATA(pgm)->ext_addr_byte = ext_byte; 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, static int stk500_paged_write(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m,
unsigned int page_size, unsigned int page_size,
unsigned int addr, unsigned int n_bytes) 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 n;
unsigned int i; unsigned int i;
if (strcmp(m->desc, "flash") == 0) { if(set_memtype_a_div(pgm, p, m, &memtype, &a_div) < 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 {
return -2; return -2;
}
n = addr + n_bytes; n = addr + n_bytes;
#if 0 #if 0
msg_info( msg_debug(
"n_bytes = %d\n" "n_bytes = %d\n"
"n = %u\n" "n = %u\n"
"a_div = %d\n" "a_div = %d\n"
@ -775,7 +820,7 @@ static int stk500_paged_write(const PROGRAMMER *pgm, const AVRPART *p, const AVR
tries = 0; tries = 0;
retry: retry:
tries++; 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 /* build command block and avoid multiple send commands as it leads to a crash
of the silabs usb serial driver on mac os x */ 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; unsigned int n;
int block_size; int block_size;
if (strcmp(m->desc, "flash") == 0) { if(set_memtype_a_div(pgm, p, m, &memtype, &a_div) < 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 {
return -2; return -2;
}
n = addr + n_bytes; n = addr + n_bytes;
for (; addr < n; addr += block_size) { 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; tries = 0;
retry: retry:
tries++; tries++;
stk500_loadaddr(pgm, m, addr/a_div); stk500_loadaddr(pgm, m, addr, a_div);
buf[0] = Cmnd_STK_READ_PAGE; buf[0] = Cmnd_STK_READ_PAGE;
buf[1] = (block_size >> 8) & 0xff; buf[1] = (block_size >> 8) & 0xff;
buf[2] = block_size & 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); msg_info("%sTopcard : %s\n", p, n);
} }
if(strcmp(pgm->type, "Arduino") != 0) if(strcmp(pgm->type, "Arduino") != 0)
stk500_print_parms1(pgm, p); stk500_print_parms1(pgm, p, stderr);
return; 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; unsigned vtarget, vadjust, osc_pscale, osc_cmatch, sck_duration;
stk500_getparm(pgm, Parm_STK_VTARGET, &vtarget); 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_OSC_CMATCH, &osc_cmatch);
stk500_getparm(pgm, Parm_STK_SCK_DURATION, &sck_duration); stk500_getparm(pgm, Parm_STK_SCK_DURATION, &sck_duration);
msg_info("%sVtarget : %.1f V\n", p, vtarget / 10.0); fmsg_out(fp, "%sVtarget : %.1f V\n", p, vtarget / 10.0);
msg_info("%sVaref : %.1f V\n", p, vadjust / 10.0); fmsg_out(fp, "%sVaref : %.1f V\n", p, vadjust / 10.0);
msg_info("%sOscillator : ", p); fmsg_out(fp, "%sOscillator : ", p);
if (osc_pscale == 0) if (osc_pscale == 0)
msg_info("Off\n"); fmsg_out(fp, "Off\n");
else { else {
int prescale = 1; int prescale = 1;
double f = STK500_XTAL / 2; double f = STK500_XTAL / 2;
@ -1203,16 +1235,16 @@ static void stk500_print_parms1(const PROGRAMMER *pgm, const char *p) {
unit = "kHz"; unit = "kHz";
} else } else
unit = "Hz"; 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; return;
} }
static void stk500_print_parms(const PROGRAMMER *pgm) { static void stk500_print_parms(const PROGRAMMER *pgm, FILE *fp) {
stk500_print_parms1(pgm, ""); stk500_print_parms1(pgm, "", fp);
} }
static void stk500_setup(PROGRAMMER * pgm) static void stk500_setup(PROGRAMMER * pgm)

View File

@ -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_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_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 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, static int stk500v2_paged_load(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m,
unsigned int page_size, unsigned int page_size,
unsigned int addr, unsigned int n_bytes); 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); stk500v2_getparm2(pgm, PARAM2_EC_ID_TABLE_REV, &rev);
msg_info("%sEC_ID table rev : %d\n", p, rev); msg_info("%sEC_ID table rev : %d\n", p, rev);
} }
stk500v2_print_parms1(pgm, p); stk500v2_print_parms1(pgm, p, stderr);
return; return;
} }
@ -3095,7 +3095,7 @@ f_to_kHz_MHz(double f, const char **unit)
return f; 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 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 int sck_stk600, clock_conf, dac, oct, varef;
unsigned char vtarget_jtag[4]; 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; pgmcp->cookie = PDATA(pgm)->chained_pdata;
jtagmkII_getparm(pgmcp, PAR_OCD_VTARGET, vtarget_jtag); jtagmkII_getparm(pgmcp, PAR_OCD_VTARGET, vtarget_jtag);
pgm_free(pgmcp); pgm_free(pgmcp);
msg_info("%sVtarget : %.1f V\n", p, fmsg_out(fp, "%sVtarget : %.1f V\n", p, b2_to_u16(vtarget_jtag) / 1000.0);
b2_to_u16(vtarget_jtag) / 1000.0);
} else if (PDATA(pgm)->pgmtype == PGMTYPE_JTAGICE3) { } else if (PDATA(pgm)->pgmtype == PGMTYPE_JTAGICE3) {
PROGRAMMER *pgmcp = pgm_dup(pgm); PROGRAMMER *pgmcp = pgm_dup(pgm);
pgmcp->cookie = PDATA(pgm)->chained_pdata; 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 // Copy pgm->id contents over to pgmcp->id
for(LNODEID ln=lfirst(pgm->id); ln; ln=lnext(ln)) for(LNODEID ln=lfirst(pgm->id); ln; ln=lnext(ln))
ladd(pgmcp->id, cfg_strdup("stk500v2_print_parms1()", ldata(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); pgm_free(pgmcp);
} else { } else {
stk500v2_getparm(pgm, PARAM_VTARGET, &vtarget); 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) { 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_VADJUST, &vadjust);
stk500v2_getparm(pgm, PARAM_OSC_PSCALE, &osc_pscale); stk500v2_getparm(pgm, PARAM_OSC_PSCALE, &osc_pscale);
stk500v2_getparm(pgm, PARAM_OSC_CMATCH, &osc_cmatch); 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)); stk500v2_sck_to_us(pgm, sck_duration));
msg_info("%sVaref : %.1f V\n", p, vadjust / 10.0); fmsg_out(fp, "%sVaref : %.1f V\n", p, vadjust / 10.0);
msg_info("%sOscillator : ", p); fmsg_out(fp, "%sOscillator : ", p);
if (osc_pscale == 0) if (osc_pscale == 0)
msg_info("Off\n"); fmsg_out(fp, "Off\n");
else { else {
prescale = 1; prescale = 1;
f = STK500V2_XTAL / 2; f = STK500V2_XTAL / 2;
@ -3153,14 +3152,14 @@ static void stk500v2_print_parms1(const PROGRAMMER *pgm, const char *p) {
f /= prescale; f /= prescale;
f /= (osc_cmatch + 1); f /= (osc_cmatch + 1);
f = f_to_kHz_MHz(f, &unit); f = f_to_kHz_MHz(f, &unit);
msg_info("%.3f %s\n", f, unit); fmsg_out(fp, "%.3f %s\n", f, unit);
} }
break; break;
case PGMTYPE_AVRISP_MKII: case PGMTYPE_AVRISP_MKII:
case PGMTYPE_JTAGICE_MKII: case PGMTYPE_JTAGICE_MKII:
stk500v2_getparm(pgm, PARAM_SCK_DURATION, &sck_duration); 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]); (float) 1000000 / avrispmkIIfreqs[sck_duration]);
break; break;
@ -3172,7 +3171,7 @@ static void stk500v2_print_parms1(const PROGRAMMER *pgm, const char *p) {
if (stk500v2_jtag3_send(pgm, cmd, 1) >= 0 && if (stk500v2_jtag3_send(pgm, cmd, 1) >= 0 &&
stk500v2_jtag3_recv(pgm, cmd, 4) >= 2) { stk500v2_jtag3_recv(pgm, cmd, 4) >= 2) {
unsigned int sck = cmd[1] | (cmd[2] << 8); 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))); (float)(1E6 / (1000.0 * sck)));
} }
} }
@ -3180,23 +3179,23 @@ static void stk500v2_print_parms1(const PROGRAMMER *pgm, const char *p) {
case PGMTYPE_STK600: case PGMTYPE_STK600:
stk500v2_getparm2(pgm, PARAM2_AREF0, &varef); 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); 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); 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); (float) (sck_stk600 + 1) / 8.0);
stk500v2_getparm2(pgm, PARAM2_CLOCK_CONF, &clock_conf); stk500v2_getparm2(pgm, PARAM2_CLOCK_CONF, &clock_conf);
oct = (clock_conf & 0xf000) >> 12u; oct = (clock_conf & 0xf000) >> 12u;
dac = (clock_conf & 0x0ffc) >> 2u; dac = (clock_conf & 0x0ffc) >> 2u;
f = pow(2, (double)oct) * 2078.0 / (2 - (double)dac / 1024.0); f = pow(2, (double)oct) * 2078.0 / (2 - (double)dac / 1024.0);
f = f_to_kHz_MHz(f, &unit); f = f_to_kHz_MHz(f, &unit);
msg_info("%sOscillator : %.3f %s\n", fmsg_out(fp, "%sOscillator : %.3f %s\n",
p, f, unit); p, f, unit);
break; break;
default: 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); sck_duration * 8.0e6 / STK500V2_XTAL + 0.05);
break; break;
} }
@ -3205,8 +3204,8 @@ static void stk500v2_print_parms1(const PROGRAMMER *pgm, const char *p) {
} }
static void stk500v2_print_parms(const PROGRAMMER *pgm) { static void stk500v2_print_parms(const PROGRAMMER *pgm, FILE *fp) {
stk500v2_print_parms1(pgm, ""); stk500v2_print_parms1(pgm, "", fp);
} }
static int stk500v2_perform_osccal(const PROGRAMMER *pgm) { static int stk500v2_perform_osccal(const PROGRAMMER *pgm) {

View File

@ -33,10 +33,21 @@
#include <errno.h> #include <errno.h>
#if defined(HAVE_LIBREADLINE) #if defined(HAVE_LIBREADLINE)
# include <readline/readline.h> #include <readline/readline.h>
# include <readline/history.h> #include <readline/history.h>
#ifdef _MSC_VER
#include "msvc/unistd.h"
#else
#include <unistd.h>
#endif #endif
#ifdef WIN32
#include <windows.h>
#endif
#endif
#include "avrdude.h" #include "avrdude.h"
#include "term.h" #include "term.h"
@ -114,7 +125,7 @@ static int nexttok(char *buf, char **tok, char **next) {
n = q; n = q;
uint8_t quotes = 0; uint8_t quotes = 0;
while (*n && (!isspace(*n) || quotes)) { while (*n && (!isspace(*n) || quotes)) {
// poor man's quote and escape processing // Poor man's quote and escape processing
if (*n == '"' || *n == '\'') if (*n == '"' || *n == '\'')
quotes++; quotes++;
else if(*n == '\\' && n[1]) else if(*n == '\\' && n[1])
@ -173,7 +184,7 @@ static int chardump_line(char *buffer, unsigned char *p, int n, int pad) {
int i; int i;
unsigned char b[128]; unsigned char b[128];
// sanity check // Sanity check
n = n < 1? 1: n > sizeof b? sizeof b: n; n = n < 1? 1: n > sizeof b? sizeof b: n;
memcpy(b, p, n); memcpy(b, p, n);
@ -202,7 +213,7 @@ static int hexdump_buf(FILE *f, int startaddr, unsigned char *buf, int len) {
n = len; n = len;
hexdump_line(dst1, p, n, 48); hexdump_line(dst1, p, n, 48);
chardump_line(dst2, p, n, 16); 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; len -= n;
addr += n; addr += n;
p += 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[]) { static int cmd_dump(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
if (argc < 2 || argc > 4) { if (argc < 2 || argc > 4) {
terminal_message(MSG_INFO, msg_error(
"Usage: %s <memory> <addr> <len>\n" "Usage: %s <memory> <addr> <len>\n"
" %s <memory> <addr> ...\n" " %s <memory> <addr> ...\n"
" %s <memory> <addr>\n" " %s <memory> <addr>\n"
@ -229,8 +240,7 @@ static int cmd_dump(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
char *memtype = argv[1]; char *memtype = argv[1];
AVRMEM *mem = avr_locate_mem(p, memtype); AVRMEM *mem = avr_locate_mem(p, memtype);
if (mem == NULL) { if (mem == NULL) {
terminal_message(MSG_INFO, "%s (dump): %s memory type not defined for part %s\n", pmsg_error("(dump) %s memory type not defined for part %s\n", memtype, p->desc);
progname, memtype, p->desc);
return -1; return -1;
} }
int maxsize = mem->size; 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) { if (argc >= 3 && strcmp(argv[2], "...") != 0) {
addr = strtoul(argv[2], &end_ptr, 0); addr = strtoul(argv[2], &end_ptr, 0);
if (*end_ptr || (end_ptr == argv[2])) { if (*end_ptr || (end_ptr == argv[2])) {
terminal_message(MSG_INFO, "%s (dump): can't parse address %s\n", pmsg_error("(dump) cannot parse address %s\n", argv[2]);
progname, argv[2]);
return -1; return -1;
} else if (addr < 0 || addr >= maxsize) { } else if (addr < 0 || addr >= maxsize) {
terminal_message(MSG_INFO, "%s (dump): %s address 0x%05x is out of range [0, 0x%05x]\n", pmsg_error("(dump) %s address 0x%05x is out of range [0, 0x%05x]\n", mem->desc, addr, maxsize-1);
progname, mem->desc, addr, maxsize-1);
return -1; return -1;
} }
} }
@ -263,8 +271,7 @@ static int cmd_dump(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
} else if (argc == 4) { } else if (argc == 4) {
len = strtol(argv[3], &end_ptr, 0); len = strtol(argv[3], &end_ptr, 0);
if (*end_ptr || (end_ptr == argv[3])) { if (*end_ptr || (end_ptr == argv[3])) {
terminal_message(MSG_INFO, "%s (dump): can't parse length %s\n", pmsg_error("(dump) cannot parse length %s\n", argv[3]);
progname, argv[3]);
return -1; return -1;
} }
} else { } else {
@ -288,7 +295,7 @@ static int cmd_dump(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
uint8_t *buf = malloc(len); uint8_t *buf = malloc(len);
if (buf == NULL) { if (buf == NULL) {
terminal_message(MSG_INFO, "%s (dump): out of memory\n", progname); pmsg_error("(dump) out of memory\n");
return -1; 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]); int rc = pgm->read_byte_cached(pgm, p, mem, addr + i, &buf[i]);
if (rc != 0) { if (rc != 0) {
report_progress(1, -1, NULL); report_progress(1, -1, NULL);
terminal_message(MSG_INFO, "%s (dump): error reading %s address 0x%05lx of part %s\n", pmsg_error("(dump) error reading %s address 0x%05lx of part %s\n", mem->desc, (long) addr + i, p->desc);
progname, mem->desc, (long) addr + i, p->desc);
if (rc == -1) if (rc == -1)
terminal_message(MSG_INFO, "%*sread operation not supported on memory type %s\n", imsg_error("%*sread operation not supported on memory type %s\n", 7, "", mem->desc);
(int) strlen(progname)+9, "", mem->desc);
return -1; return -1;
} }
report_progress(i, len, NULL); 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); report_progress(1, 1, NULL);
hexdump_buf(stdout, addr, buf, len); hexdump_buf(stdout, addr, buf, len);
fprintf(stdout, "\n"); term_out("\n");
free(buf); 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[]) { static int cmd_write(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
if (argc < 4) { if (argc < 4) {
terminal_message(MSG_INFO, msg_error(
"Usage: write <memory> <addr> <data>[,] {<data>[,]}\n" "Usage: write <memory> <addr> <data>[,] {<data>[,]}\n"
" write <memory> <addr> <len> <data>[,] {<data>[,]} ...\n" " write <memory> <addr> <len> <data>[,] {<data>[,]} ...\n"
"\n" "\n"
@ -399,14 +404,13 @@ static int cmd_write(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
} }
int i; int i;
uint8_t write_mode; // Operation mode, "standard" or "fill" uint8_t write_mode; // Operation mode, "standard" or "fill"
uint8_t start_offset; // Which argc argument uint8_t start_offset; // Which argc argument
int len; // Number of bytes to write to memory int len; // Number of bytes to write to memory
char *memtype = argv[1]; // Memory name string char *memtype = argv[1]; // Memory name string
AVRMEM *mem = avr_locate_mem(p, memtype); AVRMEM *mem = avr_locate_mem(p, memtype);
if (mem == NULL) { if (mem == NULL) {
terminal_message(MSG_INFO, "%s (write): %s memory type not defined for part %s\n", pmsg_error("(write) %s memory type not defined for part %s\n", memtype, p->desc);
progname, memtype, p->desc);
return -1; return -1;
} }
int maxsize = mem->size; int maxsize = mem->size;
@ -414,21 +418,19 @@ static int cmd_write(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
char *end_ptr; char *end_ptr;
int addr = strtoul(argv[2], &end_ptr, 0); int addr = strtoul(argv[2], &end_ptr, 0);
if (*end_ptr || (end_ptr == argv[2])) { if (*end_ptr || (end_ptr == argv[2])) {
terminal_message(MSG_INFO, "%s (write): can't parse address %s\n", pmsg_error("(write) cannot parse address %s\n", argv[2]);
progname, argv[2]);
return -1; return -1;
} }
if (addr < 0 || addr >= maxsize) { if (addr < 0 || addr >= maxsize) {
terminal_message(MSG_INFO, "%s (write): %s address 0x%05x is out of range [0, 0x%05x]\n", pmsg_error("(write) %s address 0x%05x is out of range [0, 0x%05x]\n", mem->desc, addr, maxsize-1);
progname, mem->desc, addr, maxsize-1);
return -1; return -1;
} }
// Allocate a buffer guaranteed to be large enough // Allocate a buffer guaranteed to be large enough
uint8_t *buf = calloc(mem->size + 8 + maxstrlen(argc-3, argv+3)+1, sizeof(uint8_t)); uint8_t *buf = calloc(mem->size + 8 + maxstrlen(argc-3, argv+3)+1, sizeof(uint8_t));
if (buf == NULL) { if (buf == NULL) {
terminal_message(MSG_INFO, "%s (write): out of memory\n", progname); pmsg_error("(write) out of memory\n");
return -1; return -1;
} }
@ -438,8 +440,7 @@ static int cmd_write(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
start_offset = 4; start_offset = 4;
len = strtoul(argv[3], &end_ptr, 0); len = strtoul(argv[3], &end_ptr, 0);
if (*end_ptr || (end_ptr == argv[3])) { if (*end_ptr || (end_ptr == argv[3])) {
terminal_message(MSG_INFO, "%s (write ...): can't parse length %s\n", pmsg_error("(write ...) cannot parse length %s\n", argv[3]);
progname, argv[3]);
free(buf); free(buf);
return -1; 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) 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? " pmsg_error("(write) assumption on data types not met? "
"Check source and recompile\n", progname); "Check source and recompile\n");
bool is_big_endian = data.a[7]; bool is_big_endian = data.a[7];
for (i = start_offset; i < len + start_offset; i++) { 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; bool is_out_of_range = 0;
int nhexdigs = p-argi-2; 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); errno = 0; (void) strtoll(argi, NULL, 0);
is_outside_int64_t = errno == ERANGE; 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) if(is_outside_int64_t || is_out_of_range)
terminal_message(MSG_INFO, "%s (write): %s out of int%d_t range, " pmsg_error("(write) %s out of int%d_t range, "
"interpreted as %d-byte %lld; consider 'U' suffix\n", "interpreted as %d-byte %lld; consider 'U' suffix\n", argi, data.size*8, data.size, (long long int) data.ll);
progname, argi, data.size*8, data.size, data.ll);
} }
} }
} }
@ -583,8 +583,8 @@ static int cmd_write(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
data.f = strtof(argi, &end_ptr); data.f = strtof(argi, &end_ptr);
if (end_ptr != argi && toupper(*end_ptr) == 'F' && end_ptr[1] == 0) if (end_ptr != argi && toupper(*end_ptr) == 'F' && end_ptr[1] == 0)
data.size = 4; data.size = 4;
if (end_ptr != argi && *end_ptr == 0) // no suffix defaults to float but ... 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) // ... do not accept valid mantissa-only floats that are integer rejects (eg, 078 or ULL overflows)
if (!is_mantissa_only(argi)) if (!is_mantissa_only(argi))
data.size = 4; 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] == '\"')) { if ((*argi == '\'' && argi[arglen-1] == '\'') || (*argi == '\"' && argi[arglen-1] == '\"')) {
char *s = calloc(arglen-1, 1); char *s = calloc(arglen-1, 1);
if (s == NULL) { 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); free(buf);
return -1; return -1;
} }
// Strip start and end quotes, and unescape C string // Strip start and end quotes, and unescape C string
strncpy(s, argi+1, arglen-2); strncpy(s, argi+1, arglen-2);
cfg_unescape(s, s); cfg_unescape(s, s);
if (*argi == '\'') { // Single C-style character if (*argi == '\'') { // Single C-style character
if(*s && s[1]) if(*s && s[1])
terminal_message(MSG_INFO, "%s (write): only using first character of %s\n", pmsg_error("(write) only using first character of %s\n", argi);
progname, argi);
data.ll = *s; data.ll = *s;
data.size = 1; data.size = 1;
free(s); free(s);
} else { // C-style string } else { // C-style string
data.str_ptr = s; data.str_ptr = s;
} }
} }
} }
if(!data.size && !data.str_ptr) { if(!data.size && !data.str_ptr) {
terminal_message(MSG_INFO, "%s (write): can't parse data %s\n", pmsg_error("(write) cannot parse data %s\n", argi);
progname, argi);
free(buf); free(buf);
return -1; return -1;
} }
@ -644,8 +642,8 @@ static int cmd_write(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
data.bytes_grown = 0; data.bytes_grown = 0;
if ((addr + len + data.bytes_grown) > maxsize) { if ((addr + len + data.bytes_grown) > maxsize) {
terminal_message(MSG_INFO, "%s (write): selected address and # bytes exceed " pmsg_error("(write) selected address and # bytes exceed "
"range for %s memory\n", progname, memtype); "range for %s memory\n", memtype);
free(buf); free(buf);
return -1; return -1;
} }
@ -653,11 +651,11 @@ static int cmd_write(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
if(data.str_ptr) if(data.str_ptr)
free(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); len + data.bytes_grown, (long) addr);
if (write_mode == WRITE_MODE_FILL) if (write_mode == WRITE_MODE_FILL)
terminal_message(MSG_NOTICE, "; remaining space filled with %s", argv[argc - 2]); msg_notice2("; remaining space filled with %s", argv[argc - 2]);
terminal_message(MSG_NOTICE, "\n"); msg_notice2("\n");
pgm->err_led(pgm, OFF); pgm->err_led(pgm, OFF);
bool werror = false; 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++) { for (i = 0; i < len + data.bytes_grown; i++) {
int rc = pgm->write_byte_cached(pgm, p, mem, addr+i, buf[i]); int rc = pgm->write_byte_cached(pgm, p, mem, addr+i, buf[i]);
if (rc) { if (rc) {
terminal_message(MSG_INFO, "%s (write): error writing 0x%02x at 0x%05lx, rc=%d\n", pmsg_error("(write) error writing 0x%02x at 0x%05lx, rc=%d\n", buf[i], (long) addr+i, (int) rc);
progname, buf[i], (long) addr+i, (int) rc);
if (rc == -1) if (rc == -1)
terminal_message(MSG_INFO, "%*swrite operation not supported on memory type %s\n", imsg_error("%*swrite operation not supported on memory type %s\n", 8, "", mem->desc);
(int) strlen(progname)+10, "", mem->desc);
werror = true; werror = true;
} }
uint8_t b; uint8_t b;
rc = pgm->read_byte_cached(pgm, p, mem, addr+i, &b); rc = pgm->read_byte_cached(pgm, p, mem, addr+i, &b);
if (b != buf[i]) { if (b != buf[i]) {
terminal_message(MSG_INFO, "%s (write): error writing 0x%02x at 0x%05lx cell=0x%02x\n", pmsg_error("(write) error writing 0x%02x at 0x%05lx cell=0x%02x\n", buf[i], (long) addr+i, b);
progname, buf[i], (long) addr+i, b);
werror = true; werror = true;
} }
@ -713,14 +708,13 @@ static int cmd_send(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
int len; int len;
if (spi_mode && (pgm->spi == NULL)) { if (spi_mode && (pgm->spi == NULL)) {
terminal_message(MSG_INFO, "%s (send): the %s programmer does not support direct SPI transfers\n", pmsg_error("(send) the %s programmer does not support direct SPI transfers\n", pgm->type);
progname, pgm->type);
return -1; return -1;
} }
if ((argc > 5) || ((argc < 5) && (!spi_mode))) { if ((argc > 5) || ((argc < 5) && (!spi_mode))) {
terminal_message(MSG_INFO, spi_mode? msg_error(spi_mode?
"Usage: send <byte1> [<byte2> [<byte3> [<byte4>]]]\n": "Usage: send <byte1> [<byte2> [<byte3> [<byte4>]]]\n":
"Usage: send <byte1> <byte2> <byte3> <byte4>\n"); "Usage: send <byte1> <byte2> <byte3> <byte4>\n");
return -1; return -1;
@ -733,8 +727,7 @@ static int cmd_send(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
for (i=1; i<argc; i++) { for (i=1; i<argc; i++) {
cmd[i-1] = strtoul(argv[i], &e, 0); cmd[i-1] = strtoul(argv[i], &e, 0);
if (*e || (e == argv[i])) { if (*e || (e == argv[i])) {
terminal_message(MSG_INFO, "%s (send): can't parse byte %s\n", pmsg_error("(send) cannot parse byte %s\n", argv[i]);
progname, argv[i]);
return -1; return -1;
} }
} }
@ -749,19 +742,17 @@ static int cmd_send(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
/* /*
* display results * display results
*/ */
terminal_message(MSG_INFO, "results:"); term_out("results:");
for (i=0; i<len; i++) for (i=0; i<len; i++)
terminal_message(MSG_INFO, " %02x", res[i]); term_out(" %02x", res[i]);
terminal_message(MSG_INFO, "\n"); term_out("\n\n");
fprintf(stdout, "\n");
return 0; return 0;
} }
static int cmd_erase(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { static int cmd_erase(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
terminal_message(MSG_INFO, "%s: erasing chip\n", progname); term_out("erasing chip ...\n");
// Erase chip and clear cache // Erase chip and clear cache
pgm->chip_erase_cached(pgm, p); pgm->chip_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[]) { static int cmd_pgerase(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
if(argc < 3) { if(argc < 3) {
terminal_message(MSG_INFO, "Usage: pgerase <memory> <addr>\n"); msg_error("Usage: pgerase <memory> <addr>\n");
return -1; return -1;
} }
char *memtype = argv[1]; char *memtype = argv[1];
AVRMEM *mem = avr_locate_mem(p, memtype); AVRMEM *mem = avr_locate_mem(p, memtype);
if(!mem) { if(!mem) {
terminal_message(MSG_INFO, "%s (pgerase): %s memory type not defined for part %s\n", pmsg_error("(pgerase) %s memory type not defined for part %s\n", memtype, p->desc);
progname, memtype, p->desc);
return -1; return -1;
} }
if(!avr_has_paged_access(pgm, mem)) { if(!avr_has_paged_access(pgm, mem)) {
terminal_message(MSG_INFO, "%s (pgerase): %s memory cannot be paged addressed by %s\n", pmsg_error("(pgerase) %s memory cannot be paged addressed by %s\n", memtype, (char *) ldata(lfirst(pgm->id)));
progname, memtype, ldata(lfirst(pgm->id)));
return -1; return -1;
} }
@ -793,21 +782,17 @@ static int cmd_pgerase(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
char *end_ptr; char *end_ptr;
int addr = strtoul(argv[2], &end_ptr, 0); int addr = strtoul(argv[2], &end_ptr, 0);
if(*end_ptr || (end_ptr == argv[2])) { if(*end_ptr || (end_ptr == argv[2])) {
terminal_message(MSG_INFO, "%s (pgerase): can't parse address %s\n", pmsg_error("(pgerase) cannot parse address %s\n", argv[2]);
progname, argv[2]);
return -1; return -1;
} }
if (addr < 0 || addr >= maxsize) { if (addr < 0 || addr >= maxsize) {
terminal_message(MSG_INFO, "%s (pgerase): %s address 0x%05x is out of range [0, 0x%05x]\n", pmsg_error("(pgerase) %s address 0x%05x is out of range [0, 0x%05x]\n", mem->desc, addr, maxsize-1);
progname, mem->desc, addr, maxsize-1);
return -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) { 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", pmsg_error("(pgerase) unable to erase %s page at 0x%05x\n", mem->desc, addr);
progname, mem->desc, addr);
return -1; 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[]) { static int cmd_part(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
fprintf(stdout, "\n"); term_out("\n");
avr_display(stdout, p, "", 0); avr_display(stdout, p, "", 0);
fprintf(stdout, "\n"); term_out("\n");
return 0; return 0;
} }
@ -831,20 +816,18 @@ static int cmd_sig(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
rc = avr_signature(pgm, p); rc = avr_signature(pgm, p);
if (rc != 0) { if (rc != 0) {
terminal_message(MSG_INFO, "%s (sig): error reading signature data, rc=%d\n", pmsg_error("(sig) error reading signature data, rc=%d\n", rc);
progname, rc);
} }
m = avr_locate_mem(p, "signature"); m = avr_locate_mem(p, "signature");
if (m == NULL) { if (m == NULL) {
terminal_message(MSG_INFO, "%s (sig): signature data not defined for device %s\n", pmsg_error("(sig) signature data not defined for device %s\n", p->desc);
progname, p->desc);
} }
else { else {
fprintf(stdout, "Device signature = 0x"); term_out("Device signature = 0x");
for (i=0; i<m->size; i++) for (i=0; i<m->size; i++)
fprintf(stdout, "%02x", m->buf[i]); term_out("%02x", m->buf[i]);
fprintf(stdout, "\n\n"); term_out("\n\n");
} }
return 0; 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[]) { static int cmd_parms(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
pgm->print_parms(pgm); pgm->print_parms(pgm, stdout);
terminal_message(MSG_INFO, "\n"); term_out("\n");
return 0; return 0;
} }
@ -873,18 +856,16 @@ static int cmd_vtarg(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
char *endp; char *endp;
if (argc != 2) { if (argc != 2) {
terminal_message(MSG_INFO, "Usage: vtarg <value>\n"); msg_error("Usage: vtarg <value>\n");
return -1; return -1;
} }
v = strtod(argv[1], &endp); v = strtod(argv[1], &endp);
if (endp == argv[1]) { if (endp == argv[1]) {
terminal_message(MSG_INFO, "%s (vtarg): can't parse voltage %s\n", pmsg_error("(vtarg) cannot parse voltage %s\n", argv[1]);
progname, argv[1]);
return -1; return -1;
} }
if ((rc = pgm->set_vtarget(pgm, v)) != 0) { if ((rc = pgm->set_vtarget(pgm, v)) != 0) {
terminal_message(MSG_INFO, "%s (vtarg): unable to set V[target] (rc = %d)\n", pmsg_error("(vtarg) unable to set V[target] (rc = %d)\n", rc);
progname, rc);
return -3; return -3;
} }
return 0; return 0;
@ -897,7 +878,7 @@ static int cmd_fosc(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
char *endp; char *endp;
if (argc != 2) { if (argc != 2) {
terminal_message(MSG_INFO, "Usage: fosc <value>[M|k] | off\n"); msg_error("Usage: fosc <value>[M|k] | off\n");
return -1; return -1;
} }
v = strtod(argv[1], &endp); 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) if (strcmp(argv[1], "off") == 0)
v = 0.0; v = 0.0;
else { else {
terminal_message(MSG_INFO, "%s (fosc): can't parse frequency %s\n", pmsg_error("(fosc) cannot parse frequency %s\n", argv[1]);
progname, argv[1]);
return -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') else if (*endp == 'k' || *endp == 'K')
v *= 1e3; v *= 1e3;
if ((rc = pgm->set_fosc(pgm, v)) != 0) { if ((rc = pgm->set_fosc(pgm, v)) != 0) {
terminal_message(MSG_INFO, "%s (fosc): unable to set oscillator frequency (rc = %d)\n", pmsg_error("(fosc) unable to set oscillator frequency (rc = %d)\n", rc);
progname, rc);
return -3; return -3;
} }
return 0; return 0;
@ -929,19 +908,17 @@ static int cmd_sck(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
char *endp; char *endp;
if (argc != 2) { if (argc != 2) {
terminal_message(MSG_INFO, "Usage: sck <value>\n"); msg_error("Usage: sck <value>\n");
return -1; return -1;
} }
v = strtod(argv[1], &endp); v = strtod(argv[1], &endp);
if (endp == argv[1]) { if (endp == argv[1]) {
terminal_message(MSG_INFO, "%s (sck): can't parse period %s\n", pmsg_error("(sck) cannot parse period %s\n", argv[1]);
progname, argv[1]);
return -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) { if ((rc = pgm->set_sck_period(pgm, v)) != 0) {
terminal_message(MSG_INFO, "%s (sck): unable to set SCK period (rc = %d)\n", pmsg_error("(sck) unable to set SCK period (rc = %d)\n", rc);
progname, rc);
return -3; return -3;
} }
return 0; return 0;
@ -955,34 +932,30 @@ static int cmd_varef(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
char *endp; char *endp;
if (argc != 2 && argc != 3) { if (argc != 2 && argc != 3) {
terminal_message(MSG_INFO, "Usage: varef [channel] <value>\n"); msg_error("Usage: varef [channel] <value>\n");
return -1; return -1;
} }
if (argc == 2) { if (argc == 2) {
chan = 0; chan = 0;
v = strtod(argv[1], &endp); v = strtod(argv[1], &endp);
if (endp == argv[1]) { if (endp == argv[1]) {
terminal_message(MSG_INFO, "%s (varef): can't parse voltage %s\n", pmsg_error("(varef) cannot parse voltage %s\n", argv[1]);
progname, argv[1]);
return -1; return -1;
} }
} else { } else {
chan = strtoul(argv[1], &endp, 10); chan = strtoul(argv[1], &endp, 10);
if (endp == argv[1]) { if (endp == argv[1]) {
terminal_message(MSG_INFO, "%s (varef): can't parse channel %s\n", pmsg_error("(varef) cannot parse channel %s\n", argv[1]);
progname, argv[1]);
return -1; return -1;
} }
v = strtod(argv[2], &endp); v = strtod(argv[2], &endp);
if (endp == argv[2]) { if (endp == argv[2]) {
terminal_message(MSG_INFO, "%s (varef): can't parse voltage %s\n", pmsg_error("(varef) cannot parse voltage %s\n", argv[2]);
progname, argv[2]);
return -1; return -1;
} }
} }
if ((rc = pgm->set_varef(pgm, chan, v)) != 0) { if ((rc = pgm->set_varef(pgm, chan, v)) != 0) {
terminal_message(MSG_INFO, "%s (varef): unable to set V[aref] (rc = %d)\n", pmsg_error("(varef) unable to set V[aref] (rc = %d)\n", rc);
progname, rc);
return -3; return -3;
} }
return 0; 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[]) { static int cmd_help(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
int i; int i;
fprintf(stdout, "Valid commands:\n"); term_out("Valid commands:\n");
for (i=0; i<NCMDS; i++) { for (i=0; i<NCMDS; i++) {
if(!*(void (**)(void)) ((char *) pgm + cmd[i].fnoff)) if(!*(void (**)(void)) ((char *) pgm + cmd[i].fnoff))
continue; continue;
fprintf(stdout, " %-7s : ", cmd[i].name); term_out(" %-7s : ", cmd[i].name);
fprintf(stdout, cmd[i].desc, cmd[i].name); term_out(cmd[i].desc, cmd[i].name);
fprintf(stdout, "\n"); term_out("\n");
} }
fprintf(stdout, "\n" term_out("\n"
"Note that not all programmer derivatives support all commands. Flash and\n" "Note that not all programmer derivatives support all commands. Flash and\n"
"EEPROM type memories are normally read and written using a cache via paged\n" "EEPROM type memories are normally read and written using a cache via paged\n"
"read and write access; the cache is synchronised on quit. Use the part\n" "read and write access; the cache is synchronised on quit or flush commands.\n"
"command to display valid memory types for use with dump and write.\n\n"); "The part command displays valid memory types for use with dump and write.\n\n");
return 0; return 0;
} }
@ -1026,26 +999,24 @@ static int cmd_verbose(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
char *endp; char *endp;
if (argc != 1 && argc != 2) { if (argc != 1 && argc != 2) {
terminal_message(MSG_INFO, "Usage: verbose [<value>]\n"); msg_error("Usage: verbose [<value>]\n");
return -1; return -1;
} }
if (argc == 1) { if (argc == 1) {
terminal_message(MSG_INFO, "Verbosity level: %d\n", verbose); msg_error("Verbosity level: %d\n", verbose);
return 0; return 0;
} }
nverb = strtol(argv[1], &endp, 0); nverb = strtol(argv[1], &endp, 0);
if (endp == argv[1] || *endp) { if (endp == argv[1] || *endp) {
terminal_message(MSG_INFO, "%s (verbose): can't parse verbosity level %s\n", pmsg_error("(verbose) cannot parse verbosity level %s\n", argv[1]);
progname, argv[1]);
return -1; return -1;
} }
if (nverb < 0) { if (nverb < 0) {
terminal_message(MSG_INFO, "%s: verbosity level must not be negative: %d\n", pmsg_error("(verbose) level must not be negative: %d\n", nverb);
progname, nverb);
return -1; return -1;
} }
verbose = nverb; verbose = nverb;
terminal_message(MSG_INFO, "New verbosity level: %d\n", verbose); term_out("New verbosity level: %d\n", verbose);
return 0; return 0;
} }
@ -1055,26 +1026,24 @@ static int cmd_quell(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
char *endp; char *endp;
if (argc != 1 && argc != 2) { if (argc != 1 && argc != 2) {
terminal_message(MSG_INFO, "Usage: quell [<value>]\n"); msg_error("Usage: quell [<value>]\n");
return -1; return -1;
} }
if (argc == 1) { if (argc == 1) {
terminal_message(MSG_INFO, "Quell level: %d\n", quell_progress); msg_error("Quell level: %d\n", quell_progress);
return 0; return 0;
} }
nquell = strtol(argv[1], &endp, 0); nquell = strtol(argv[1], &endp, 0);
if (endp == argv[1] || *endp) { if (endp == argv[1] || *endp) {
terminal_message(MSG_INFO, "%s (quell): can't parse quell level %s\n", pmsg_error("(quell) cannot parse quell level %s\n", argv[1]);
progname, argv[1]);
return -1; return -1;
} }
if (nquell < 0) { if (nquell < 0) {
terminal_message(MSG_INFO, "%s: quell level must not be negative: %d\n", pmsg_error("(quell) level must not be negative: %d\n", nquell);
progname, nquell);
return -1; return -1;
} }
quell_progress = nquell; 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) if(quell_progress > 0)
update_progress = NULL; 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); return cmd[i].func(pgm, p, argc, argv);
if (len && strncasecmp(argv[0], cmd[i].name, len)==0) { if (len && strncasecmp(argv[0], cmd[i].name, len)==0) {
if (hold != -1) { if (hold != -1) {
terminal_message(MSG_INFO, "%s (cmd): command %s is ambiguous\n", pmsg_error("(cmd) command %s is ambiguous\n", argv[0]);
progname, argv[0]);
return -1; return -1;
} }
hold = i; hold = i;
@ -1206,104 +1174,177 @@ static int do_cmd(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
if (hold != -1) if (hold != -1)
return cmd[hold].func(pgm, p, argc, argv); return cmd[hold].func(pgm, p, argc, argv);
terminal_message(MSG_INFO, "%s (cmd): invalid command %s\n", pmsg_error("(cmd) invalid command %s\n", argv[0]);
progname, argv[0]);
return -1; return -1;
} }
char *terminal_get_input(const char *prompt) { 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]; char input[256];
fprintf(stdout, "%s", prompt);
if (fgets(input, sizeof(input), stdin)) term_out("%s", prompt);
{ if(fgets(input, sizeof(input), stdin)) {
/* FIXME: readline strips the '\n', should this too? */ int len = strlen(input);
return strdup(input); if(len > 0 && input[len-1] == '\n')
input[len-1] = 0;
return cfg_strdup(__func__, input);
} }
else
return NULL; return NULL;
#endif
} }
int terminal_mode(PROGRAMMER *pgm, AVRPART *p) { static int process_line(char *cmdbuf, PROGRAMMER *pgm, struct avrpart *p) {
char *cmdbuf; int argc, rc;
char *q; char **argv = NULL, *q;
int rc;
int argc;
char **argv;
rc = 0; // Find the start of the command, skipping any white space
while ((cmdbuf = terminal_get_input("avrdude> ")) != NULL) { q = cmdbuf;
/* while(*q && isspace((unsigned char) *q))
* find the start of the command, skipping any white space q++;
*/
q = cmdbuf;
while (*q && isspace((unsigned char) *q))
q++;
/* skip blank lines and comments */ // Skip blank lines and comments
if (!*q || (*q == '#')) if (!*q || (*q == '#'))
continue; return 0;
/* tokenize command line */ // Tokenize command line
argc = tokenize(q, &argv); argc = tokenize(q, &argv);
if (argc < 0) {
free(cmdbuf); if(!argv)
return argc; return -1;
}
#if !defined(HAVE_LIBREADLINE) || defined(WIN32) || defined(__APPLE__) #if !defined(HAVE_LIBREADLINE) || defined(WIN32) || defined(__APPLE__)
fprintf(stdout, ">>> "); term_out(">>> ");
for (int i=0; i<argc; i++) for (int i=0; i<argc; i++)
fprintf(stdout, "%s ", argv[i]); term_out("%s ", argv[i]);
fprintf(stdout, "\n"); term_out("\n");
#endif #endif
/* run the command */ // Run the command
rc = do_cmd(pgm, p, argc, argv); rc = do_cmd(pgm, p, argc, argv);
free(argv); free(argv);
if (rc > 0) {
rc = 0; return rc;
break; }
#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; int rc = 0;
va_list ap;
fflush(stdout); fflush(stderr); while((cmdbuf = terminal_get_input("avrdude> "))) {
if (verbose >= msglvl) { int rc = process_line(cmdbuf, pgm, p);
va_start(ap, format); free(cmdbuf);
rc = vfprintf(stderr, format, ap); if(rc > 0)
va_end(ap); 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 void update_progress_tty(int percent, double etime, const char *hdr, int finish) {
static char *header; static char *header;
static int last, done; static int last, done = 1;
int i; int i;
setvbuf(stderr, (char *) NULL, _IONBF, 0); 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[i/2] = '#';
hashes[50] = 0; 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(percent == 100) {
if(finish) if(finish)
msg_info("\n\n"); 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 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); setvbuf(stderr, (char *) NULL, _IONBF, 0);

View File

@ -35,7 +35,6 @@ typedef enum {
int terminal_mode(PROGRAMMER * pgm, struct avrpart * p); int terminal_mode(PROGRAMMER * pgm, struct avrpart * p);
char * terminal_get_input(const char *prompt); char * terminal_get_input(const char *prompt);
void terminal_setup_update_progress(); void terminal_setup_update_progress();
int terminal_message(const int msglvl, const char *format, ...);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -335,11 +335,11 @@ int update_is_readable(const char *fn) {
static void ioerror(const char *iotype, UPDATE *upd) { static void ioerror(const char *iotype, UPDATE *upd) {
int errnocp = errno; 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) if(errnocp)
msg_ext_error("memstats(): %s", strerror(errnocp)); msg_ext_error("%s", strerror(errnocp));
else if(upd->filename && *upd->filename) 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"); 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); 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); rc = avr_read(pgm, p, upd->memtype, 0);
report_progress(1, 1, NULL); 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); update_plural(fs.nbytes), mem->desc, alias_mem_desc);
if (!(flags & UF_NOWRITE)) { 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); rc = avr_write(pgm, p, upd->memtype, size, (flags & UF_AUTO_ERASE) != 0);
report_progress(1, 1, NULL); report_progress(1, 1, NULL);
} else { } 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); 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); rc = avr_read(pgm, p, upd->memtype, v);
report_progress (1,1,NULL); report_progress (1,1,NULL);
if (rc < 0) { if (rc < 0) {

View File

@ -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 * right-to-left, so only the least significant nibbles need to be
* specified. * specified.
*/ */
if ((serno = strchr(port, ':')) != NULL) if ((serno = strchr(port, ':')) != NULL) {
{ /* First, drop all colons there if any */
/* first, drop all colons there if any */ cp2 = ++serno;
cp2 = ++serno;
while ((cp2 = strchr(cp2, ':')) != NULL) while ((cp2 = strchr(cp2, ':')) != NULL) {
{ x = strlen(cp2) - 1;
x = strlen(cp2) - 1; memmove(cp2, cp2 + 1, x);
memmove(cp2, cp2 + 1, x); cp2[x] = '\0';
cp2[x] = '\0'; }
}
if (strlen(serno) > 12) if (strlen(serno) > 12) {
{ pmsg_error("invalid serial number %s\n", serno);
pmsg_error("invalid serial number %s\n", serno); return -1;
return -1; }
}
wchar_t wserno[15]; wchar_t wserno[15];
mbstowcs(wserno, serno, 15); mbstowcs(wserno, serno, 15);
size_t serlen = strlen(serno); size_t serlen = strlen(serno);
/* /*
* Now, try finding all devices matching VID:PID, and compare * Now, try finding all devices matching VID:PID, and compare
* their serial numbers against the requested one. * their serial numbers against the requested one.
*/ */
struct hid_device_info *list, *walk; struct hid_device_info *list, *walk;
list = hid_enumerate(pinfo.usbinfo.vid, pinfo.usbinfo.pid); list = hid_enumerate(pinfo.usbinfo.vid, pinfo.usbinfo.pid);
if (list == NULL) if (list == NULL) {
return -1; pmsg_error("No USB HID devices found\n");
return -1;
}
walk = list; walk = list;
while (walk) 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); /* Found matching serial number */
size_t slen = wcslen(walk->serial_number); break;
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;
} }
if (walk == NULL) pmsg_debug("usbhid_open(): serial number does not match\n");
{ walk = walk->next;
pmsg_error("no matching device found\n"); }
hid_free_enumeration(list); if (walk == NULL) {
return -1; pmsg_error("no matching device found\n");
}
pmsg_debug("usbhid_open(): opening path %s\n", walk->path);
dev = hid_open_path(walk->path);
hid_free_enumeration(list); hid_free_enumeration(list);
if (dev == NULL) return -1;
{
pmsg_error("found device, but hid_open_path() failed\n");
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)
{ {
/* pmsg_warning("USB device with VID: 0x%04x and PID: 0x%04x not found\n",
* No serial number requested, pass straight to hid_open() pinfo.usbinfo.vid, pinfo.usbinfo.pid);
*/ return -1;
dev = hid_open(pinfo.usbinfo.vid, pinfo.usbinfo.pid, NULL);
if (dev == NULL)
{
pmsg_error("no device found\n");
return -1;
}
} }
}
fd->usb.handle = dev; 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 * be incremented by one, as the report ID will be omitted by the
* hidapi library. * hidapi library.
*/ */
if (pinfo.usbinfo.vid == USB_VENDOR_ATMEL) if (pinfo.usbinfo.vid == USB_VENDOR_ATMEL) {
{ pmsg_debug("usbhid_open(): probing for max packet size\n");
pmsg_debug("usbhid_open(): probing for max packet size\n"); memset(usbbuf, 0, sizeof usbbuf);
memset(usbbuf, 0, sizeof usbbuf); usbbuf[0] = 0; /* no HID reports used */
usbbuf[0] = 0; /* no HID reports used */ usbbuf[1] = 0; /* DAP_Info */
usbbuf[1] = 0; /* DAP_Info */ usbbuf[2] = 0xFF; /* get max. packet size */
usbbuf[2] = 0xFF; /* get max. packet size */
hid_write(dev, usbbuf, 65); hid_write(dev, usbbuf, 65);
fd->usb.max_xfer = 64; /* first guess */ fd->usb.max_xfer = 64; /* first guess */
memset(usbbuf, 0, sizeof usbbuf); memset(usbbuf, 0, sizeof usbbuf);
int res = hid_read_timeout(dev, usbbuf, 10 /* bytes */, 50 /* milliseconds */); int res = hid_read_timeout(dev, usbbuf, 10 /* bytes */, 50 /* milliseconds */);
if (res == 0) { if (res == 0) {
/* no timely response, assume 512 byte size */ /* No timely response, assume 512 byte size */
hid_write(dev, usbbuf, (512 - 64) + 1); hid_write(dev, usbbuf, (512 - 64) + 1);
fd->usb.max_xfer = 512; fd->usb.max_xfer = 512;
res = hid_read_timeout(dev, usbbuf, 10, 50); 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 (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) { if (fd->usb.max_xfer > USBDEV_MAX_XFER_3) {
pmsg_error("unexpected max size %d, reducing to %d\n", pmsg_error("unexpected max size %d, reducing to %d\n",
fd->usb.max_xfer, USBDEV_MAX_XFER_3); 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; return 0;
} }
static void usbhid_close(union filedescriptor *fd) static void usbhid_close(union filedescriptor *fd) {
{
hid_device *udev = (hid_device *)fd->usb.handle; hid_device *udev = (hid_device *)fd->usb.handle;
if (udev == NULL) 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; hid_device *udev = (hid_device *)fd->usb.handle;
int rv; int rv;
int i = mlen; int i = mlen;
const unsigned char * p = bp; const unsigned char * p = bp;
unsigned char usbbuf[USBDEV_MAX_XFER_3 + 1]; unsigned char usbbuf[USBDEV_MAX_XFER_3 + 1];
int tx_size; int tx_size;
if (udev == NULL) if (udev == NULL)
return -1; return -1;
tx_size = (mlen < USBDEV_MAX_XFER_3)? mlen: USBDEV_MAX_XFER_3; 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); memcpy(usbbuf + 1, bp, tx_size);
rv = hid_write(udev, usbbuf, tx_size + 1); rv = hid_write(udev, usbbuf, tx_size + 1);
if (rv < 0) { if (rv < 0) {
@ -244,30 +232,26 @@ static int usbhid_send(const union filedescriptor *fd, const unsigned char *bp,
if (rv != tx_size + 1) if (rv != tx_size + 1)
pmsg_error("short write to USB: %d bytes out of %d written\n", rv, tx_size + 1); pmsg_error("short write to USB: %d bytes out of %d written\n", rv, tx_size + 1);
if (verbose > 4) if (verbose > 4) {
{ pmsg_trace2("sent: ");
pmsg_trace2("sent: ");
while (i) { while (i) {
unsigned char c = *p; unsigned char c = *p;
if (isprint(c)) { if (isprint(c))
msg_trace2("%c ", c); msg_trace2("%c ", c);
} else
else { msg_trace2(". ");
msg_trace2(". "); msg_trace2("[%02x] ", c);
}
msg_trace2("[%02x] ", c);
p++; p++;
i--; i--;
} }
msg_trace2("\n"); msg_trace2("\n");
} }
return 0; 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; hid_device *udev = (hid_device *)fd->usb.handle;
int i, rv; int i, rv;
unsigned char * p = buf; unsigned char * p = buf;
@ -279,31 +263,26 @@ static int usbhid_recv(const union filedescriptor *fd, unsigned char *buf, size_
if (i != nbytes) if (i != nbytes)
pmsg_error("short read, read only %d out of %lu bytes\n", i, (unsigned long) nbytes); pmsg_error("short read, read only %d out of %lu bytes\n", i, (unsigned long) nbytes);
if (verbose > 4) if (verbose > 4) {
{ pmsg_trace2("recv: ");
pmsg_trace2("recv: ");
while (i) { while (i) {
unsigned char c = *p; unsigned char c = *p;
if (isprint(c)) { if (isprint(c))
msg_trace2("%c ", c); msg_trace2("%c ", c);
} else
else { msg_trace2(". ");
msg_trace2(". "); msg_trace2("[%02x] ", c);
}
msg_trace2("[%02x] ", c);
p++; p++;
i--; i--;
} }
msg_trace2("\n"); msg_trace2("\n");
} }
return rv; 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 * There is not much point in trying to flush any data
* on an USB endpoint, as the endpoint is supposed to * 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. * Device descriptor.
*/ */
struct serial_device usbhid_serdev = struct serial_device usbhid_serdev = {
{
.open = usbhid_open, .open = usbhid_open,
.close = usbhid_close, .close = usbhid_close,
.send = usbhid_send, .send = usbhid_send,

View File

@ -25,19 +25,28 @@
#ifndef usbdevs_h #ifndef usbdevs_h
#define usbdevs_h #define usbdevs_h
#define USB_VENDOR_ATMEL 1003 #define USB_VENDOR_ATMEL 0x03EB
#define USB_DEVICE_JTAGICEMKII 0x2103 #define USB_VENDOR_MICROCHIP 0x04D8
#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_FTDI 0x0403 #define USB_DEVICE_JTAGICEMKII 0x2103
#define USB_DEVICE_FT2232 0x6010 #define USB_DEVICE_AVRISPMKII 0x2104
#define USB_DEVICE_FT245 0x6001 #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_VID 0x16C0 /* VOTI */
#define USBASP_SHARED_PID 0x05DC /* Obdev's free shared PID */ #define USBASP_SHARED_PID 0x05DC /* Obdev's free shared PID */