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

16
NEWS
View File

@ -58,6 +58,12 @@ Changes since version 7.0:
- Make UPDI programmers less verbose during initialization
#1084
- Quell mode isn't handled systematically #1114
- Mixing the progress bar with warning messages #1136
- Inconsistent terminal output re stdout and stderr #1130
- Supress the warning for Microchip SNAP #1135
- ATtiny85 communication problem with default bitclock #1133
- [Regression] Optiboot for "modern AVRs" no longer works #1120
- Cannot access EEPROM on some bootloader/part combos #970
* Pull requests:
@ -153,6 +159,16 @@ Changes since version 7.0:
- Suppress Teensy USB communication error message on reboot #1122
- Fix UPDI erase when target is locked #1125
- Review and overhaul AVRDUDE's messaging system #1126
- Look for ~/.config/avrdude/avrdude.rc then ~/.avrduderc #1131
- Revamp terminal output (progress bar, callback and
stdout/stderr) #1132
- Detect PICkit4 and SNAP in PIC mode #1138
- Mention -B in the error message #1139
- Support optiboot, optiboot_dx and optiboot_x bootloaders for
-c arduino #1140
- Always use paged access for programmers that serve
bootloaders #1141
- Add libreadline-dev for Linux github action build #1146
* Internals:

View File

@ -53,9 +53,9 @@ case "${ostype}" in
# Apple M1 (may be new version of homebrew also)
if [ -d /opt/homebrew ]
then
build_flags="${build_flags} -D CMAKE_C_FLAGS=-I/opt/homebrew/include -D CMAKE_EXE_LINKER_FLAGS=-L/opt/homebrew/Cellar"
build_flags="${build_flags} -D CMAKE_C_FLAGS=-I/opt/homebrew/include -D CMAKE_EXE_LINKER_FLAGS=-L/opt/homebrew/Cellar -D HAVE_LIBREADLINE:FILEPATH=/opt/homebrew/lib/libreadline.dylib"
else
build_flags="${build_flags} -D CMAKE_C_FLAGS=-I/usr/local/include -D CMAKE_EXE_LINKER_FLAGS=-L/usr/local/Cellar"
build_flags="${build_flags} -D CMAKE_C_FLAGS=-I/usr/local/include -D CMAKE_EXE_LINKER_FLAGS=-L/usr/local/Cellar -D HAVE_LIBREADLINE:FILEPATH=/usr/local/lib/libreadline.dylib"
fi
fi
;;

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);
}
if (pgm->paged_load != NULL && mem->page_size > 1 &&
mem->size % mem->page_size == 0) {
// HW programmers need a page size > 1, bootloader typ only offer paged r/w
if ((pgm->paged_load && mem->page_size > 1 && mem->size % mem->page_size == 0) ||
((pgm->prog_modes & PM_SPM) && avr_has_paged_access(pgm, mem))) {
/*
* the programmer supports a paged mode read
*/
@ -894,7 +895,9 @@ int avr_write_mem(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m, int
return i;
}
if (pgm->paged_write != NULL && m->page_size > 1) {
// HW programmers need a page size > 1, bootloader typ only offer paged r/w
if ((pgm->paged_load && m->page_size > 1 && m->size % m->page_size == 0) ||
((pgm->prog_modes & PM_SPM) && avr_has_paged_access(pgm, m))) {
/*
* the programmer supports a paged mode write
*/
@ -1036,13 +1039,14 @@ int avr_write_mem(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m, int
int avr_signature(const PROGRAMMER *pgm, const AVRPART *p) {
int rc;
report_progress (0,1,"Reading");
if(verbose > 1)
report_progress(0, 1, "Reading");
rc = avr_read(pgm, p, "signature", 0);
if (rc < LIBAVRDUDE_SUCCESS) {
pmsg_error("unable to read signature data for part %s, rc=%d\n", p->desc, rc);
return rc;
}
report_progress (1,1,NULL);
report_progress(1, 1, NULL);
return LIBAVRDUDE_SUCCESS;
}

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
* - Caller to ensure buf has mem->page_size bytes
@ -141,14 +144,14 @@ int avr_read_page_default(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM
unsigned char *pagecopy = cfg_malloc("avr_read_page_default()", pgsize);
if(pgsize == 1)
return pgm->read_byte(pgm, p, mem, addr, buf);
return fallback_read_byte(pgm, p, mem, addr, buf);
memcpy(pagecopy, mem->buf + base, pgsize);
if((rc = pgm->paged_load(pgm, p, mem, pgsize, base, pgsize)) >= 0)
memcpy(buf, mem->buf + base, pgsize);
memcpy(mem->buf + base, pagecopy, pgsize);
if(rc < 0) {
if(rc < 0 && pgm->read_byte != avr_read_byte_cached) {
rc = LIBAVRDUDE_SUCCESS;
for(int i=0; i<pgsize; i++) {
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);
if(pgsize == 1)
return pgm->write_byte(pgm, p, mem, addr, *data);
return fallback_write_byte(pgm, p, mem, addr, *data);
memcpy(pagecopy, mem->buf + base, pgsize);
memcpy(mem->buf + base, data, pgsize);
@ -261,18 +264,25 @@ static int loadCachePage(AVR_Cache *cp, const PROGRAMMER *pgm, const AVRPART *p,
static int writeCachePage(AVR_Cache *cp, const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, int base, int nlOnErr) {
// Write modified page cont to device; if unsuccessful try bytewise access
if(avr_write_page_default(pgm, p, mem, base, cp->cont + base) < 0) {
for(int i=0; i < cp->page_size; i++)
if(cp->cont[base+i] != cp->copy[base+i])
if(pgm->write_byte(pgm, p, mem, base+i, cp->cont[base+i]) < 0 ||
pgm->read_byte(pgm, p, mem, base+i, cp->copy+base+i) < 0) {
report_progress(1, -1, NULL);
if(nlOnErr && quell_progress)
msg_info("\n");
pmsg_error("writeCachePage() %s access error at addr 0x%04x\n", mem->desc, base+i);
return LIBAVRDUDE_GENERAL_FAILURE;
}
if(pgm->read_byte != avr_read_byte_cached && pgm->write_byte != avr_write_byte_cached) {
for(int i=0; i < cp->page_size; i++)
if(cp->cont[base+i] != cp->copy[base+i])
if(pgm->write_byte(pgm, p, mem, base+i, cp->cont[base+i]) < 0 ||
pgm->read_byte(pgm, p, mem, base+i, cp->copy+base+i) < 0) {
report_progress(1, -1, NULL);
if(nlOnErr && quell_progress)
msg_info("\n");
pmsg_error("%s access error at addr 0x%04x\n", mem->desc, base+i);
return LIBAVRDUDE_GENERAL_FAILURE;
}
return LIBAVRDUDE_SUCCESS; // Bytewise writes & reads successful
return LIBAVRDUDE_SUCCESS; // Bytewise writes & reads successful
}
report_progress(1, -1, NULL);
if(nlOnErr && quell_progress)
msg_info("\n");
pmsg_error("write %s page error at addr 0x%04x\n", mem->desc, base);
return LIBAVRDUDE_GENERAL_FAILURE;
}
// Read page back from device and update copy to what is on device
if(avr_read_page_default(pgm, p, mem, base, cp->copy + base) < 0) {
@ -552,7 +562,7 @@ int avr_read_byte_cached(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *
// Use pgm->read_byte() if not EEPROM/flash or no paged access
if(!avr_has_paged_access(pgm, mem))
return pgm->read_byte(pgm, p, mem, addr, value);
return fallback_read_byte(pgm, p, mem, addr, value);
// If address is out of range synchronise cache and, if successful, pretend reading a zero
if(addr >= (unsigned long) mem->size) {
@ -592,9 +602,9 @@ int avr_read_byte_cached(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *
int avr_write_byte_cached(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem,
unsigned long addr, unsigned char data) {
// Use pgm->read_byte() if not EEPROM/flash or no paged access
// Use pgm->write_byte() if not EEPROM/flash or no paged access
if(!avr_has_paged_access(pgm, mem))
return pgm->write_byte(pgm, p, mem, addr, data);
return fallback_write_byte(pgm, p, mem, addr, data);
// If address is out of range synchronise caches with device and return whether successful
if(addr >= (unsigned long) mem->size)
@ -687,7 +697,7 @@ int avr_page_erase_cached(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM
return LIBAVRDUDE_GENERAL_FAILURE;
if(mem->page_size == 1) {
if(pgm->write_byte(pgm, p, mem, uaddr, 0xff) < 0)
if(fallback_write_byte(pgm, p, mem, uaddr, 0xff) < 0)
return LIBAVRDUDE_GENERAL_FAILURE;
} else {
if(!pgm->page_erase || pgm->page_erase(pgm, p, mem, uaddr) < 0)

View File

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

View File

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

View File

@ -21,11 +21,14 @@
#ifndef avrdude_h
#define avrdude_h
#include <stdio.h>
#define SYSTEM_CONF_FILE "avrdude.conf"
#if defined(WIN32)
#define USER_CONF_FILE "avrdude.rc"
#else
#define USER_CONF_FILE ".avrduderc"
#define XDG_USER_CONF_FILE "avrdude/avrdude.rc"
#endif
extern char *progname; // name of program, for messages
@ -36,7 +39,7 @@ extern int verbose; // verbosity level (-v, -vv, ...)
extern int quell_progress; // quell progress report -q, reduce effective verbosity level (-qq, -qqq)
int avrdude_message(int msglvl, const char *format, ...);
int avrdude_message2(const char *fname, int msgmode, int msglvl, const char *format, ...);
int avrdude_message2(FILE *fp, int lno, const char *file, const char *func, int msgmode, int msglvl, const char *format, ...);
#define MSG_EXT_ERROR (-3) // OS-type error, no -v option, can be suppressed with -qqqqq
#define MSG_ERROR (-2) // Avrdude error, no -v option, can be suppressed with -qqqq
@ -49,41 +52,45 @@ int avrdude_message2(const char *fname, int msgmode, int msglvl, const char *for
#define MSG_TRACE2 5 // Displayed with -vvvvv
#define MSG2_PROGNAME 1 // Start by printing progname
#define MSG2_FUNCTION 2 // Print calling function (1st arg) after progname
#define MSG2_TYPE 4 // Print message type after function or progname
#define MSG2_INDENT1 8 // Start by printing indentation of progname+1 blanks
#define MSG2_INDENT2 16 // Start by printing indentation of progname+2 blanks
#define MSG2_FLUSH 32 // Flush before and after printing
#define MSG2_FUNCTION 2 // Print calling function (1st arg) after progname if >= notice
#define MSG2_FILELINE 4 // Print source file and line number after function if >= debug
#define MSG2_TYPE 8 // Print message type after function or progname
#define MSG2_INDENT1 16 // Start by printing indentation of progname+1 blanks
#define MSG2_INDENT2 32 // Start by printing indentation of progname+2 blanks
#define MSG2_FLUSH 64 // Flush before and after printing
// Shortcuts
#define msg_ext_error(...) avrdude_message2(__func__, 0, MSG_EXT_ERROR, __VA_ARGS__)
#define msg_error(...) avrdude_message2(__func__, 0, MSG_ERROR, __VA_ARGS__)
#define msg_warning(...) avrdude_message2(__func__, 0, MSG_WARNING, __VA_ARGS__)
#define msg_info(...) avrdude_message2(__func__, 0, MSG_INFO, __VA_ARGS__)
#define msg_notice(...) avrdude_message2(__func__, 0, MSG_NOTICE, __VA_ARGS__)
#define msg_notice2(...) avrdude_message2(__func__, 0, MSG_NOTICE2, __VA_ARGS__)
#define msg_debug(...) avrdude_message2(__func__, 0, MSG_DEBUG, __VA_ARGS__)
#define msg_trace(...) avrdude_message2(__func__, 0, MSG_TRACE, __VA_ARGS__)
#define msg_trace2(...) avrdude_message2(__func__, 0, MSG_TRACE2, __VA_ARGS__)
#define msg_ext_error(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, 0, MSG_EXT_ERROR, __VA_ARGS__)
#define msg_error(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, 0, MSG_ERROR, __VA_ARGS__)
#define msg_warning(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, 0, MSG_WARNING, __VA_ARGS__)
#define msg_info(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, 0, MSG_INFO, __VA_ARGS__)
#define msg_notice(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, 0, MSG_NOTICE, __VA_ARGS__)
#define msg_notice2(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, 0, MSG_NOTICE2, __VA_ARGS__)
#define msg_debug(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, 0, MSG_DEBUG, __VA_ARGS__)
#define msg_trace(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, 0, MSG_TRACE, __VA_ARGS__)
#define msg_trace2(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, 0, MSG_TRACE2, __VA_ARGS__)
#define pmsg_ext_error(...) avrdude_message2(__func__, MSG2_PROGNAME|MSG2_FUNCTION|MSG2_TYPE|MSG2_FLUSH, MSG_EXT_ERROR, __VA_ARGS__)
#define pmsg_error(...) avrdude_message2(__func__, MSG2_PROGNAME|MSG2_FUNCTION|MSG2_TYPE|MSG2_FLUSH, MSG_ERROR, __VA_ARGS__)
#define pmsg_warning(...) avrdude_message2(__func__, MSG2_PROGNAME|MSG2_FUNCTION|MSG2_TYPE|MSG2_FLUSH, MSG_WARNING, __VA_ARGS__)
#define pmsg_info(...) avrdude_message2(__func__, MSG2_PROGNAME|MSG2_FLUSH, MSG_INFO, __VA_ARGS__)
#define pmsg_notice(...) avrdude_message2(__func__, MSG2_PROGNAME|MSG2_FLUSH, MSG_NOTICE, __VA_ARGS__)
#define pmsg_notice2(...) avrdude_message2(__func__, MSG2_PROGNAME|MSG2_FLUSH, MSG_NOTICE2, __VA_ARGS__)
#define pmsg_debug(...) avrdude_message2(__func__, MSG2_PROGNAME|MSG2_FLUSH, MSG_DEBUG, __VA_ARGS__)
#define pmsg_trace(...) avrdude_message2(__func__, MSG2_PROGNAME|MSG2_FLUSH, MSG_TRACE, __VA_ARGS__)
#define pmsg_trace2(...) avrdude_message2(__func__, MSG2_PROGNAME|MSG2_FLUSH, MSG_TRACE2, __VA_ARGS__)
#define pmsg_ext_error(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_PROGNAME|MSG2_FUNCTION|MSG2_FILELINE|MSG2_TYPE|MSG2_FLUSH, MSG_EXT_ERROR, __VA_ARGS__)
#define pmsg_error(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_PROGNAME|MSG2_FUNCTION|MSG2_FILELINE|MSG2_TYPE|MSG2_FLUSH, MSG_ERROR, __VA_ARGS__)
#define pmsg_warning(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_PROGNAME|MSG2_FUNCTION|MSG2_FILELINE|MSG2_TYPE|MSG2_FLUSH, MSG_WARNING, __VA_ARGS__)
#define pmsg_info(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_PROGNAME|MSG2_FLUSH, MSG_INFO, __VA_ARGS__)
#define pmsg_notice(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_PROGNAME|MSG2_FLUSH, MSG_NOTICE, __VA_ARGS__)
#define pmsg_notice2(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_PROGNAME|MSG2_FLUSH, MSG_NOTICE2, __VA_ARGS__)
#define pmsg_debug(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_PROGNAME|MSG2_FLUSH, MSG_DEBUG, __VA_ARGS__)
#define pmsg_trace(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_PROGNAME|MSG2_FLUSH, MSG_TRACE, __VA_ARGS__)
#define pmsg_trace2(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_PROGNAME|MSG2_FLUSH, MSG_TRACE2, __VA_ARGS__)
#define imsg_ext_error(...) avrdude_message2(__func__, MSG2_INDENT1|MSG2_FLUSH, MSG_EXT_ERROR, __VA_ARGS__)
#define imsg_error(...) avrdude_message2(__func__, MSG2_INDENT1|MSG2_FLUSH, MSG_ERROR, __VA_ARGS__)
#define imsg_warning(...) avrdude_message2(__func__, MSG2_INDENT1|MSG2_FLUSH, MSG_WARNING, __VA_ARGS__)
#define imsg_info(...) avrdude_message2(__func__, MSG2_INDENT2|MSG2_FLUSH, MSG_INFO, __VA_ARGS__)
#define imsg_notice(...) avrdude_message2(__func__, MSG2_INDENT2|MSG2_FLUSH, MSG_NOTICE, __VA_ARGS__)
#define imsg_notice2(...) avrdude_message2(__func__, MSG2_INDENT2|MSG2_FLUSH, MSG_NOTICE2, __VA_ARGS__)
#define imsg_debug(...) avrdude_message2(__func__, MSG2_INDENT2|MSG2_FLUSH, MSG_DEBUG, __VA_ARGS__)
#define imsg_trace(...) avrdude_message2(__func__, MSG2_INDENT2|MSG2_FLUSH, MSG_TRACE, __VA_ARGS__)
#define imsg_trace2(...) avrdude_message2(__func__, MSG2_INDENT2|MSG2_FLUSH, MSG_TRACE2, __VA_ARGS__)
#define imsg_ext_error(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_INDENT1|MSG2_FLUSH, MSG_EXT_ERROR, __VA_ARGS__)
#define imsg_error(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_INDENT1|MSG2_FLUSH, MSG_ERROR, __VA_ARGS__)
#define imsg_warning(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_INDENT1|MSG2_FLUSH, MSG_WARNING, __VA_ARGS__)
#define imsg_info(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_INDENT2|MSG2_FLUSH, MSG_INFO, __VA_ARGS__)
#define imsg_notice(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_INDENT2|MSG2_FLUSH, MSG_NOTICE, __VA_ARGS__)
#define imsg_notice2(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_INDENT2|MSG2_FLUSH, MSG_NOTICE2, __VA_ARGS__)
#define imsg_debug(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_INDENT2|MSG2_FLUSH, MSG_DEBUG, __VA_ARGS__)
#define imsg_trace(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_INDENT2|MSG2_FLUSH, MSG_TRACE, __VA_ARGS__)
#define imsg_trace2(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_INDENT2|MSG2_FLUSH, MSG_TRACE2, __VA_ARGS__)
#define term_out(...) avrdude_message2(stdout, __LINE__, __FILE__, __func__, MSG2_FLUSH, MSG_INFO, __VA_ARGS__)
#define fmsg_out(fp, ...) avrdude_message2(fp, __LINE__, __FILE__, __func__, MSG2_FLUSH, MSG_INFO, __VA_ARGS__)
#endif

View File

@ -498,22 +498,15 @@ void avr_mem_display(const char *prefix, FILE *f, const AVRMEM *m,
int i, j;
char * optr;
if (m == NULL) {
if (m == NULL || verbose > 2) {
fprintf(f,
"%s Block Poll Page Polled\n"
"%sMemory Type Alias Mode Delay Size Indx Paged Size Size #Pages MinW MaxW ReadBack\n"
"%s----------- -------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- ---------\n",
prefix, prefix, prefix);
}
else {
if (verbose > 2) {
fprintf(f,
"%s Block Poll Page Polled\n"
"%sMemory Type Alias Mode Delay Size Indx Paged Size Size #Pages MinW MaxW ReadBack\n"
"%s----------- -------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- ---------\n",
prefix, prefix, prefix);
}
if (m != NULL) {
// Only print memory section if the previous section printed isn't identical
if(prev_mem_offset != m->offset || prev_mem_size != m->size || (strcmp(p->family_id, "") == 0)) {
prev_mem_offset = m->offset;

View File

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

View File

@ -121,6 +121,8 @@ enum flip2_mem_unit {
FLIP2_MEM_UNIT_EXT_MEM_DF = 0x10
};
#ifdef HAVE_LIBUSB
/* EXPORTED PROGRAMMER FUNCTION PROTOTYPES */
static int flip2_open(PROGRAMMER *pgm, const char *port_spec);
@ -146,8 +148,6 @@ static void flip2_setup(PROGRAMMER * pgm);
static void flip2_teardown(PROGRAMMER * pgm);
/* INTERNAL PROGRAMMER FUNCTION PROTOTYPES */
#ifdef HAVE_LIBUSB
// The internal ones are made conditional, as they're not defined further down #ifndef HAVE_LIBUSB
static void flip2_show_info(struct flip2 *flip2);

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,
unsigned long addr, unsigned char data);
static int jtag3_set_sck_period(const PROGRAMMER *pgm, double v);
void jtag3_print_parms1(const PROGRAMMER *pgm, const char *p);
void jtag3_print_parms1(const PROGRAMMER *pgm, const char *p, FILE *fp);
static int jtag3_paged_write(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m,
unsigned int page_size,
unsigned int addr, unsigned int n_bytes);
@ -1077,7 +1077,7 @@ static int jtag3_initialize(const PROGRAMMER *pgm, const AVRPART *p) {
if (PDATA(pgm)->set_sck(pgm, parm) < 0)
return -1;
}
jtag3_print_parms1(pgm, progbuf);
jtag3_print_parms1(pgm, progbuf, stderr);
if (conn == PARM3_CONN_JTAG)
{
pmsg_notice2("jtag3_initialize(): "
@ -1504,6 +1504,30 @@ int jtag3_open_common(PROGRAMMER *pgm, const char *port) {
}
#endif
if (rv < 0) {
// Check if SNAP or PICkit4 is in PIC mode
for(LNODEID ln=lfirst(pgm->id); ln; ln=lnext(ln)) {
if (matches(ldata(ln), "snap")) {
pinfo.usbinfo.vid = USB_VENDOR_MICROCHIP;
pinfo.usbinfo.pid = USB_DEVICE_SNAP_PIC_MODE;
int pic_mode = serial_open(port, pinfo, &pgm->fd);
if(pic_mode >= 0) {
msg_error("\n");
pmsg_error("MPLAB SNAP in PIC mode detected!\n");
imsg_error("Use MPLAB X or Microchip Studio to switch to AVR mode\n\n");
return -1;
}
} else if(matches(ldata(ln), "pickit4")) {
pinfo.usbinfo.vid = USB_VENDOR_MICROCHIP;
pinfo.usbinfo.pid = USB_DEVICE_PICKIT4_PIC_MODE;
int pic_mode = serial_open(port, pinfo, &pgm->fd);
if(pic_mode >= 0) {
msg_error("\n");
pmsg_error("PICkit4 in PIC mode detected!\n");
imsg_error("Use MPLAB X or Microchip Studio to switch to AVR mode\n\n");
return -1;
}
}
}
pmsg_error("did not find any device matching VID 0x%04x and PID list: ",
(unsigned) pinfo.usbinfo.vid);
int notfirst = 0;
@ -2333,12 +2357,12 @@ static void jtag3_display(const PROGRAMMER *pgm, const char *p) {
}
void jtag3_print_parms1(const PROGRAMMER *pgm, const char *p) {
void jtag3_print_parms1(const PROGRAMMER *pgm, const char *p, FILE *fp) {
unsigned char buf[3];
if (jtag3_getparm(pgm, SCOPE_GENERAL, 1, PARM3_VTARGET, buf, 2) < 0)
return;
msg_info("%sVtarget %s: %.2f V\n", p,
fmsg_out(fp, "%sVtarget %s: %.2f V\n", p,
verbose? "": " ", b2_to_u16(buf)/1000.0);
// Print features unique to the Power Debugger
@ -2350,7 +2374,7 @@ void jtag3_print_parms1(const PROGRAMMER *pgm, const char *p) {
if (jtag3_getparm(pgm, SCOPE_GENERAL, 1, PARM3_VADJUST, buf, 2) < 0)
return;
analog_raw_data = b2_to_u16(buf);
msg_info("%sVout set %s: %.2f V\n", p,
fmsg_out(fp, "%sVout set %s: %.2f V\n", p,
verbose? "": " ", analog_raw_data / 1000.0);
// Read measured generator voltage value (VOUT)
@ -2362,7 +2386,7 @@ void jtag3_print_parms1(const PROGRAMMER *pgm, const char *p) {
else {
if (analog_raw_data & 0x0800)
analog_raw_data |= 0xF000;
msg_info("%sVout measured %s: %.02f V\n", p,
fmsg_out(fp, "%sVout measured %s: %.02f V\n", p,
verbose? "": " ", ((float) analog_raw_data / -200.0));
}
@ -2375,7 +2399,7 @@ void jtag3_print_parms1(const PROGRAMMER *pgm, const char *p) {
else {
if (analog_raw_data & 0x0800)
analog_raw_data |= 0xF000;
msg_info("%sCh A voltage %s: %.03f V\n", p,
fmsg_out(fp, "%sCh A voltage %s: %.03f V\n", p,
verbose? "": " ", ((float) analog_raw_data / -200.0));
}
@ -2386,7 +2410,7 @@ void jtag3_print_parms1(const PROGRAMMER *pgm, const char *p) {
if (buf[0] != 0x90)
pmsg_error("invalid PARM3_ANALOG_A_CURRENT data packet format\n");
else
msg_info("%sCh A current %s: %.3f mA\n", p,
fmsg_out(fp, "%sCh A current %s: %.3f mA\n", p,
verbose? "": " ", (float) analog_raw_data * 0.003472);
// Read channel B voltage
@ -2398,7 +2422,7 @@ void jtag3_print_parms1(const PROGRAMMER *pgm, const char *p) {
else {
if (analog_raw_data & 0x0800)
analog_raw_data |= 0xF000;
msg_info("%sCh B voltage %s: %.03f V\n", p,
fmsg_out(fp, "%sCh B voltage %s: %.03f V\n", p,
verbose? "": " ", (float) analog_raw_data / -200.0);
}
@ -2411,7 +2435,7 @@ void jtag3_print_parms1(const PROGRAMMER *pgm, const char *p) {
else {
if (analog_raw_data & 0x0800)
analog_raw_data |= 0xF000;
msg_info("%sCh B current %s: %.3f mA\n", p,
fmsg_out(fp, "%sCh B current %s: %.3f mA\n", p,
verbose? "": " ", (float) analog_raw_data * 0.555556);
}
break;
@ -2422,33 +2446,33 @@ void jtag3_print_parms1(const PROGRAMMER *pgm, const char *p) {
return;
if (b2_to_u16(buf) > 0) {
msg_info("%sJTAG clock megaAVR/program : %u kHz\n", p, b2_to_u16(buf));
fmsg_out(fp, "%sJTAG clock megaAVR/program : %u kHz\n", p, b2_to_u16(buf));
}
if (jtag3_getparm(pgm, SCOPE_AVR, 1, PARM3_CLK_MEGA_DEBUG, buf, 2) < 0)
return;
if (b2_to_u16(buf) > 0) {
msg_info("%sJTAG clock megaAVR/debug : %u kHz\n", p, b2_to_u16(buf));
fmsg_out(fp, "%sJTAG clock megaAVR/debug : %u kHz\n", p, b2_to_u16(buf));
}
if (jtag3_getparm(pgm, SCOPE_AVR, 1, PARM3_CLK_XMEGA_JTAG, buf, 2) < 0)
return;
if (b2_to_u16(buf) > 0) {
msg_info("%sJTAG clock Xmega : %u kHz\n", p, b2_to_u16(buf));
fmsg_out(fp, "%sJTAG clock Xmega : %u kHz\n", p, b2_to_u16(buf));
}
if (jtag3_getparm(pgm, SCOPE_AVR, 1, PARM3_CLK_XMEGA_PDI, buf, 2) < 0)
return;
if (b2_to_u16(buf) > 0) {
msg_info("%sPDI/UPDI clock Xmega/megaAVR : %u kHz\n", p, b2_to_u16(buf));
fmsg_out(fp, "%sPDI/UPDI clock Xmega/megaAVR : %u kHz\n", p, b2_to_u16(buf));
}
}
static void jtag3_print_parms(const PROGRAMMER *pgm) {
jtag3_print_parms1(pgm, "");
static void jtag3_print_parms(const PROGRAMMER *pgm, FILE *fp) {
jtag3_print_parms1(pgm, "", fp);
}
static unsigned char jtag3_memtype(const PROGRAMMER *pgm, const AVRPART *p, unsigned long addr) {

View File

@ -38,7 +38,7 @@ int jtag3_setparm(const PROGRAMMER *pgm, unsigned char scope,
unsigned char *value, unsigned char length);
int jtag3_command(const PROGRAMMER *pgm, unsigned char *cmd, unsigned int cmdlen,
unsigned char **resp, const char *descr);
void jtag3_print_parms1(const PROGRAMMER *pgm, const char *p);
void jtag3_print_parms1(const PROGRAMMER *pgm, const char *p, FILE *fp);
int jtag3_set_vtarget(const PROGRAMMER *pgm, double voltage);
extern const char jtag3_desc[];
extern const char jtag3_dw_desc[];

View File

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

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_setparm(const PROGRAMMER *pgm, unsigned char parm,
unsigned char * value);
static void jtagmkII_print_parms1(const PROGRAMMER *pgm, const char *p);
static void jtagmkII_print_parms1(const PROGRAMMER *pgm, const char *p, FILE *fp);
static int jtagmkII_paged_write(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m,
unsigned int page_size,
unsigned int addr, unsigned int n_bytes);
@ -2508,13 +2508,13 @@ static void jtagmkII_display(const PROGRAMMER *pgm, const char *p) {
PDATA(pgm)->serno[0], PDATA(pgm)->serno[1], PDATA(pgm)->serno[2],
PDATA(pgm)->serno[3], PDATA(pgm)->serno[4], PDATA(pgm)->serno[5]);
jtagmkII_print_parms1(pgm, p);
jtagmkII_print_parms1(pgm, p, stderr);
return;
}
static void jtagmkII_print_parms1(const PROGRAMMER *pgm, const char *p) {
static void jtagmkII_print_parms1(const PROGRAMMER *pgm, const char *p, FILE *fp) {
unsigned char vtarget[4], jtag_clock[4];
char clkbuf[20];
double clk;
@ -2522,7 +2522,7 @@ static void jtagmkII_print_parms1(const PROGRAMMER *pgm, const char *p) {
if (jtagmkII_getparm(pgm, PAR_OCD_VTARGET, vtarget) < 0)
return;
msg_info("%sVtarget : %.1f V\n", p, b2_to_u16(vtarget) / 1000.0);
fmsg_out(fp, "%sVtarget : %.1f V\n", p, b2_to_u16(vtarget) / 1000.0);
if ((pgm->flag & PGM_FL_IS_JTAG)) {
if (jtagmkII_getparm(pgm, PAR_OCD_JTAG_CLK, jtag_clock) < 0)
@ -2541,15 +2541,15 @@ static void jtagmkII_print_parms1(const PROGRAMMER *pgm, const char *p) {
sprintf(clkbuf, "%.1f kHz", 5.35e3 / (double)jtag_clock[0]);
clk = 5.35e6 / (double)jtag_clock[0];
msg_info("%sJTAG clock : %s (%.1f us)\n", p, clkbuf, 1.0e6 / clk);
fmsg_out(fp, "%sJTAG clock : %s (%.1f us)\n", p, clkbuf, 1.0e6 / clk);
}
}
return;
}
static void jtagmkII_print_parms(const PROGRAMMER *pgm) {
jtagmkII_print_parms1(pgm, "");
static void jtagmkII_print_parms(const PROGRAMMER *pgm, FILE *fp) {
jtagmkII_print_parms1(pgm, "", fp);
}
static unsigned char jtagmkII_memtype(const PROGRAMMER *pgm, const AVRPART *p, unsigned long addr) {

View File

@ -783,7 +783,8 @@ typedef struct programmer_t {
unsigned long addr, unsigned char *value);
int (*read_sig_bytes) (const struct programmer_t *pgm, const AVRPART *p, const AVRMEM *m);
int (*read_sib) (const struct programmer_t *pgm, const AVRPART *p, char *sib);
void (*print_parms) (const struct programmer_t *pgm);
int (*term_keep_alive)(const struct programmer_t *pgm, const AVRPART *p);
void (*print_parms) (const struct programmer_t *pgm, FILE *fp);
int (*set_vtarget) (const struct programmer_t *pgm, double v);
int (*set_varef) (const struct programmer_t *pgm, unsigned int chan, double v);
int (*set_fosc) (const struct programmer_t *pgm, double v);

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

View File

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

View File

@ -47,7 +47,7 @@
static int stk500_getparm(const PROGRAMMER *pgm, unsigned parm, unsigned *value);
static int stk500_setparm(const PROGRAMMER *pgm, unsigned parm, unsigned value);
static void stk500_print_parms1(const PROGRAMMER *pgm, const char *p);
static void stk500_print_parms1(const PROGRAMMER *pgm, const char *p, FILE *fp);
static int stk500_send(const PROGRAMMER *pgm, unsigned char *buf, size_t len) {
@ -625,6 +625,12 @@ static void stk500_disable(const PROGRAMMER *pgm) {
}
static void stk500_enable(PROGRAMMER *pgm, const AVRPART *p) {
AVRMEM *mem;
if(pgm->prog_modes & PM_SPM) // For bootloaders (eg, arduino)
if(!(p->prog_modes & (PM_UPDI | PM_PDI | PM_aWire))) // Classic parts, eg, optiboot with word addresses
if((mem = avr_locate_mem(p, "eeprom")))
if(mem->page_size == 1) // Increase pagesize if it is 1
mem->page_size = 16;
return;
}
@ -666,27 +672,56 @@ static void stk500_close(PROGRAMMER * pgm)
}
static int stk500_loadaddr(const PROGRAMMER *pgm, const AVRMEM *mem, const unsigned int addr) {
// Address is byte address; a_div == 2: send word address; a_div == 1: send byte address
static int stk500_loadaddr(const PROGRAMMER *pgm, const AVRMEM *mem, unsigned int addr, int a_div) {
unsigned char buf[16];
int tries;
unsigned char ext_byte;
OPCODE * lext;
addr /= a_div;
tries = 0;
retry:
tries++;
/* To support flash > 64K words the correct Extended Address Byte is needed */
lext = mem->op[AVR_OP_LOAD_EXT_ADDR];
if (lext != NULL) {
ext_byte = (addr >> 16) & 0xff;
if (ext_byte != PDATA(pgm)->ext_addr_byte) {
/* Either this is the first addr load, or a different 64K word section */
memset(buf, 0, 4);
avr_set_bits(lext, buf);
avr_set_addr(lext, buf, addr);
stk500_cmd(pgm, buf, buf);
PDATA(pgm)->ext_addr_byte = ext_byte;
// Support large flash by sending the correct extended address byte when needed
if(pgm->prog_modes & PM_SPM) { // Bootloaders, eg, optiboot, optiboot_dx, optiboot_x
if(mem->size/a_div > 64*1024) { // Extended addressing needed
ext_byte = (addr >> 16) & 0xff;
if(ext_byte != PDATA(pgm)->ext_addr_byte) { // First addr load or a different 64k section
buf[0] = 0x4d; // Protocol bytes that bootloaders expect
buf[1] = 0x00;
buf[2] = ext_byte;
buf[3] = 0x00;
if(stk500_cmd(pgm, buf, buf) == 0)
PDATA(pgm)->ext_addr_byte = ext_byte;
}
/*
* Ensure next paged r/w will load ext addr again if page sits just below a 64k boundary
*
* Some bootloaders increment their copy of ext_addr_byte in that situation, eg, when they
* use elpm rx,Z+ to read a byte from flash or spm Z+ to write to flash whilst they keep
* ext_addr_byte in RAMPZ, which in turn gets incremented by Z+ at 64k page boundaries. So,
* if an upload with automated verify finishes just below 64k, AVRDUDE still holds
* ext_addr_byte at the current 64k segment whilst its copy in the bootloader has been
* auto-incremented. Verifying the code from start exposes the discrepancy.
*/
if((addr & 0xffff0000) != ((addr+mem->page_size/a_div) & 0xffff0000))
PDATA(pgm)->ext_addr_byte = 0xff;
}
} else { // Programmer *not* for bootloaders? Original stk500v1 protocol!
OPCODE *lext = mem->op[AVR_OP_LOAD_EXT_ADDR];
if(lext) {
ext_byte = (addr >> 16) & 0xff;
if(ext_byte != PDATA(pgm)->ext_addr_byte) { // First addr load or a different 64k section
memset(buf, 0, 4); // Part's load_ext_addr command is typically 4d 00 ext_addr 00
avr_set_bits(lext, buf);
avr_set_addr(lext, buf, addr);
if(stk500_cmd(pgm, buf, buf) == 0)
PDATA(pgm)->ext_addr_byte = ext_byte;
}
}
}
@ -724,6 +759,29 @@ static int stk500_loadaddr(const PROGRAMMER *pgm, const AVRMEM *mem, const unsig
}
static int set_memtype_a_div(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m, int *memtypep, int *a_divp) {
if(avr_mem_is_flash_type(m)) {
*memtypep = 'F';
if(!(pgm->prog_modes & PM_SPM)) // Programmer *not* for bootloaders: original stk500v1 protocol
*a_divp = m->op[AVR_OP_LOADPAGE_LO] || m->op[AVR_OP_READ_LO]? 2: 1;
else if(!(p->prog_modes & (PM_UPDI | PM_PDI | PM_aWire)))
*a_divp = 2; // Bootloader where part is a "classic" part (eg, optiboot)
else
*a_divp = 1; // Bootloader where part is Xmega or "new" families (optiboot_x, optiboot_dx)
return 0;
}
if(avr_mem_is_eeprom_type(m)) {
*memtypep = 'E';
// Word addr for bootloaders where part is a "classic" part (eg, optiboot, arduinoisp, ...), byte addr otherwise
*a_divp = (pgm->prog_modes & PM_SPM) && !(p->prog_modes & (PM_UPDI | PM_PDI))? 2: 1;
return 0;
}
return -1;
}
static int stk500_paged_write(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m,
unsigned int page_size,
unsigned int addr, unsigned int n_bytes)
@ -736,25 +794,12 @@ static int stk500_paged_write(const PROGRAMMER *pgm, const AVRPART *p, const AVR
unsigned int n;
unsigned int i;
if (strcmp(m->desc, "flash") == 0) {
memtype = 'F';
a_div = 2;
} else if (strcmp(m->desc, "eeprom") == 0) {
memtype = 'E';
/*
* The STK original 500 v1 protocol actually expects a_div = 1, but the
* v1.x FW of the STK500 kit has been superseded by v2 FW in the mid
* 2000s. Since optiboot, arduino as ISP and others assume a_div = 2,
* better use that. See https://github.com/avrdudes/avrdude/issues/967
*/
a_div = 2;
} else {
if(set_memtype_a_div(pgm, p, m, &memtype, &a_div) < 0)
return -2;
}
n = addr + n_bytes;
#if 0
msg_info(
msg_debug(
"n_bytes = %d\n"
"n = %u\n"
"a_div = %d\n"
@ -775,7 +820,7 @@ static int stk500_paged_write(const PROGRAMMER *pgm, const AVRPART *p, const AVR
tries = 0;
retry:
tries++;
stk500_loadaddr(pgm, m, addr/a_div);
stk500_loadaddr(pgm, m, addr, a_div);
/* build command block and avoid multiple send commands as it leads to a crash
of the silabs usb serial driver on mac os x */
@ -830,21 +875,8 @@ static int stk500_paged_load(const PROGRAMMER *pgm, const AVRPART *p, const AVRM
unsigned int n;
int block_size;
if (strcmp(m->desc, "flash") == 0) {
memtype = 'F';
a_div = 2;
} else if (strcmp(m->desc, "eeprom") == 0) {
memtype = 'E';
/*
* The STK original 500 v1 protocol actually expects a_div = 1, but the
* v1.x FW of the STK500 kit has been superseded by v2 FW in the mid
* 2000s. Since optiboot, arduino as ISP and others assume a_div = 2,
* better use that. See https://github.com/avrdudes/avrdude/issues/967
*/
a_div = 2;
} else {
if(set_memtype_a_div(pgm, p, m, &memtype, &a_div) < 0)
return -2;
}
n = addr + n_bytes;
for (; addr < n; addr += block_size) {
@ -861,7 +893,7 @@ static int stk500_paged_load(const PROGRAMMER *pgm, const AVRPART *p, const AVRM
tries = 0;
retry:
tries++;
stk500_loadaddr(pgm, m, addr/a_div);
stk500_loadaddr(pgm, m, addr, a_div);
buf[0] = Cmnd_STK_READ_PAGE;
buf[1] = (block_size >> 8) & 0xff;
buf[2] = block_size & 0xff;
@ -1160,13 +1192,13 @@ static void stk500_display(const PROGRAMMER *pgm, const char *p) {
msg_info("%sTopcard : %s\n", p, n);
}
if(strcmp(pgm->type, "Arduino") != 0)
stk500_print_parms1(pgm, p);
stk500_print_parms1(pgm, p, stderr);
return;
}
static void stk500_print_parms1(const PROGRAMMER *pgm, const char *p) {
static void stk500_print_parms1(const PROGRAMMER *pgm, const char *p, FILE *fp) {
unsigned vtarget, vadjust, osc_pscale, osc_cmatch, sck_duration;
stk500_getparm(pgm, Parm_STK_VTARGET, &vtarget);
@ -1175,11 +1207,11 @@ static void stk500_print_parms1(const PROGRAMMER *pgm, const char *p) {
stk500_getparm(pgm, Parm_STK_OSC_CMATCH, &osc_cmatch);
stk500_getparm(pgm, Parm_STK_SCK_DURATION, &sck_duration);
msg_info("%sVtarget : %.1f V\n", p, vtarget / 10.0);
msg_info("%sVaref : %.1f V\n", p, vadjust / 10.0);
msg_info("%sOscillator : ", p);
fmsg_out(fp, "%sVtarget : %.1f V\n", p, vtarget / 10.0);
fmsg_out(fp, "%sVaref : %.1f V\n", p, vadjust / 10.0);
fmsg_out(fp, "%sOscillator : ", p);
if (osc_pscale == 0)
msg_info("Off\n");
fmsg_out(fp, "Off\n");
else {
int prescale = 1;
double f = STK500_XTAL / 2;
@ -1203,16 +1235,16 @@ static void stk500_print_parms1(const PROGRAMMER *pgm, const char *p) {
unit = "kHz";
} else
unit = "Hz";
msg_info("%.3f %s\n", f, unit);
fmsg_out(fp, "%.3f %s\n", f, unit);
}
msg_info("%sSCK period : %.1f us\n", p, sck_duration * 8.0e6 / STK500_XTAL + 0.05);
fmsg_out(fp, "%sSCK period : %.1f us\n", p, sck_duration * 8.0e6 / STK500_XTAL + 0.05);
return;
}
static void stk500_print_parms(const PROGRAMMER *pgm) {
stk500_print_parms1(pgm, "");
static void stk500_print_parms(const PROGRAMMER *pgm, FILE *fp) {
stk500_print_parms1(pgm, "", fp);
}
static void stk500_setup(PROGRAMMER * pgm)

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

View File

@ -33,10 +33,21 @@
#include <errno.h>
#if defined(HAVE_LIBREADLINE)
# include <readline/readline.h>
# include <readline/history.h>
#include <readline/readline.h>
#include <readline/history.h>
#ifdef _MSC_VER
#include "msvc/unistd.h"
#else
#include <unistd.h>
#endif
#ifdef WIN32
#include <windows.h>
#endif
#endif
#include "avrdude.h"
#include "term.h"
@ -114,7 +125,7 @@ static int nexttok(char *buf, char **tok, char **next) {
n = q;
uint8_t quotes = 0;
while (*n && (!isspace(*n) || quotes)) {
// poor man's quote and escape processing
// Poor man's quote and escape processing
if (*n == '"' || *n == '\'')
quotes++;
else if(*n == '\\' && n[1])
@ -173,7 +184,7 @@ static int chardump_line(char *buffer, unsigned char *p, int n, int pad) {
int i;
unsigned char b[128];
// sanity check
// Sanity check
n = n < 1? 1: n > sizeof b? sizeof b: n;
memcpy(b, p, n);
@ -202,7 +213,7 @@ static int hexdump_buf(FILE *f, int startaddr, unsigned char *buf, int len) {
n = len;
hexdump_line(dst1, p, n, 48);
chardump_line(dst2, p, n, 16);
fprintf(f, "%04x %s |%s|\n", addr, dst1, dst2);
term_out("%04x %s |%s|\n", addr, dst1, dst2);
len -= n;
addr += n;
p += n;
@ -214,7 +225,7 @@ static int hexdump_buf(FILE *f, int startaddr, unsigned char *buf, int len) {
static int cmd_dump(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
if (argc < 2 || argc > 4) {
terminal_message(MSG_INFO,
msg_error(
"Usage: %s <memory> <addr> <len>\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];
AVRMEM *mem = avr_locate_mem(p, memtype);
if (mem == NULL) {
terminal_message(MSG_INFO, "%s (dump): %s memory type not defined for part %s\n",
progname, memtype, p->desc);
pmsg_error("(dump) %s memory type not defined for part %s\n", memtype, p->desc);
return -1;
}
int maxsize = mem->size;
@ -242,12 +252,10 @@ static int cmd_dump(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
if (argc >= 3 && strcmp(argv[2], "...") != 0) {
addr = strtoul(argv[2], &end_ptr, 0);
if (*end_ptr || (end_ptr == argv[2])) {
terminal_message(MSG_INFO, "%s (dump): can't parse address %s\n",
progname, argv[2]);
pmsg_error("(dump) cannot parse address %s\n", argv[2]);
return -1;
} else if (addr < 0 || addr >= maxsize) {
terminal_message(MSG_INFO, "%s (dump): %s address 0x%05x is out of range [0, 0x%05x]\n",
progname, mem->desc, addr, maxsize-1);
pmsg_error("(dump) %s address 0x%05x is out of range [0, 0x%05x]\n", mem->desc, addr, maxsize-1);
return -1;
}
}
@ -263,8 +271,7 @@ static int cmd_dump(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
} else if (argc == 4) {
len = strtol(argv[3], &end_ptr, 0);
if (*end_ptr || (end_ptr == argv[3])) {
terminal_message(MSG_INFO, "%s (dump): can't parse length %s\n",
progname, argv[3]);
pmsg_error("(dump) cannot parse length %s\n", argv[3]);
return -1;
}
} else {
@ -288,7 +295,7 @@ static int cmd_dump(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
uint8_t *buf = malloc(len);
if (buf == NULL) {
terminal_message(MSG_INFO, "%s (dump): out of memory\n", progname);
pmsg_error("(dump) out of memory\n");
return -1;
}
@ -297,11 +304,9 @@ static int cmd_dump(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
int rc = pgm->read_byte_cached(pgm, p, mem, addr + i, &buf[i]);
if (rc != 0) {
report_progress(1, -1, NULL);
terminal_message(MSG_INFO, "%s (dump): error reading %s address 0x%05lx of part %s\n",
progname, mem->desc, (long) addr + i, p->desc);
pmsg_error("(dump) error reading %s address 0x%05lx of part %s\n", mem->desc, (long) addr + i, p->desc);
if (rc == -1)
terminal_message(MSG_INFO, "%*sread operation not supported on memory type %s\n",
(int) strlen(progname)+9, "", mem->desc);
imsg_error("%*sread operation not supported on memory type %s\n", 7, "", mem->desc);
return -1;
}
report_progress(i, len, NULL);
@ -309,7 +314,7 @@ static int cmd_dump(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
report_progress(1, 1, NULL);
hexdump_buf(stdout, addr, buf, len);
fprintf(stdout, "\n");
term_out("\n");
free(buf);
@ -365,7 +370,7 @@ static int is_mantissa_only(char *p) {
static int cmd_write(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
if (argc < 4) {
terminal_message(MSG_INFO,
msg_error(
"Usage: write <memory> <addr> <data>[,] {<data>[,]}\n"
" write <memory> <addr> <len> <data>[,] {<data>[,]} ...\n"
"\n"
@ -399,14 +404,13 @@ static int cmd_write(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
}
int i;
uint8_t write_mode; // Operation mode, "standard" or "fill"
uint8_t start_offset; // Which argc argument
int len; // Number of bytes to write to memory
char *memtype = argv[1]; // Memory name string
uint8_t write_mode; // Operation mode, "standard" or "fill"
uint8_t start_offset; // Which argc argument
int len; // Number of bytes to write to memory
char *memtype = argv[1]; // Memory name string
AVRMEM *mem = avr_locate_mem(p, memtype);
if (mem == NULL) {
terminal_message(MSG_INFO, "%s (write): %s memory type not defined for part %s\n",
progname, memtype, p->desc);
pmsg_error("(write) %s memory type not defined for part %s\n", memtype, p->desc);
return -1;
}
int maxsize = mem->size;
@ -414,21 +418,19 @@ static int cmd_write(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
char *end_ptr;
int addr = strtoul(argv[2], &end_ptr, 0);
if (*end_ptr || (end_ptr == argv[2])) {
terminal_message(MSG_INFO, "%s (write): can't parse address %s\n",
progname, argv[2]);
pmsg_error("(write) cannot parse address %s\n", argv[2]);
return -1;
}
if (addr < 0 || addr >= maxsize) {
terminal_message(MSG_INFO, "%s (write): %s address 0x%05x is out of range [0, 0x%05x]\n",
progname, mem->desc, addr, maxsize-1);
pmsg_error("(write) %s address 0x%05x is out of range [0, 0x%05x]\n", mem->desc, addr, maxsize-1);
return -1;
}
// Allocate a buffer guaranteed to be large enough
uint8_t *buf = calloc(mem->size + 8 + maxstrlen(argc-3, argv+3)+1, sizeof(uint8_t));
if (buf == NULL) {
terminal_message(MSG_INFO, "%s (write): out of memory\n", progname);
pmsg_error("(write) out of memory\n");
return -1;
}
@ -438,8 +440,7 @@ static int cmd_write(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
start_offset = 4;
len = strtoul(argv[3], &end_ptr, 0);
if (*end_ptr || (end_ptr == argv[3])) {
terminal_message(MSG_INFO, "%s (write ...): can't parse length %s\n",
progname, argv[3]);
pmsg_error("(write ...) cannot parse length %s\n", argv[3]);
free(buf);
return -1;
}
@ -471,8 +472,8 @@ static int cmd_write(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
};
if(sizeof(long long) != sizeof(int64_t) || (data.a[0]^data.a[7]) != 1)
terminal_message(MSG_INFO, "%s (write): assumption on data types not met? "
"Check source and recompile\n", progname);
pmsg_error("(write) assumption on data types not met? "
"Check source and recompile\n");
bool is_big_endian = data.a[7];
for (i = start_offset; i < len + start_offset; i++) {
@ -518,7 +519,7 @@ static int cmd_write(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
bool is_out_of_range = 0;
int nhexdigs = p-argi-2;
if(is_signed) { // Is input in range for int64_t?
if(is_signed) { // Is input in range for int64_t?
errno = 0; (void) strtoll(argi, NULL, 0);
is_outside_int64_t = errno == ERANGE;
}
@ -566,9 +567,8 @@ static int cmd_write(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
}
if(is_outside_int64_t || is_out_of_range)
terminal_message(MSG_INFO, "%s (write): %s out of int%d_t range, "
"interpreted as %d-byte %lld; consider 'U' suffix\n",
progname, argi, data.size*8, data.size, data.ll);
pmsg_error("(write) %s out of int%d_t range, "
"interpreted as %d-byte %lld; consider 'U' suffix\n", argi, data.size*8, data.size, (long long int) data.ll);
}
}
}
@ -583,8 +583,8 @@ static int cmd_write(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
data.f = strtof(argi, &end_ptr);
if (end_ptr != argi && toupper(*end_ptr) == 'F' && end_ptr[1] == 0)
data.size = 4;
if (end_ptr != argi && *end_ptr == 0) // no suffix defaults to float but ...
// ... do not accept valid mantissa-only floats that are integer rejects (eg, 078 or ULL overflows)
if (end_ptr != argi && *end_ptr == 0) // No suffix defaults to float but ...
// ... do not accept valid mantissa-only floats that are integer rejects (eg, 078 or ULL overflows)
if (!is_mantissa_only(argi))
data.size = 4;
}
@ -593,29 +593,27 @@ static int cmd_write(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
if ((*argi == '\'' && argi[arglen-1] == '\'') || (*argi == '\"' && argi[arglen-1] == '\"')) {
char *s = calloc(arglen-1, 1);
if (s == NULL) {
terminal_message(MSG_INFO, "%s (write str): out of memory\n", progname);
pmsg_error("(write str) out of memory\n");
free(buf);
return -1;
}
// Strip start and end quotes, and unescape C string
strncpy(s, argi+1, arglen-2);
cfg_unescape(s, s);
if (*argi == '\'') { // Single C-style character
if (*argi == '\'') { // Single C-style character
if(*s && s[1])
terminal_message(MSG_INFO, "%s (write): only using first character of %s\n",
progname, argi);
pmsg_error("(write) only using first character of %s\n", argi);
data.ll = *s;
data.size = 1;
free(s);
} else { // C-style string
} else { // C-style string
data.str_ptr = s;
}
}
}
if(!data.size && !data.str_ptr) {
terminal_message(MSG_INFO, "%s (write): can't parse data %s\n",
progname, argi);
pmsg_error("(write) cannot parse data %s\n", argi);
free(buf);
return -1;
}
@ -644,8 +642,8 @@ static int cmd_write(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
data.bytes_grown = 0;
if ((addr + len + data.bytes_grown) > maxsize) {
terminal_message(MSG_INFO, "%s (write): selected address and # bytes exceed "
"range for %s memory\n", progname, memtype);
pmsg_error("(write) selected address and # bytes exceed "
"range for %s memory\n", memtype);
free(buf);
return -1;
}
@ -653,11 +651,11 @@ static int cmd_write(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
if(data.str_ptr)
free(data.str_ptr);
terminal_message(MSG_NOTICE, "Info: writing %d bytes starting from address 0x%02lx",
pmsg_notice2("(write) writing %d bytes starting from address 0x%02lx",
len + data.bytes_grown, (long) addr);
if (write_mode == WRITE_MODE_FILL)
terminal_message(MSG_NOTICE, "; remaining space filled with %s", argv[argc - 2]);
terminal_message(MSG_NOTICE, "\n");
msg_notice2("; remaining space filled with %s", argv[argc - 2]);
msg_notice2("\n");
pgm->err_led(pgm, OFF);
bool werror = false;
@ -665,19 +663,16 @@ static int cmd_write(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
for (i = 0; i < len + data.bytes_grown; i++) {
int rc = pgm->write_byte_cached(pgm, p, mem, addr+i, buf[i]);
if (rc) {
terminal_message(MSG_INFO, "%s (write): error writing 0x%02x at 0x%05lx, rc=%d\n",
progname, buf[i], (long) addr+i, (int) rc);
pmsg_error("(write) error writing 0x%02x at 0x%05lx, rc=%d\n", buf[i], (long) addr+i, (int) rc);
if (rc == -1)
terminal_message(MSG_INFO, "%*swrite operation not supported on memory type %s\n",
(int) strlen(progname)+10, "", mem->desc);
imsg_error("%*swrite operation not supported on memory type %s\n", 8, "", mem->desc);
werror = true;
}
uint8_t b;
rc = pgm->read_byte_cached(pgm, p, mem, addr+i, &b);
if (b != buf[i]) {
terminal_message(MSG_INFO, "%s (write): error writing 0x%02x at 0x%05lx cell=0x%02x\n",
progname, buf[i], (long) addr+i, b);
pmsg_error("(write) error writing 0x%02x at 0x%05lx cell=0x%02x\n", buf[i], (long) addr+i, b);
werror = true;
}
@ -713,14 +708,13 @@ static int cmd_send(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
int len;
if (spi_mode && (pgm->spi == NULL)) {
terminal_message(MSG_INFO, "%s (send): the %s programmer does not support direct SPI transfers\n",
progname, pgm->type);
pmsg_error("(send) the %s programmer does not support direct SPI transfers\n", pgm->type);
return -1;
}
if ((argc > 5) || ((argc < 5) && (!spi_mode))) {
terminal_message(MSG_INFO, spi_mode?
msg_error(spi_mode?
"Usage: send <byte1> [<byte2> [<byte3> [<byte4>]]]\n":
"Usage: send <byte1> <byte2> <byte3> <byte4>\n");
return -1;
@ -733,8 +727,7 @@ static int cmd_send(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
for (i=1; i<argc; i++) {
cmd[i-1] = strtoul(argv[i], &e, 0);
if (*e || (e == argv[i])) {
terminal_message(MSG_INFO, "%s (send): can't parse byte %s\n",
progname, argv[i]);
pmsg_error("(send) cannot parse byte %s\n", argv[i]);
return -1;
}
}
@ -749,19 +742,17 @@ static int cmd_send(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
/*
* display results
*/
terminal_message(MSG_INFO, "results:");
term_out("results:");
for (i=0; i<len; i++)
terminal_message(MSG_INFO, " %02x", res[i]);
terminal_message(MSG_INFO, "\n");
fprintf(stdout, "\n");
term_out(" %02x", res[i]);
term_out("\n\n");
return 0;
}
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
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[]) {
if(argc < 3) {
terminal_message(MSG_INFO, "Usage: pgerase <memory> <addr>\n");
msg_error("Usage: pgerase <memory> <addr>\n");
return -1;
}
char *memtype = argv[1];
AVRMEM *mem = avr_locate_mem(p, memtype);
if(!mem) {
terminal_message(MSG_INFO, "%s (pgerase): %s memory type not defined for part %s\n",
progname, memtype, p->desc);
pmsg_error("(pgerase) %s memory type not defined for part %s\n", memtype, p->desc);
return -1;
}
if(!avr_has_paged_access(pgm, mem)) {
terminal_message(MSG_INFO, "%s (pgerase): %s memory cannot be paged addressed by %s\n",
progname, memtype, ldata(lfirst(pgm->id)));
pmsg_error("(pgerase) %s memory cannot be paged addressed by %s\n", memtype, (char *) ldata(lfirst(pgm->id)));
return -1;
}
@ -793,21 +782,17 @@ static int cmd_pgerase(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
char *end_ptr;
int addr = strtoul(argv[2], &end_ptr, 0);
if(*end_ptr || (end_ptr == argv[2])) {
terminal_message(MSG_INFO, "%s (pgerase): can't parse address %s\n",
progname, argv[2]);
pmsg_error("(pgerase) cannot parse address %s\n", argv[2]);
return -1;
}
if (addr < 0 || addr >= maxsize) {
terminal_message(MSG_INFO, "%s (pgerase): %s address 0x%05x is out of range [0, 0x%05x]\n",
progname, mem->desc, addr, maxsize-1);
pmsg_error("(pgerase) %s address 0x%05x is out of range [0, 0x%05x]\n", mem->desc, addr, maxsize-1);
return -1;
}
// terminal_message(MSG_INFO, "%s: %s page erase 0x%05x\n", progname, mem->desc, addr & ~(mem->page_size-1));
if(pgm->page_erase_cached(pgm, p, mem, (unsigned int) addr) < 0) {
terminal_message(MSG_INFO, "%s (pgerase): unable to erase %s page at 0x%05x\n",
progname, mem->desc, addr);
pmsg_error("(pgerase) unable to erase %s page at 0x%05x\n", mem->desc, addr);
return -1;
}
@ -816,9 +801,9 @@ static int cmd_pgerase(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
static int cmd_part(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
fprintf(stdout, "\n");
term_out("\n");
avr_display(stdout, p, "", 0);
fprintf(stdout, "\n");
term_out("\n");
return 0;
}
@ -831,20 +816,18 @@ static int cmd_sig(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
rc = avr_signature(pgm, p);
if (rc != 0) {
terminal_message(MSG_INFO, "%s (sig): error reading signature data, rc=%d\n",
progname, rc);
pmsg_error("(sig) error reading signature data, rc=%d\n", rc);
}
m = avr_locate_mem(p, "signature");
if (m == NULL) {
terminal_message(MSG_INFO, "%s (sig): signature data not defined for device %s\n",
progname, p->desc);
pmsg_error("(sig) signature data not defined for device %s\n", p->desc);
}
else {
fprintf(stdout, "Device signature = 0x");
term_out("Device signature = 0x");
for (i=0; i<m->size; i++)
fprintf(stdout, "%02x", m->buf[i]);
fprintf(stdout, "\n\n");
term_out("%02x", m->buf[i]);
term_out("\n\n");
}
return 0;
@ -861,8 +844,8 @@ static int cmd_quit(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
static int cmd_parms(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
pgm->print_parms(pgm);
terminal_message(MSG_INFO, "\n");
pgm->print_parms(pgm, stdout);
term_out("\n");
return 0;
}
@ -873,18 +856,16 @@ static int cmd_vtarg(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
char *endp;
if (argc != 2) {
terminal_message(MSG_INFO, "Usage: vtarg <value>\n");
msg_error("Usage: vtarg <value>\n");
return -1;
}
v = strtod(argv[1], &endp);
if (endp == argv[1]) {
terminal_message(MSG_INFO, "%s (vtarg): can't parse voltage %s\n",
progname, argv[1]);
pmsg_error("(vtarg) cannot parse voltage %s\n", argv[1]);
return -1;
}
if ((rc = pgm->set_vtarget(pgm, v)) != 0) {
terminal_message(MSG_INFO, "%s (vtarg): unable to set V[target] (rc = %d)\n",
progname, rc);
pmsg_error("(vtarg) unable to set V[target] (rc = %d)\n", rc);
return -3;
}
return 0;
@ -897,7 +878,7 @@ static int cmd_fosc(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
char *endp;
if (argc != 2) {
terminal_message(MSG_INFO, "Usage: fosc <value>[M|k] | off\n");
msg_error("Usage: fosc <value>[M|k] | off\n");
return -1;
}
v = strtod(argv[1], &endp);
@ -905,8 +886,7 @@ static int cmd_fosc(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
if (strcmp(argv[1], "off") == 0)
v = 0.0;
else {
terminal_message(MSG_INFO, "%s (fosc): can't parse frequency %s\n",
progname, argv[1]);
pmsg_error("(fosc) cannot parse frequency %s\n", argv[1]);
return -1;
}
}
@ -915,8 +895,7 @@ static int cmd_fosc(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
else if (*endp == 'k' || *endp == 'K')
v *= 1e3;
if ((rc = pgm->set_fosc(pgm, v)) != 0) {
terminal_message(MSG_INFO, "%s (fosc): unable to set oscillator frequency (rc = %d)\n",
progname, rc);
pmsg_error("(fosc) unable to set oscillator frequency (rc = %d)\n", rc);
return -3;
}
return 0;
@ -929,19 +908,17 @@ static int cmd_sck(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
char *endp;
if (argc != 2) {
terminal_message(MSG_INFO, "Usage: sck <value>\n");
msg_error("Usage: sck <value>\n");
return -1;
}
v = strtod(argv[1], &endp);
if (endp == argv[1]) {
terminal_message(MSG_INFO, "%s (sck): can't parse period %s\n",
progname, argv[1]);
pmsg_error("(sck) cannot parse period %s\n", argv[1]);
return -1;
}
v *= 1e-6; /* Convert from microseconds to seconds. */
v *= 1e-6; // Convert from microseconds to seconds
if ((rc = pgm->set_sck_period(pgm, v)) != 0) {
terminal_message(MSG_INFO, "%s (sck): unable to set SCK period (rc = %d)\n",
progname, rc);
pmsg_error("(sck) unable to set SCK period (rc = %d)\n", rc);
return -3;
}
return 0;
@ -955,34 +932,30 @@ static int cmd_varef(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
char *endp;
if (argc != 2 && argc != 3) {
terminal_message(MSG_INFO, "Usage: varef [channel] <value>\n");
msg_error("Usage: varef [channel] <value>\n");
return -1;
}
if (argc == 2) {
chan = 0;
v = strtod(argv[1], &endp);
if (endp == argv[1]) {
terminal_message(MSG_INFO, "%s (varef): can't parse voltage %s\n",
progname, argv[1]);
pmsg_error("(varef) cannot parse voltage %s\n", argv[1]);
return -1;
}
} else {
chan = strtoul(argv[1], &endp, 10);
if (endp == argv[1]) {
terminal_message(MSG_INFO, "%s (varef): can't parse channel %s\n",
progname, argv[1]);
pmsg_error("(varef) cannot parse channel %s\n", argv[1]);
return -1;
}
v = strtod(argv[2], &endp);
if (endp == argv[2]) {
terminal_message(MSG_INFO, "%s (varef): can't parse voltage %s\n",
progname, argv[2]);
pmsg_error("(varef) cannot parse voltage %s\n", argv[2]);
return -1;
}
}
if ((rc = pgm->set_varef(pgm, chan, v)) != 0) {
terminal_message(MSG_INFO, "%s (varef): unable to set V[aref] (rc = %d)\n",
progname, rc);
pmsg_error("(varef) unable to set V[aref] (rc = %d)\n", rc);
return -3;
}
return 0;
@ -992,19 +965,19 @@ static int cmd_varef(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
static int cmd_help(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
int i;
fprintf(stdout, "Valid commands:\n");
term_out("Valid commands:\n");
for (i=0; i<NCMDS; i++) {
if(!*(void (**)(void)) ((char *) pgm + cmd[i].fnoff))
continue;
fprintf(stdout, " %-7s : ", cmd[i].name);
fprintf(stdout, cmd[i].desc, cmd[i].name);
fprintf(stdout, "\n");
term_out(" %-7s : ", cmd[i].name);
term_out(cmd[i].desc, cmd[i].name);
term_out("\n");
}
fprintf(stdout, "\n"
term_out("\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"
"read and write access; the cache is synchronised on quit. Use the part\n"
"command to display valid memory types for use with dump and write.\n\n");
"read and write access; the cache is synchronised on quit or flush commands.\n"
"The part command displays valid memory types for use with dump and write.\n\n");
return 0;
}
@ -1026,26 +999,24 @@ static int cmd_verbose(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
char *endp;
if (argc != 1 && argc != 2) {
terminal_message(MSG_INFO, "Usage: verbose [<value>]\n");
msg_error("Usage: verbose [<value>]\n");
return -1;
}
if (argc == 1) {
terminal_message(MSG_INFO, "Verbosity level: %d\n", verbose);
msg_error("Verbosity level: %d\n", verbose);
return 0;
}
nverb = strtol(argv[1], &endp, 0);
if (endp == argv[1] || *endp) {
terminal_message(MSG_INFO, "%s (verbose): can't parse verbosity level %s\n",
progname, argv[1]);
pmsg_error("(verbose) cannot parse verbosity level %s\n", argv[1]);
return -1;
}
if (nverb < 0) {
terminal_message(MSG_INFO, "%s: verbosity level must not be negative: %d\n",
progname, nverb);
pmsg_error("(verbose) level must not be negative: %d\n", nverb);
return -1;
}
verbose = nverb;
terminal_message(MSG_INFO, "New verbosity level: %d\n", verbose);
term_out("New verbosity level: %d\n", verbose);
return 0;
}
@ -1055,26 +1026,24 @@ static int cmd_quell(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
char *endp;
if (argc != 1 && argc != 2) {
terminal_message(MSG_INFO, "Usage: quell [<value>]\n");
msg_error("Usage: quell [<value>]\n");
return -1;
}
if (argc == 1) {
terminal_message(MSG_INFO, "Quell level: %d\n", quell_progress);
msg_error("Quell level: %d\n", quell_progress);
return 0;
}
nquell = strtol(argv[1], &endp, 0);
if (endp == argv[1] || *endp) {
terminal_message(MSG_INFO, "%s (quell): can't parse quell level %s\n",
progname, argv[1]);
pmsg_error("(quell) cannot parse quell level %s\n", argv[1]);
return -1;
}
if (nquell < 0) {
terminal_message(MSG_INFO, "%s: quell level must not be negative: %d\n",
progname, nquell);
pmsg_error("(quell) level must not be negative: %d\n", nquell);
return -1;
}
quell_progress = nquell;
terminal_message(MSG_INFO, "New quell level: %d\n", quell_progress);
term_out("New quell level: %d\n", quell_progress);
if(quell_progress > 0)
update_progress = NULL;
@ -1195,8 +1164,7 @@ static int do_cmd(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
return cmd[i].func(pgm, p, argc, argv);
if (len && strncasecmp(argv[0], cmd[i].name, len)==0) {
if (hold != -1) {
terminal_message(MSG_INFO, "%s (cmd): command %s is ambiguous\n",
progname, argv[0]);
pmsg_error("(cmd) command %s is ambiguous\n", argv[0]);
return -1;
}
hold = i;
@ -1206,104 +1174,177 @@ static int do_cmd(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
if (hold != -1)
return cmd[hold].func(pgm, p, argc, argv);
terminal_message(MSG_INFO, "%s (cmd): invalid command %s\n",
progname, argv[0]);
pmsg_error("(cmd) invalid command %s\n", argv[0]);
return -1;
}
char *terminal_get_input(const char *prompt) {
#if defined(HAVE_LIBREADLINE) && !defined(WIN32)
char *input;
input = readline(prompt);
if ((input != NULL) && (strlen(input) >= 1))
add_history(input);
return input;
#else
char input[256];
fprintf(stdout, "%s", prompt);
if (fgets(input, sizeof(input), stdin))
{
/* FIXME: readline strips the '\n', should this too? */
return strdup(input);
term_out("%s", prompt);
if(fgets(input, sizeof(input), stdin)) {
int len = strlen(input);
if(len > 0 && input[len-1] == '\n')
input[len-1] = 0;
return cfg_strdup(__func__, input);
}
else
return NULL;
#endif
return NULL;
}
int terminal_mode(PROGRAMMER *pgm, AVRPART *p) {
char *cmdbuf;
char *q;
int rc;
int argc;
char **argv;
static int process_line(char *cmdbuf, PROGRAMMER *pgm, struct avrpart *p) {
int argc, rc;
char **argv = NULL, *q;
rc = 0;
while ((cmdbuf = terminal_get_input("avrdude> ")) != NULL) {
/*
* find the start of the command, skipping any white space
*/
q = cmdbuf;
while (*q && isspace((unsigned char) *q))
q++;
// Find the start of the command, skipping any white space
q = cmdbuf;
while(*q && isspace((unsigned char) *q))
q++;
/* skip blank lines and comments */
if (!*q || (*q == '#'))
continue;
// Skip blank lines and comments
if (!*q || (*q == '#'))
return 0;
/* tokenize command line */
argc = tokenize(q, &argv);
if (argc < 0) {
free(cmdbuf);
return argc;
}
// Tokenize command line
argc = tokenize(q, &argv);
if(!argv)
return -1;
#if !defined(HAVE_LIBREADLINE) || defined(WIN32) || defined(__APPLE__)
fprintf(stdout, ">>> ");
term_out(">>> ");
for (int i=0; i<argc; i++)
fprintf(stdout, "%s ", argv[i]);
fprintf(stdout, "\n");
term_out("%s ", argv[i]);
term_out("\n");
#endif
/* run the command */
rc = do_cmd(pgm, p, argc, argv);
free(argv);
if (rc > 0) {
rc = 0;
break;
// Run the command
rc = do_cmd(pgm, p, argc, argv);
free(argv);
return rc;
}
#if defined(HAVE_LIBREADLINE)
static PROGRAMMER *term_pgm;
static struct avrpart *term_p;
static int term_running;
// Any character in standard input available (without sleeping)?
static int readytoread() {
#ifdef WIN32
HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
while(1) {
INPUT_RECORD input[1] = { 0 };
DWORD dwNumberOfEventsRead = 0;
if(!PeekConsoleInputA(hStdin, input, ARRAYSIZE(input), &dwNumberOfEventsRead)) {
DWORD dwError = GetLastError();
// Stdin redirected from a pipe or file (FIXME: reading from a pipe may sleep)
if(dwError == ERROR_INVALID_HANDLE)
return 1;
pmsg_warning("PeekConsoleInputA() failed with error code %u\n", (unsigned int) dwError);
return -1;
}
if(dwNumberOfEventsRead <= 0) // Nothing in the input buffer
return 0;
// Filter out all the events that readline does not handle ...
if((input[0].EventType & KEY_EVENT) != 0 && input[0].Event.KeyEvent.bKeyDown)
return 1;
// Drain other events not handled by readline
if(!ReadConsoleInputA(hStdin, input, ARRAYSIZE(input), &dwNumberOfEventsRead)) {
pmsg_warning("ReadConsoleInputA() failed with error code %u\n", (unsigned int) GetLastError());
return -1;
}
free(cmdbuf);
}
#else
struct timeval tv = { 0L, 0L };
fd_set fds;
FD_ZERO(&fds);
FD_SET(0, &fds);
pgm->flush_cache(pgm, p);
return select(1, &fds, NULL, NULL, &tv) > 0;
#endif
}
return rc;
// Callback processes commands whenever readline() has finished
void term_gotline(char *cmdstr) {
if(cmdstr) {
if(*cmdstr) {
add_history(cmdstr);
// only quit/abort returns a value > 0
if(process_line(cmdstr, term_pgm, term_p) > 0)
term_running = 0;
}
free(cmdstr);
} else {
// call quit at end of file or terminal ^D
term_out("\n");
cmd_quit(term_pgm, term_p, 0, NULL);
term_running = 0;
}
}
int terminal_message(const int msglvl, const char *format, ...) {
int terminal_mode(PROGRAMMER *pgm, struct avrpart *p) {
term_pgm = pgm; // For callback routine
term_p = p;
rl_callback_handler_install("avrdude> ", term_gotline);
term_running = 1;
for(int n=1; term_running; n++) {
if(n%16 == 0) { // Every 100 ms (16*6.25 us) reset bootloader watchdog timer
if(pgm->term_keep_alive)
pgm->term_keep_alive(pgm, NULL);
}
usleep(6250);
if(readytoread() > 0 && term_running)
rl_callback_read_char();
}
rl_callback_handler_remove();
return pgm->flush_cache(pgm, p);
}
#else
int terminal_mode(PROGRAMMER *pgm, struct avrpart *p) {
char *cmdbuf;
int rc = 0;
va_list ap;
fflush(stdout); fflush(stderr);
if (verbose >= msglvl) {
va_start(ap, format);
rc = vfprintf(stderr, format, ap);
va_end(ap);
while((cmdbuf = terminal_get_input("avrdude> "))) {
int rc = process_line(cmdbuf, pgm, p);
free(cmdbuf);
if(rc > 0)
break;
}
fflush(stderr);
return rc;
if(rc <= 0)
cmd_quit(pgm, p, 0, NULL);
return pgm->flush_cache(pgm, p);
}
#endif
static void update_progress_tty(int percent, double etime, const char *hdr, int finish) {
static char *header;
static int last, done;
static int last, done = 1;
int i;
setvbuf(stderr, (char *) NULL, _IONBF, 0);
@ -1330,7 +1371,7 @@ static void update_progress_tty(int percent, double etime, const char *hdr, int
hashes[i/2] = '#';
hashes[50] = 0;
msg_info("\r%s | %s | %d%% %0.2fs", header, hashes, showperc, etime);
msg_info("\r%s | %s | %d%% %0.2f s ", header, hashes, showperc, etime);
if(percent == 100) {
if(finish)
msg_info("\n\n");
@ -1343,7 +1384,7 @@ static void update_progress_tty(int percent, double etime, const char *hdr, int
}
static void update_progress_no_tty(int percent, double etime, const char *hdr, int finish) {
static int last, done;
static int last, done = 1;
setvbuf(stderr, (char *) NULL, _IONBF, 0);

View File

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

View File

@ -335,11 +335,11 @@ int update_is_readable(const char *fn) {
static void ioerror(const char *iotype, UPDATE *upd) {
int errnocp = errno;
pmsg_ext_error("file %s is not %s", update_outname(upd->filename), iotype);
pmsg_ext_error("file %s is not %s: ", update_outname(upd->filename), iotype);
if(errnocp)
msg_ext_error("memstats(): %s", strerror(errnocp));
msg_ext_error("%s", strerror(errnocp));
else if(upd->filename && *upd->filename)
msg_ext_error(" (not a regular or character file?)");
msg_ext_error("(not a regular or character file?)");
msg_ext_error("\n");
}
@ -456,7 +456,8 @@ int do_op(PROGRAMMER * pgm, struct avrpart * p, UPDATE * upd, enum updateflags f
}
pmsg_info("reading %s%s memory ...\n", mem->desc, alias_mem_desc);
report_progress(0, 1, "Reading");
if(mem->size > 32 || verbose > 1)
report_progress(0, 1, "Reading");
rc = avr_read(pgm, p, upd->memtype, 0);
report_progress(1, 1, NULL);
@ -511,7 +512,8 @@ int do_op(PROGRAMMER * pgm, struct avrpart * p, UPDATE * upd, enum updateflags f
update_plural(fs.nbytes), mem->desc, alias_mem_desc);
if (!(flags & UF_NOWRITE)) {
report_progress(0, 1, "Writing");
if(mem->size > 32 || verbose > 1)
report_progress(0, 1, "Writing");
rc = avr_write(pgm, p, upd->memtype, size, (flags & UF_AUTO_ERASE) != 0);
report_progress(1, 1, NULL);
} else {
@ -569,7 +571,8 @@ int do_op(PROGRAMMER * pgm, struct avrpart * p, UPDATE * upd, enum updateflags f
pmsg_notice2("reading on-chip %s%s data ...\n", mem->desc, alias_mem_desc);
}
report_progress (0,1,"Reading");
if(mem->size > 32 || verbose > 1)
report_progress (0,1,"Reading");
rc = avr_read(pgm, p, upd->memtype, v);
report_progress (1,1,NULL);
if (rc < 0) {

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

View File

@ -25,19 +25,28 @@
#ifndef usbdevs_h
#define usbdevs_h
#define USB_VENDOR_ATMEL 1003
#define USB_DEVICE_JTAGICEMKII 0x2103
#define USB_DEVICE_AVRISPMKII 0x2104
#define USB_DEVICE_STK600 0x2106
#define USB_DEVICE_AVRDRAGON 0x2107
#define USB_DEVICE_JTAGICE3 0x2110
#define USB_DEVICE_XPLAINEDPRO 0x2111
#define USB_DEVICE_JTAG3_EDBG 0x2140
#define USB_DEVICE_ATMEL_ICE 0x2141
#define USB_VENDOR_ATMEL 0x03EB
#define USB_VENDOR_MICROCHIP 0x04D8
#define USB_VENDOR_FTDI 0x0403
#define USB_DEVICE_FT2232 0x6010
#define USB_DEVICE_FT245 0x6001
#define USB_DEVICE_JTAGICEMKII 0x2103
#define USB_DEVICE_AVRISPMKII 0x2104
#define USB_DEVICE_STK600 0x2106
#define USB_DEVICE_AVRDRAGON 0x2107
#define USB_DEVICE_JTAGICE3 0x2110
#define USB_DEVICE_XPLAINEDPRO 0x2111
#define USB_DEVICE_JTAG3_EDBG 0x2140
#define USB_DEVICE_ATMEL_ICE 0x2141
#define USB_DEVICE_POWERDEBUGGER 0x2144
#define USB_DEVICE_XPLAINEDMINI 0x2145
#define USB_DEVICE_PKOBN 0x2175
#define USB_DEVICE_PICKIT4_AVR_MODE 0x2177
#define USB_DEVICE_PICKIT4_PIC_MODE 0x9012
#define USB_DEVICE_SNAP_AVR_MODE 0x2180
#define USB_DEVICE_SNAP_PIC_MODE 0x9018
#define USB_VENDOR_FTDI 0x0403
#define USB_DEVICE_FT2232 0x6010
#define USB_DEVICE_FT245 0x6001
#define USBASP_SHARED_VID 0x16C0 /* VOTI */
#define USBASP_SHARED_PID 0x05DC /* Obdev's free shared PID */