From c999083b8f7a0312451ea9ed58cbb8bb76f4926d Mon Sep 17 00:00:00 2001 From: MCUdude Date: Thu, 20 Oct 2022 00:12:17 +0200 Subject: [PATCH 01/18] Change message type from error to warning and add additional USB info --- src/usb_hidapi.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/usb_hidapi.c b/src/usb_hidapi.c index b6dc3d33..4ad372b1 100644 --- a/src/usb_hidapi.c +++ b/src/usb_hidapi.c @@ -133,8 +133,9 @@ static int usbhid_open(const char *port, union pinfo pinfo, union filedescriptor 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; } } From 13817459e1010e37752a15cf45937335100ca705 Mon Sep 17 00:00:00 2001 From: MCUdude Date: Thu, 20 Oct 2022 00:12:44 +0200 Subject: [PATCH 02/18] Add missing USB VID/PIDs --- src/usbdevs.h | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/src/usbdevs.h b/src/usbdevs.h index 0dbdb482..f801e01b 100644 --- a/src/usbdevs.h +++ b/src/usbdevs.h @@ -25,19 +25,28 @@ #ifndef usbdevs_h #define usbdevs_h -#define USB_VENDOR_ATMEL 1003 -#define USB_DEVICE_JTAGICEMKII 0x2103 -#define USB_DEVICE_AVRISPMKII 0x2104 -#define USB_DEVICE_STK600 0x2106 -#define USB_DEVICE_AVRDRAGON 0x2107 -#define USB_DEVICE_JTAGICE3 0x2110 -#define USB_DEVICE_XPLAINEDPRO 0x2111 -#define USB_DEVICE_JTAG3_EDBG 0x2140 -#define USB_DEVICE_ATMEL_ICE 0x2141 +#define USB_VENDOR_ATMEL 0x03EB +#define USB_VENDOR_MICROCHIP 0x04D8 -#define USB_VENDOR_FTDI 0x0403 -#define USB_DEVICE_FT2232 0x6010 -#define USB_DEVICE_FT245 0x6001 +#define USB_DEVICE_JTAGICEMKII 0x2103 +#define USB_DEVICE_AVRISPMKII 0x2104 +#define USB_DEVICE_STK600 0x2106 +#define USB_DEVICE_AVRDRAGON 0x2107 +#define USB_DEVICE_JTAGICE3 0x2110 +#define USB_DEVICE_XPLAINEDPRO 0x2111 +#define USB_DEVICE_JTAG3_EDBG 0x2140 +#define USB_DEVICE_ATMEL_ICE 0x2141 +#define USB_DEVICE_POWERDEBUGGER 0x2144 +#define USB_DEVICE_XPLAINEDMINI 0x2145 +#define USB_DEVICE_PKOBN 0x2175 +#define USB_DEVICE_PICKIT4_AVR_MODE 0x2177 +#define USB_DEVICE_PICKIT4_PIC_MODE 0x9012 +#define USB_DEVICE_SNAP_AVR_MODE 0x2180 +#define USB_DEVICE_SNAP_PIC_MODE 0x9018 + +#define USB_VENDOR_FTDI 0x0403 +#define USB_DEVICE_FT2232 0x6010 +#define USB_DEVICE_FT245 0x6001 #define USBASP_SHARED_VID 0x16C0 /* VOTI */ #define USBASP_SHARED_PID 0x05DC /* Obdev's free shared PID */ From b083416e3b335d1ccc94a7a7fd1625d918dd8523 Mon Sep 17 00:00:00 2001 From: MCUdude Date: Thu, 20 Oct 2022 00:13:15 +0200 Subject: [PATCH 03/18] Let Avrdude use the valid SNAP USB PID first --- src/avrdude.conf.in | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/avrdude.conf.in b/src/avrdude.conf.in index 706b915a..6e3ea3cd 100644 --- a/src/avrdude.conf.in +++ b/src/avrdude.conf.in @@ -2280,7 +2280,7 @@ programmer type = "jtagice3_updi"; prog_modes = PM_UPDI; connection_type = usb; - usbpid = 0x217f, 0x2180, 0x2181; + usbpid = 0x2180, 0x217f, 0x2181; hvupdi_support = 1; ; @@ -2294,7 +2294,7 @@ programmer type = "jtagice3_pdi"; prog_modes = PM_PDI; connection_type = usb; - usbpid = 0x217f, 0x2180, 0x2181; + usbpid = 0x2180, 0x217f, 0x2181; ; #------------------------------------------------------------ @@ -2307,7 +2307,7 @@ programmer type = "jtagice3_isp"; prog_modes = PM_ISP; connection_type = usb; - usbpid = 0x217f, 0x2180, 0x2181; + usbpid = 0x2180, 0x217f, 0x2181; ; #------------------------------------------------------------ From 14446950dfdef305c4e40512434640f6188a2535 Mon Sep 17 00:00:00 2001 From: MCUdude Date: Thu, 20 Oct 2022 00:13:37 +0200 Subject: [PATCH 04/18] Check for PICkit4 or SNAP in PIC mode --- src/jtag3.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/jtag3.c b/src/jtag3.c index e3e39fbe..3ca5f4e3 100644 --- a/src/jtag3.c +++ b/src/jtag3.c @@ -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; From 867d83c21536ed7e13f32f2a3a152302e784b742 Mon Sep 17 00:00:00 2001 From: MCUdude Date: Thu, 20 Oct 2022 12:27:59 +0200 Subject: [PATCH 05/18] Print error message if no HID device is connected when using hidapi --- src/usb_hidapi.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/usb_hidapi.c b/src/usb_hidapi.c index 4ad372b1..4ddb80e3 100644 --- a/src/usb_hidapi.c +++ b/src/usb_hidapi.c @@ -93,8 +93,10 @@ static int usbhid_open(const char *port, union pinfo pinfo, union filedescriptor */ struct hid_device_info *list, *walk; list = hid_enumerate(pinfo.usbinfo.vid, pinfo.usbinfo.pid); - if (list == NULL) - return -1; + if (list == NULL) { + pmsg_error("No USB HID devices found\n"); + return -1; + } walk = list; while (walk) From 72da5c73db639c0b79cdd9a52954bf26ccb7c521 Mon Sep 17 00:00:00 2001 From: MCUdude Date: Thu, 20 Oct 2022 12:39:11 +0200 Subject: [PATCH 06/18] Fix formatting and replace tabs with spaces --- src/usb_hidapi.c | 253 +++++++++++++++++++++-------------------------- 1 file changed, 114 insertions(+), 139 deletions(-) diff --git a/src/usb_hidapi.c b/src/usb_hidapi.c index 4ddb80e3..c9fa258e 100644 --- a/src/usb_hidapi.c +++ b/src/usb_hidapi.c @@ -65,81 +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) { - pmsg_error("No USB HID devices found\n"); - 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_warning("USB device with VID: 0x%04x and PID: 0x%04x not found\n", - pinfo.usbinfo.vid, pinfo.usbinfo.pid); - 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; @@ -169,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); @@ -211,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) @@ -222,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) { @@ -247,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; @@ -282,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 @@ -324,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, From 9977f1ed129573f6e3a0365cee50fb470b76e26c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Stelmach?= Date: Thu, 20 Oct 2022 19:43:45 +0200 Subject: [PATCH 07/18] Document meaning of -F during initialization --- src/avrdude.1 | 2 ++ src/doc/avrdude.texi | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/avrdude.1 b/src/avrdude.1 index ba5292ee..5ed09b79 100644 --- a/src/avrdude.1 +++ b/src/avrdude.1 @@ -507,6 +507,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 diff --git a/src/doc/avrdude.texi b/src/doc/avrdude.texi index 1e139234..d2e9d9df 100644 --- a/src/doc/avrdude.texi +++ b/src/doc/avrdude.texi @@ -598,6 +598,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 From b9396bcd027ba2be4307f9e03e83df7a7603dc71 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Fri, 21 Oct 2022 00:56:43 +0100 Subject: [PATCH 08/18] Always use paged access for programmers that serve bootloaders --- src/avr.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/avr.c b/src/avr.c index 553e3ec4..5c97cbe7 100644 --- a/src/avr.c +++ b/src/avr.c @@ -377,8 +377,9 @@ int avr_read_mem(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, con return avr_mem_hiaddr(mem); } - if (pgm->paged_load != NULL && mem->page_size > 1 && - mem->size % mem->page_size == 0) { + // HW programmers need a page size > 1, bootloader typ only offer paged r/w + if ((pgm->paged_load && mem->page_size > 1 && mem->size % mem->page_size == 0) || + ((pgm->prog_modes & PM_SPM) && avr_has_paged_access(pgm, mem))) { /* * the programmer supports a paged mode read */ @@ -894,7 +895,9 @@ int avr_write_mem(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m, int return i; } - if (pgm->paged_write != NULL && m->page_size > 1) { + // HW programmers need a page size > 1, bootloader typ only offer paged r/w + if ((pgm->paged_load && m->page_size > 1 && m->size % m->page_size == 0) || + ((pgm->prog_modes & PM_SPM) && avr_has_paged_access(pgm, m))) { /* * the programmer supports a paged mode write */ From c890ff90ebff2fe9ad6573d1114e9fc995ef921e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Stelmach?= Date: Thu, 20 Oct 2022 17:34:21 +0200 Subject: [PATCH 09/18] Mention -B in the error message One of possible problems of failed initialization is too hight frequency of ISP clock. Mention using -B option as a possible solution. Closes #1133 --- src/doc/avrdude.texi | 13 +++++++------ src/main.c | 5 +++-- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/doc/avrdude.texi b/src/doc/avrdude.texi index d2e9d9df..ea892e1c 100644 --- a/src/doc/avrdude.texi +++ b/src/doc/avrdude.texi @@ -3046,14 +3046,15 @@ See also: @url{http://www.libusb.org/ticket/6} @item Problem: after flashing a firmware that reduces the target's clock speed (e.g. through the @code{CLKPR} register), further ISP connection -attempts fail. +attempts fail. Or a programmer cannot initialize communication with +a brand new chip. Solution: Even though ISP starts with pulling @var{/RESET} low, the -target continues to run at the internal clock speed as defined by the -firmware running before. Therefore, the ISP clock speed must be -reduced appropriately (to less than 1/4 of the internal clock speed) -using the -B option before the ISP initialization sequence will -succeed. +target continues to run at the internal clock speed either as defined by +the firmware running before or as set by the factory. Therefore, the +ISP clock speed must be reduced appropriately (to less than 1/4 of the +internal clock speed) using the -B option before the ISP initialization +sequence will succeed. As that slows down the entire subsequent ISP session, it might make sense to just issue a @emph{chip erase} using the slow ISP clock diff --git a/src/main.c b/src/main.c index 73b0a25c..49807809 100644 --- a/src/main.c +++ b/src/main.c @@ -1190,9 +1190,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; } From 992e9666a374dc863791a22bae8ac3660050f80d Mon Sep 17 00:00:00 2001 From: MCUdude Date: Sat, 22 Oct 2022 12:51:03 +0200 Subject: [PATCH 10/18] STK600 supports programming using PDI --- src/avrdude.conf.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/avrdude.conf.in b/src/avrdude.conf.in index 706b915a..b23ab46f 100644 --- a/src/avrdude.conf.in +++ b/src/avrdude.conf.in @@ -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; ; From 21e372f639ce1183c4eb7e5c8946347493dc214a Mon Sep 17 00:00:00 2001 From: mcuee Date: Sun, 23 Oct 2022 14:03:33 +0800 Subject: [PATCH 11/18] Add libreadline-dev for Linux github action build --- .github/workflows/build.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 916b7f1a..2ac4313c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -49,6 +49,7 @@ jobs: libusb-1.0-0-dev libhidapi-dev libftdi1-dev + libreadline-dev texinfo texlive texi2html @@ -110,6 +111,7 @@ jobs: libusb-1.0-0-dev:${{matrix.arch}} libhidapi-dev:${{matrix.arch}} libftdi1-dev:${{matrix.arch}} + libreadline-dev:${{matrix.arch}} - name: Configure run: >- cmake From e300861505160970f13eadc10cd81593ec8272f6 Mon Sep 17 00:00:00 2001 From: mcuee Date: Sun, 23 Oct 2022 14:40:04 +0800 Subject: [PATCH 12/18] Add readline for MSYS2 mingw32/mingw64 build --- .github/workflows/build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 916b7f1a..6704bfa6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -264,6 +264,7 @@ jobs: mingw-w64-${{matrix.env}}-libusb-compat-git mingw-w64-${{matrix.env}}-hidapi mingw-w64-${{matrix.env}}-libftdi + mingw-w64-${{matrix.env}}-readline - name: Configure run: >- cmake From 34fa2faba5629eb75309fcc34db646d6ab50192d Mon Sep 17 00:00:00 2001 From: steelman Date: Sun, 23 Oct 2022 22:52:54 +0200 Subject: [PATCH 13/18] Look for ~/.config/avrdude/avrduce.rc configuration file (#1131) * Look for ~/.config/avrdude/config configuration file Traditionally per-user configuration files have been placed in user's home directory with their names beginnig with a dot to hide them from some tools like ls(1). However, the number of programs following this convention have grown over time to the point where the number of hidden files becomes inconvenient to some users. For this reason the XDG Base Directory Specification[1] specifies an alternate place to store configuration files under ~/.config directory. This patch enables avrdude to look for ~/.config/avrdude/config configuration file, if ~/.avrduderc doesn't exist. [1] https://specifications.freedesktop.org/basedir-spec/basedir-spec-0.8.html * Safely concatenate directories and configurations files and minor changes in docs * Make stats variable available for WIN32 again in main.c * Utilise full usr_config[] array space * Check for xdg-style avrdude.rc file first before fallback ~/.avrduderc Co-authored-by: Stefan Rueger --- src/avrdude.1 | 18 +++++++++++++----- src/avrdude.conf.in | 2 +- src/avrdude.h | 1 + src/doc/avrdude.texi | 25 ++++++++++++++----------- src/main.c | 42 ++++++++++++++++++++++++++++++------------ 5 files changed, 59 insertions(+), 29 deletions(-) diff --git a/src/avrdude.1 b/src/avrdude.1 index ba5292ee..0049924f 100644 --- a/src/avrdude.1 +++ b/src/avrdude.1 @@ -1320,10 +1320,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 +1332,22 @@ On all other systems, the file is first looked up in relative to the path of the executable, then in the same directory as the executable itself, and finally in the system default location .Pa ${PREFIX}/etc/avrdude.conf . +.It Pa ${XDG_CONFIG_HOME}/avrdude/avrdude.rc +Local programmer and parts configuration file (per-user overrides); it follows the same syntax as +.Pa avrdude.conf ; +if the +.Pa ${XDG_CONFIG_HOME} +environment variable is not set or empty, the directory +.Pa ${HOME}/.config/ +is used instead. .It Pa ${HOME}/.avrduderc -programmer and parts configuration file (per-user overrides) +Alternative location of the per-user configuration file if above file does not exist .It Pa ~/.inputrc Initialization file for the .Xr readline 3 library -.It Pa ${PREFIX}/share/doc/avrdude/avrdude.pdf -Schematic of programming hardware +.It Pa /doc/avrdude/avrdude.pdf +User manual .El .\" .Sh EXAMPLES .Sh DIAGNOSTICS diff --git a/src/avrdude.conf.in b/src/avrdude.conf.in index 706b915a..67bad16f 100644 --- a/src/avrdude.conf.in +++ b/src/avrdude.conf.in @@ -389,7 +389,7 @@ # ATmega169 0x78 # -# Overall avrdude defaults; suitable for ~/.avrduderc +# Overall avrdude defaults; suitable for ~/.config/avrdude/config # default_parallel = "@DEFAULT_PAR_PORT@"; default_serial = "@DEFAULT_SER_PORT@"; diff --git a/src/avrdude.h b/src/avrdude.h index d765e9a5..a4079974 100644 --- a/src/avrdude.h +++ b/src/avrdude.h @@ -26,6 +26,7 @@ #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 diff --git a/src/doc/avrdude.texi b/src/doc/avrdude.texi index 1e139234..6e659593 100644 --- a/src/doc/avrdude.texi +++ b/src/doc/avrdude.texi @@ -1714,21 +1714,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:: diff --git a/src/main.c b/src/main.c index 73b0a25c..035a15f3 100644 --- a/src/main.c +++ b/src/main.c @@ -425,6 +425,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 +491,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 +878,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) From 5b008a04cfa825a05447c9943680d063eb115f0f Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Sun, 23 Oct 2022 21:56:45 +0100 Subject: [PATCH 14/18] Revamp terminal output: progress bar, callback and stdout/stderr (#1132) * Print parms output to stdout * Flush terminal writes and other minor changes * Prepare terminal for periodic calls to programmer to reset bootloader WDT * Only show progress reports for memories > 32 bytes or on -vv * Freeze progress bar on serious error * Allow cached r/w byte routines to be used in pgm->read_byte and pgm->write_byte --- build.sh | 4 +- src/avr.c | 5 +- src/avrcache.c | 46 +++-- src/avrdude.h | 72 ++++---- src/avrpart.c | 11 +- src/flip2.c | 4 +- src/jtag3.c | 32 ++-- src/jtag3.h | 2 +- src/jtagmkI.c | 14 +- src/jtagmkII.c | 14 +- src/libavrdude.h | 3 +- src/main.c | 34 ++-- src/pgm.c | 1 + src/stk500.c | 22 +-- src/stk500v2.c | 41 +++-- src/term.c | 455 ++++++++++++++++++++++++++--------------------- src/term.h | 1 - src/update.c | 15 +- 18 files changed, 421 insertions(+), 355 deletions(-) diff --git a/build.sh b/build.sh index bbb2f586..879c0a73 100755 --- a/build.sh +++ b/build.sh @@ -53,9 +53,9 @@ case "${ostype}" in # Apple M1 (may be new version of homebrew also) if [ -d /opt/homebrew ] then - build_flags="${build_flags} -D CMAKE_C_FLAGS=-I/opt/homebrew/include -D CMAKE_EXE_LINKER_FLAGS=-L/opt/homebrew/Cellar" + build_flags="${build_flags} -D CMAKE_C_FLAGS=-I/opt/homebrew/include -D CMAKE_EXE_LINKER_FLAGS=-L/opt/homebrew/Cellar -D HAVE_LIBREADLINE:FILEPATH=/opt/homebrew/lib/libreadline.dylib" else - build_flags="${build_flags} -D CMAKE_C_FLAGS=-I/usr/local/include -D CMAKE_EXE_LINKER_FLAGS=-L/usr/local/Cellar" + build_flags="${build_flags} -D CMAKE_C_FLAGS=-I/usr/local/include -D CMAKE_EXE_LINKER_FLAGS=-L/usr/local/Cellar -D HAVE_LIBREADLINE:FILEPATH=/usr/local/lib/libreadline.dylib" fi fi ;; diff --git a/src/avr.c b/src/avr.c index 553e3ec4..336780d3 100644 --- a/src/avr.c +++ b/src/avr.c @@ -1036,13 +1036,14 @@ int avr_write_mem(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m, int int avr_signature(const PROGRAMMER *pgm, const AVRPART *p) { int rc; - report_progress (0,1,"Reading"); + if(verbose > 1) + report_progress(0, 1, "Reading"); rc = avr_read(pgm, p, "signature", 0); if (rc < LIBAVRDUDE_SUCCESS) { pmsg_error("unable to read signature data for part %s, rc=%d\n", p->desc, rc); return rc; } - report_progress (1,1,NULL); + report_progress(1, 1, NULL); return LIBAVRDUDE_SUCCESS; } diff --git a/src/avrcache.c b/src/avrcache.c index c573014b..a0fa9082 100644 --- a/src/avrcache.c +++ b/src/avrcache.c @@ -126,6 +126,9 @@ int avr_has_paged_access(const PROGRAMMER *pgm, const AVRMEM *mem) { } +#define fallback_read_byte (pgm->read_byte != avr_read_byte_cached? pgm->read_byte: avr_read_byte_default) +#define fallback_write_byte (pgm->write_byte != avr_write_byte_cached? pgm->write_byte: avr_write_byte_default) + /* * Read the page containing addr from the device into buf * - Caller to ensure buf has mem->page_size bytes @@ -141,14 +144,14 @@ int avr_read_page_default(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM unsigned char *pagecopy = cfg_malloc("avr_read_page_default()", pgsize); if(pgsize == 1) - return pgm->read_byte(pgm, p, mem, addr, buf); + return fallback_read_byte(pgm, p, mem, addr, buf); memcpy(pagecopy, mem->buf + base, pgsize); if((rc = pgm->paged_load(pgm, p, mem, pgsize, base, pgsize)) >= 0) memcpy(buf, mem->buf + base, pgsize); memcpy(mem->buf + base, pagecopy, pgsize); - if(rc < 0) { + if(rc < 0 && pgm->read_byte != avr_read_byte_cached) { rc = LIBAVRDUDE_SUCCESS; for(int i=0; iread_byte(pgm, p, mem, base+i, pagecopy+i) < 0) { @@ -179,7 +182,7 @@ int avr_write_page_default(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM unsigned char *pagecopy = cfg_malloc("avr_write_page_default()", pgsize); if(pgsize == 1) - return pgm->write_byte(pgm, p, mem, addr, *data); + return fallback_write_byte(pgm, p, mem, addr, *data); memcpy(pagecopy, mem->buf + base, pgsize); memcpy(mem->buf + base, data, pgsize); @@ -261,18 +264,25 @@ static int loadCachePage(AVR_Cache *cp, const PROGRAMMER *pgm, const AVRPART *p, static int writeCachePage(AVR_Cache *cp, const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, int base, int nlOnErr) { // Write modified page cont to device; if unsuccessful try bytewise access if(avr_write_page_default(pgm, p, mem, base, cp->cont + base) < 0) { - for(int i=0; i < cp->page_size; i++) - if(cp->cont[base+i] != cp->copy[base+i]) - if(pgm->write_byte(pgm, p, mem, base+i, cp->cont[base+i]) < 0 || - pgm->read_byte(pgm, p, mem, base+i, cp->copy+base+i) < 0) { - report_progress(1, -1, NULL); - if(nlOnErr && quell_progress) - msg_info("\n"); - pmsg_error("writeCachePage() %s access error at addr 0x%04x\n", mem->desc, base+i); - return LIBAVRDUDE_GENERAL_FAILURE; - } + if(pgm->read_byte != avr_read_byte_cached && pgm->write_byte != avr_write_byte_cached) { + for(int i=0; i < cp->page_size; i++) + if(cp->cont[base+i] != cp->copy[base+i]) + if(pgm->write_byte(pgm, p, mem, base+i, cp->cont[base+i]) < 0 || + pgm->read_byte(pgm, p, mem, base+i, cp->copy+base+i) < 0) { + report_progress(1, -1, NULL); + if(nlOnErr && quell_progress) + msg_info("\n"); + pmsg_error("%s access error at addr 0x%04x\n", mem->desc, base+i); + return LIBAVRDUDE_GENERAL_FAILURE; + } - return LIBAVRDUDE_SUCCESS; // Bytewise writes & reads successful + return LIBAVRDUDE_SUCCESS; // Bytewise writes & reads successful + } + report_progress(1, -1, NULL); + if(nlOnErr && quell_progress) + msg_info("\n"); + pmsg_error("write %s page error at addr 0x%04x\n", mem->desc, base); + return LIBAVRDUDE_GENERAL_FAILURE; } // Read page back from device and update copy to what is on device if(avr_read_page_default(pgm, p, mem, base, cp->copy + base) < 0) { @@ -552,7 +562,7 @@ int avr_read_byte_cached(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM * // Use pgm->read_byte() if not EEPROM/flash or no paged access if(!avr_has_paged_access(pgm, mem)) - return pgm->read_byte(pgm, p, mem, addr, value); + return fallback_read_byte(pgm, p, mem, addr, value); // If address is out of range synchronise cache and, if successful, pretend reading a zero if(addr >= (unsigned long) mem->size) { @@ -592,9 +602,9 @@ int avr_read_byte_cached(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM * int avr_write_byte_cached(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, unsigned long addr, unsigned char data) { - // Use pgm->read_byte() if not EEPROM/flash or no paged access + // Use pgm->write_byte() if not EEPROM/flash or no paged access if(!avr_has_paged_access(pgm, mem)) - return pgm->write_byte(pgm, p, mem, addr, data); + return fallback_write_byte(pgm, p, mem, addr, data); // If address is out of range synchronise caches with device and return whether successful if(addr >= (unsigned long) mem->size) @@ -687,7 +697,7 @@ int avr_page_erase_cached(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM return LIBAVRDUDE_GENERAL_FAILURE; if(mem->page_size == 1) { - if(pgm->write_byte(pgm, p, mem, uaddr, 0xff) < 0) + if(fallback_write_byte(pgm, p, mem, uaddr, 0xff) < 0) return LIBAVRDUDE_GENERAL_FAILURE; } else { if(!pgm->page_erase || pgm->page_erase(pgm, p, mem, uaddr) < 0) diff --git a/src/avrdude.h b/src/avrdude.h index a4079974..7ee21bf6 100644 --- a/src/avrdude.h +++ b/src/avrdude.h @@ -21,6 +21,8 @@ #ifndef avrdude_h #define avrdude_h +#include + #define SYSTEM_CONF_FILE "avrdude.conf" #if defined(WIN32) #define USER_CONF_FILE "avrdude.rc" @@ -37,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 @@ -50,41 +52,45 @@ int avrdude_message2(const char *fname, int msgmode, int msglvl, const char *for #define MSG_TRACE2 5 // Displayed with -vvvvv #define MSG2_PROGNAME 1 // Start by printing progname -#define MSG2_FUNCTION 2 // Print calling function (1st arg) after progname -#define MSG2_TYPE 4 // Print message type after function or progname -#define MSG2_INDENT1 8 // Start by printing indentation of progname+1 blanks -#define MSG2_INDENT2 16 // Start by printing indentation of progname+2 blanks -#define MSG2_FLUSH 32 // Flush before and after printing +#define MSG2_FUNCTION 2 // Print calling function (1st arg) after progname if >= notice +#define MSG2_FILELINE 4 // Print source file and line number after function if >= debug +#define MSG2_TYPE 8 // Print message type after function or progname +#define MSG2_INDENT1 16 // Start by printing indentation of progname+1 blanks +#define MSG2_INDENT2 32 // Start by printing indentation of progname+2 blanks +#define MSG2_FLUSH 64 // Flush before and after printing // Shortcuts -#define msg_ext_error(...) avrdude_message2(__func__, 0, MSG_EXT_ERROR, __VA_ARGS__) -#define msg_error(...) avrdude_message2(__func__, 0, MSG_ERROR, __VA_ARGS__) -#define msg_warning(...) avrdude_message2(__func__, 0, MSG_WARNING, __VA_ARGS__) -#define msg_info(...) avrdude_message2(__func__, 0, MSG_INFO, __VA_ARGS__) -#define msg_notice(...) avrdude_message2(__func__, 0, MSG_NOTICE, __VA_ARGS__) -#define msg_notice2(...) avrdude_message2(__func__, 0, MSG_NOTICE2, __VA_ARGS__) -#define msg_debug(...) avrdude_message2(__func__, 0, MSG_DEBUG, __VA_ARGS__) -#define msg_trace(...) avrdude_message2(__func__, 0, MSG_TRACE, __VA_ARGS__) -#define msg_trace2(...) avrdude_message2(__func__, 0, MSG_TRACE2, __VA_ARGS__) +#define msg_ext_error(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, 0, MSG_EXT_ERROR, __VA_ARGS__) +#define msg_error(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, 0, MSG_ERROR, __VA_ARGS__) +#define msg_warning(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, 0, MSG_WARNING, __VA_ARGS__) +#define msg_info(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, 0, MSG_INFO, __VA_ARGS__) +#define msg_notice(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, 0, MSG_NOTICE, __VA_ARGS__) +#define msg_notice2(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, 0, MSG_NOTICE2, __VA_ARGS__) +#define msg_debug(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, 0, MSG_DEBUG, __VA_ARGS__) +#define msg_trace(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, 0, MSG_TRACE, __VA_ARGS__) +#define msg_trace2(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, 0, MSG_TRACE2, __VA_ARGS__) -#define pmsg_ext_error(...) avrdude_message2(__func__, MSG2_PROGNAME|MSG2_FUNCTION|MSG2_TYPE|MSG2_FLUSH, MSG_EXT_ERROR, __VA_ARGS__) -#define pmsg_error(...) avrdude_message2(__func__, MSG2_PROGNAME|MSG2_FUNCTION|MSG2_TYPE|MSG2_FLUSH, MSG_ERROR, __VA_ARGS__) -#define pmsg_warning(...) avrdude_message2(__func__, MSG2_PROGNAME|MSG2_FUNCTION|MSG2_TYPE|MSG2_FLUSH, MSG_WARNING, __VA_ARGS__) -#define pmsg_info(...) avrdude_message2(__func__, MSG2_PROGNAME|MSG2_FLUSH, MSG_INFO, __VA_ARGS__) -#define pmsg_notice(...) avrdude_message2(__func__, MSG2_PROGNAME|MSG2_FLUSH, MSG_NOTICE, __VA_ARGS__) -#define pmsg_notice2(...) avrdude_message2(__func__, MSG2_PROGNAME|MSG2_FLUSH, MSG_NOTICE2, __VA_ARGS__) -#define pmsg_debug(...) avrdude_message2(__func__, MSG2_PROGNAME|MSG2_FLUSH, MSG_DEBUG, __VA_ARGS__) -#define pmsg_trace(...) avrdude_message2(__func__, MSG2_PROGNAME|MSG2_FLUSH, MSG_TRACE, __VA_ARGS__) -#define pmsg_trace2(...) avrdude_message2(__func__, MSG2_PROGNAME|MSG2_FLUSH, MSG_TRACE2, __VA_ARGS__) +#define pmsg_ext_error(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_PROGNAME|MSG2_FUNCTION|MSG2_FILELINE|MSG2_TYPE|MSG2_FLUSH, MSG_EXT_ERROR, __VA_ARGS__) +#define pmsg_error(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_PROGNAME|MSG2_FUNCTION|MSG2_FILELINE|MSG2_TYPE|MSG2_FLUSH, MSG_ERROR, __VA_ARGS__) +#define pmsg_warning(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_PROGNAME|MSG2_FUNCTION|MSG2_FILELINE|MSG2_TYPE|MSG2_FLUSH, MSG_WARNING, __VA_ARGS__) +#define pmsg_info(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_PROGNAME|MSG2_FLUSH, MSG_INFO, __VA_ARGS__) +#define pmsg_notice(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_PROGNAME|MSG2_FLUSH, MSG_NOTICE, __VA_ARGS__) +#define pmsg_notice2(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_PROGNAME|MSG2_FLUSH, MSG_NOTICE2, __VA_ARGS__) +#define pmsg_debug(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_PROGNAME|MSG2_FLUSH, MSG_DEBUG, __VA_ARGS__) +#define pmsg_trace(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_PROGNAME|MSG2_FLUSH, MSG_TRACE, __VA_ARGS__) +#define pmsg_trace2(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_PROGNAME|MSG2_FLUSH, MSG_TRACE2, __VA_ARGS__) -#define imsg_ext_error(...) avrdude_message2(__func__, MSG2_INDENT1|MSG2_FLUSH, MSG_EXT_ERROR, __VA_ARGS__) -#define imsg_error(...) avrdude_message2(__func__, MSG2_INDENT1|MSG2_FLUSH, MSG_ERROR, __VA_ARGS__) -#define imsg_warning(...) avrdude_message2(__func__, MSG2_INDENT1|MSG2_FLUSH, MSG_WARNING, __VA_ARGS__) -#define imsg_info(...) avrdude_message2(__func__, MSG2_INDENT2|MSG2_FLUSH, MSG_INFO, __VA_ARGS__) -#define imsg_notice(...) avrdude_message2(__func__, MSG2_INDENT2|MSG2_FLUSH, MSG_NOTICE, __VA_ARGS__) -#define imsg_notice2(...) avrdude_message2(__func__, MSG2_INDENT2|MSG2_FLUSH, MSG_NOTICE2, __VA_ARGS__) -#define imsg_debug(...) avrdude_message2(__func__, MSG2_INDENT2|MSG2_FLUSH, MSG_DEBUG, __VA_ARGS__) -#define imsg_trace(...) avrdude_message2(__func__, MSG2_INDENT2|MSG2_FLUSH, MSG_TRACE, __VA_ARGS__) -#define imsg_trace2(...) avrdude_message2(__func__, MSG2_INDENT2|MSG2_FLUSH, MSG_TRACE2, __VA_ARGS__) +#define imsg_ext_error(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_INDENT1|MSG2_FLUSH, MSG_EXT_ERROR, __VA_ARGS__) +#define imsg_error(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_INDENT1|MSG2_FLUSH, MSG_ERROR, __VA_ARGS__) +#define imsg_warning(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_INDENT1|MSG2_FLUSH, MSG_WARNING, __VA_ARGS__) +#define imsg_info(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_INDENT2|MSG2_FLUSH, MSG_INFO, __VA_ARGS__) +#define imsg_notice(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_INDENT2|MSG2_FLUSH, MSG_NOTICE, __VA_ARGS__) +#define imsg_notice2(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_INDENT2|MSG2_FLUSH, MSG_NOTICE2, __VA_ARGS__) +#define imsg_debug(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_INDENT2|MSG2_FLUSH, MSG_DEBUG, __VA_ARGS__) +#define imsg_trace(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_INDENT2|MSG2_FLUSH, MSG_TRACE, __VA_ARGS__) +#define imsg_trace2(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_INDENT2|MSG2_FLUSH, MSG_TRACE2, __VA_ARGS__) + +#define term_out(...) avrdude_message2(stdout, __LINE__, __FILE__, __func__, MSG2_FLUSH, MSG_INFO, __VA_ARGS__) +#define fmsg_out(fp, ...) avrdude_message2(fp, __LINE__, __FILE__, __func__, MSG2_FLUSH, MSG_INFO, __VA_ARGS__) #endif diff --git a/src/avrpart.c b/src/avrpart.c index 49a55dba..cf4fa996 100644 --- a/src/avrpart.c +++ b/src/avrpart.c @@ -498,22 +498,15 @@ void avr_mem_display(const char *prefix, FILE *f, const AVRMEM *m, int i, j; char * optr; - if (m == NULL) { + if (m == NULL || verbose > 2) { fprintf(f, "%s Block Poll Page Polled\n" "%sMemory Type Alias Mode Delay Size Indx Paged Size Size #Pages MinW MaxW ReadBack\n" "%s----------- -------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- ---------\n", prefix, prefix, prefix); } - else { - if (verbose > 2) { - fprintf(f, - "%s Block Poll Page Polled\n" - "%sMemory Type Alias Mode Delay Size Indx Paged Size Size #Pages MinW MaxW ReadBack\n" - "%s----------- -------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- ---------\n", - prefix, prefix, prefix); - } + if (m != NULL) { // Only print memory section if the previous section printed isn't identical if(prev_mem_offset != m->offset || prev_mem_size != m->size || (strcmp(p->family_id, "") == 0)) { prev_mem_offset = m->offset; diff --git a/src/flip2.c b/src/flip2.c index 50275f46..84609576 100644 --- a/src/flip2.c +++ b/src/flip2.c @@ -121,6 +121,8 @@ enum flip2_mem_unit { FLIP2_MEM_UNIT_EXT_MEM_DF = 0x10 }; +#ifdef HAVE_LIBUSB + /* EXPORTED PROGRAMMER FUNCTION PROTOTYPES */ static int flip2_open(PROGRAMMER *pgm, const char *port_spec); @@ -146,8 +148,6 @@ static void flip2_setup(PROGRAMMER * pgm); static void flip2_teardown(PROGRAMMER * pgm); /* INTERNAL PROGRAMMER FUNCTION PROTOTYPES */ -#ifdef HAVE_LIBUSB -// The internal ones are made conditional, as they're not defined further down #ifndef HAVE_LIBUSB static void flip2_show_info(struct flip2 *flip2); diff --git a/src/jtag3.c b/src/jtag3.c index e3e39fbe..b6770b5b 100644 --- a/src/jtag3.c +++ b/src/jtag3.c @@ -103,7 +103,7 @@ static int jtag3_read_byte(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM static int jtag3_write_byte(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, unsigned long addr, unsigned char data); static int jtag3_set_sck_period(const PROGRAMMER *pgm, double v); -void jtag3_print_parms1(const PROGRAMMER *pgm, const char *p); +void jtag3_print_parms1(const PROGRAMMER *pgm, const char *p, FILE *fp); static int jtag3_paged_write(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m, unsigned int page_size, unsigned int addr, unsigned int n_bytes); @@ -1077,7 +1077,7 @@ static int jtag3_initialize(const PROGRAMMER *pgm, const AVRPART *p) { if (PDATA(pgm)->set_sck(pgm, parm) < 0) return -1; } - jtag3_print_parms1(pgm, progbuf); + jtag3_print_parms1(pgm, progbuf, stderr); if (conn == PARM3_CONN_JTAG) { pmsg_notice2("jtag3_initialize(): " @@ -2333,12 +2333,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 +2350,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 +2362,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 +2375,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 +2386,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 +2398,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 +2411,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 +2422,33 @@ void jtag3_print_parms1(const PROGRAMMER *pgm, const char *p) { return; if (b2_to_u16(buf) > 0) { - msg_info("%sJTAG clock megaAVR/program : %u kHz\n", p, b2_to_u16(buf)); + fmsg_out(fp, "%sJTAG clock megaAVR/program : %u kHz\n", p, b2_to_u16(buf)); } if (jtag3_getparm(pgm, SCOPE_AVR, 1, PARM3_CLK_MEGA_DEBUG, buf, 2) < 0) return; if (b2_to_u16(buf) > 0) { - msg_info("%sJTAG clock megaAVR/debug : %u kHz\n", p, b2_to_u16(buf)); + fmsg_out(fp, "%sJTAG clock megaAVR/debug : %u kHz\n", p, b2_to_u16(buf)); } if (jtag3_getparm(pgm, SCOPE_AVR, 1, PARM3_CLK_XMEGA_JTAG, buf, 2) < 0) return; if (b2_to_u16(buf) > 0) { - msg_info("%sJTAG clock Xmega : %u kHz\n", p, b2_to_u16(buf)); + fmsg_out(fp, "%sJTAG clock Xmega : %u kHz\n", p, b2_to_u16(buf)); } if (jtag3_getparm(pgm, SCOPE_AVR, 1, PARM3_CLK_XMEGA_PDI, buf, 2) < 0) return; if (b2_to_u16(buf) > 0) { - msg_info("%sPDI/UPDI clock Xmega/megaAVR : %u kHz\n", p, b2_to_u16(buf)); + fmsg_out(fp, "%sPDI/UPDI clock Xmega/megaAVR : %u kHz\n", p, b2_to_u16(buf)); } } -static void jtag3_print_parms(const PROGRAMMER *pgm) { - jtag3_print_parms1(pgm, ""); +static void jtag3_print_parms(const PROGRAMMER *pgm, FILE *fp) { + jtag3_print_parms1(pgm, "", fp); } static unsigned char jtag3_memtype(const PROGRAMMER *pgm, const AVRPART *p, unsigned long addr) { diff --git a/src/jtag3.h b/src/jtag3.h index 945ddcb2..7ee95b5b 100644 --- a/src/jtag3.h +++ b/src/jtag3.h @@ -38,7 +38,7 @@ int jtag3_setparm(const PROGRAMMER *pgm, unsigned char scope, unsigned char *value, unsigned char length); int jtag3_command(const PROGRAMMER *pgm, unsigned char *cmd, unsigned int cmdlen, unsigned char **resp, const char *descr); -void jtag3_print_parms1(const PROGRAMMER *pgm, const char *p); +void jtag3_print_parms1(const PROGRAMMER *pgm, const char *p, FILE *fp); int jtag3_set_vtarget(const PROGRAMMER *pgm, double voltage); extern const char jtag3_desc[]; extern const char jtag3_dw_desc[]; diff --git a/src/jtagmkI.c b/src/jtagmkI.c index 796a9cb3..9c3be6dd 100644 --- a/src/jtagmkI.c +++ b/src/jtagmkI.c @@ -104,7 +104,7 @@ static int jtagmkI_getparm(const PROGRAMMER *pgm, unsigned char parm, unsigned char * value); static int jtagmkI_setparm(const PROGRAMMER *pgm, unsigned char parm, unsigned char value); -static void jtagmkI_print_parms1(const PROGRAMMER *pgm, const char *p); +static void jtagmkI_print_parms1(const PROGRAMMER *pgm, const char *p, FILE *fp); static int jtagmkI_resync(const PROGRAMMER *pgm, int maxtries, int signon); @@ -1170,13 +1170,13 @@ static void jtagmkI_display(const PROGRAMMER *pgm, const char *p) { msg_info("%sICE HW version: 0x%02x\n", p, hw); msg_info("%sICE FW version: 0x%02x\n", p, fw); - jtagmkI_print_parms1(pgm, p); + jtagmkI_print_parms1(pgm, p, stderr); return; } -static void jtagmkI_print_parms1(const PROGRAMMER *pgm, const char *p) { +static void jtagmkI_print_parms1(const PROGRAMMER *pgm, const char *p, FILE *fp) { unsigned char vtarget, jtag_clock; const char *clkstr; double clk; @@ -1211,15 +1211,15 @@ static void jtagmkI_print_parms1(const PROGRAMMER *pgm, const char *p) { clk = 1e6; } - msg_info("%sVtarget : %.1f V\n", p, 6.25 * (unsigned)vtarget / 255.0); - msg_info("%sJTAG clock : %s (%.1f us)\n", p, clkstr, 1.0e6 / clk); + fmsg_out(fp, "%sVtarget : %.1f V\n", p, 6.25 * (unsigned)vtarget / 255.0); + fmsg_out(fp, "%sJTAG clock : %s (%.1f us)\n", p, clkstr, 1.0e6 / clk); return; } -static void jtagmkI_print_parms(const PROGRAMMER *pgm) { - jtagmkI_print_parms1(pgm, ""); +static void jtagmkI_print_parms(const PROGRAMMER *pgm, FILE *fp) { + jtagmkI_print_parms1(pgm, "", fp); } const char jtagmkI_desc[] = "Atmel JTAG ICE mkI"; diff --git a/src/jtagmkII.c b/src/jtagmkII.c index 9e3f1bbb..2f6425cf 100644 --- a/src/jtagmkII.c +++ b/src/jtagmkII.c @@ -144,7 +144,7 @@ static int jtagmkII_reset(const PROGRAMMER *pgm, unsigned char flags); static int jtagmkII_set_sck_period(const PROGRAMMER *pgm, double v); static int jtagmkII_setparm(const PROGRAMMER *pgm, unsigned char parm, unsigned char * value); -static void jtagmkII_print_parms1(const PROGRAMMER *pgm, const char *p); +static void jtagmkII_print_parms1(const PROGRAMMER *pgm, const char *p, FILE *fp); static int jtagmkII_paged_write(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m, unsigned int page_size, unsigned int addr, unsigned int n_bytes); @@ -2508,13 +2508,13 @@ static void jtagmkII_display(const PROGRAMMER *pgm, const char *p) { PDATA(pgm)->serno[0], PDATA(pgm)->serno[1], PDATA(pgm)->serno[2], PDATA(pgm)->serno[3], PDATA(pgm)->serno[4], PDATA(pgm)->serno[5]); - jtagmkII_print_parms1(pgm, p); + jtagmkII_print_parms1(pgm, p, stderr); return; } -static void jtagmkII_print_parms1(const PROGRAMMER *pgm, const char *p) { +static void jtagmkII_print_parms1(const PROGRAMMER *pgm, const char *p, FILE *fp) { unsigned char vtarget[4], jtag_clock[4]; char clkbuf[20]; double clk; @@ -2522,7 +2522,7 @@ static void jtagmkII_print_parms1(const PROGRAMMER *pgm, const char *p) { if (jtagmkII_getparm(pgm, PAR_OCD_VTARGET, vtarget) < 0) return; - msg_info("%sVtarget : %.1f V\n", p, b2_to_u16(vtarget) / 1000.0); + fmsg_out(fp, "%sVtarget : %.1f V\n", p, b2_to_u16(vtarget) / 1000.0); if ((pgm->flag & PGM_FL_IS_JTAG)) { if (jtagmkII_getparm(pgm, PAR_OCD_JTAG_CLK, jtag_clock) < 0) @@ -2541,15 +2541,15 @@ static void jtagmkII_print_parms1(const PROGRAMMER *pgm, const char *p) { sprintf(clkbuf, "%.1f kHz", 5.35e3 / (double)jtag_clock[0]); clk = 5.35e6 / (double)jtag_clock[0]; - msg_info("%sJTAG clock : %s (%.1f us)\n", p, clkbuf, 1.0e6 / clk); + fmsg_out(fp, "%sJTAG clock : %s (%.1f us)\n", p, clkbuf, 1.0e6 / clk); } } return; } -static void jtagmkII_print_parms(const PROGRAMMER *pgm) { - jtagmkII_print_parms1(pgm, ""); +static void jtagmkII_print_parms(const PROGRAMMER *pgm, FILE *fp) { + jtagmkII_print_parms1(pgm, "", fp); } static unsigned char jtagmkII_memtype(const PROGRAMMER *pgm, const AVRPART *p, unsigned long addr) { diff --git a/src/libavrdude.h b/src/libavrdude.h index b63dcd27..f4f2146d 100644 --- a/src/libavrdude.h +++ b/src/libavrdude.h @@ -783,7 +783,8 @@ typedef struct programmer_t { unsigned long addr, unsigned char *value); int (*read_sig_bytes) (const struct programmer_t *pgm, const AVRPART *p, const AVRMEM *m); int (*read_sib) (const struct programmer_t *pgm, const AVRPART *p, char *sib); - void (*print_parms) (const struct programmer_t *pgm); + int (*term_keep_alive)(const struct programmer_t *pgm, const AVRPART *p); + void (*print_parms) (const struct programmer_t *pgm, FILE *fp); int (*set_vtarget) (const struct programmer_t *pgm, double v); int (*set_varef) (const struct programmer_t *pgm, unsigned int chan, double v); int (*set_fosc) (const struct programmer_t *pgm, double v); diff --git a/src/main.c b/src/main.c index 035a15f3..8d4409f4 100644 --- a/src/main.c +++ b/src/main.c @@ -87,36 +87,48 @@ static const char *avrdude_message_type(int msglvl) { } } -int avrdude_message2(const char *fname, int msgmode, int msglvl, const char *format, ...) { +int avrdude_message2(FILE *fp, int lno, const char *file, const char *func, int msgmode, int msglvl, const char *format, ...) { int rc = 0; va_list ap; + if(msglvl <= MSG_ERROR) // Serious error? Freee progress bars (if any) + report_progress(1, -1, NULL); + if(msgmode & MSG2_FLUSH) { fflush(stdout); fflush(stderr); } - // Reduce effective verbosity level by number of -q above one - if ((quell_progress < 2? verbose: verbose+1-quell_progress) >= msglvl) { + // Reduce effective verbosity level by number of -q above one when printing to stderr + if ((quell_progress < 2 || fp != stderr? verbose: verbose+1-quell_progress) >= msglvl) { if(msgmode & MSG2_PROGNAME) { - fprintf(stderr, "%s", progname); + fprintf(fp, "%s", progname); if(verbose >= MSG_NOTICE && (msgmode & MSG2_FUNCTION)) - fprintf(stderr, " %s()", fname); + fprintf(fp, " %s()", func); + if(verbose >= MSG_DEBUG && (msgmode & MSG2_FILELINE)) { + const char *pr = strrchr(file, '/'); // only print basename +#if defined (WIN32) + if(!pr) + pr = strrchr(file, '\\'); +#endif + pr = pr? pr+1: file; + fprintf(fp, " [%s:%d]", pr, lno); + } if(msgmode & MSG2_TYPE) - fprintf(stderr, " %s", avrdude_message_type(msglvl)); - fprintf(stderr, ": "); + fprintf(fp, " %s", avrdude_message_type(msglvl)); + fprintf(fp, ": "); } else if(msgmode & MSG2_INDENT1) { - fprintf(stderr, "%*s", (int) strlen(progname)+1, ""); + fprintf(fp, "%*s", (int) strlen(progname)+1, ""); } else if(msgmode & MSG2_INDENT2) { - fprintf(stderr, "%*s", (int) strlen(progname)+2, ""); + fprintf(fp, "%*s", (int) strlen(progname)+2, ""); } va_start(ap, format); - rc = vfprintf(stderr, format, ap); + rc = vfprintf(fp, format, ap); va_end(ap); } if(msgmode & MSG2_FLUSH) - fflush(stderr); + fflush(fp); return rc; } diff --git a/src/pgm.c b/src/pgm.c index b1836e00..ccded0cc 100644 --- a/src/pgm.c +++ b/src/pgm.c @@ -140,6 +140,7 @@ PROGRAMMER *pgm_new(void) { pgm->write_setup = NULL; pgm->read_sig_bytes = NULL; pgm->read_sib = NULL; + pgm->term_keep_alive= NULL; pgm->print_parms = NULL; pgm->set_vtarget = NULL; pgm->set_varef = NULL; diff --git a/src/stk500.c b/src/stk500.c index fecd8525..35fff2c5 100644 --- a/src/stk500.c +++ b/src/stk500.c @@ -47,7 +47,7 @@ static int stk500_getparm(const PROGRAMMER *pgm, unsigned parm, unsigned *value); static int stk500_setparm(const PROGRAMMER *pgm, unsigned parm, unsigned value); -static void stk500_print_parms1(const PROGRAMMER *pgm, const char *p); +static void stk500_print_parms1(const PROGRAMMER *pgm, const char *p, FILE *fp); static int stk500_send(const PROGRAMMER *pgm, unsigned char *buf, size_t len) { @@ -1160,13 +1160,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 +1175,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 +1203,16 @@ static void stk500_print_parms1(const PROGRAMMER *pgm, const char *p) { unit = "kHz"; } else unit = "Hz"; - msg_info("%.3f %s\n", f, unit); + fmsg_out(fp, "%.3f %s\n", f, unit); } - msg_info("%sSCK period : %.1f us\n", p, sck_duration * 8.0e6 / STK500_XTAL + 0.05); + fmsg_out(fp, "%sSCK period : %.1f us\n", p, sck_duration * 8.0e6 / STK500_XTAL + 0.05); return; } -static void stk500_print_parms(const PROGRAMMER *pgm) { - stk500_print_parms1(pgm, ""); +static void stk500_print_parms(const PROGRAMMER *pgm, FILE *fp) { + stk500_print_parms1(pgm, "", fp); } static void stk500_setup(PROGRAMMER * pgm) diff --git a/src/stk500v2.c b/src/stk500v2.c index 042041a2..edf26cae 100644 --- a/src/stk500v2.c +++ b/src/stk500v2.c @@ -262,7 +262,7 @@ static int stk500v2_setparm(const PROGRAMMER *pgm, unsigned char parm, unsigned static int stk500v2_getparm2(const PROGRAMMER *pgm, unsigned char parm, unsigned int *value); static int stk500v2_setparm2(const PROGRAMMER *pgm, unsigned char parm, unsigned int value); static int stk500v2_setparm_real(const PROGRAMMER *pgm, unsigned char parm, unsigned char value); -static void stk500v2_print_parms1(const PROGRAMMER *pgm, const char *p); +static void stk500v2_print_parms1(const PROGRAMMER *pgm, const char *p, FILE *fp); static int stk500v2_paged_load(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m, unsigned int page_size, unsigned int addr, unsigned int n_bytes); @@ -3075,7 +3075,7 @@ static void stk500v2_display(const PROGRAMMER *pgm, const char *p) { stk500v2_getparm2(pgm, PARAM2_EC_ID_TABLE_REV, &rev); msg_info("%sEC_ID table rev : %d\n", p, rev); } - stk500v2_print_parms1(pgm, p); + stk500v2_print_parms1(pgm, p, stderr); return; } @@ -3095,7 +3095,7 @@ f_to_kHz_MHz(double f, const char **unit) return f; } -static void stk500v2_print_parms1(const PROGRAMMER *pgm, const char *p) { +static void stk500v2_print_parms1(const PROGRAMMER *pgm, const char *p, FILE *fp) { unsigned char vtarget = 0, vadjust = 0, osc_pscale = 0, osc_cmatch = 0, sck_duration =0; //XXX 0 is not correct, check caller unsigned int sck_stk600, clock_conf, dac, oct, varef; unsigned char vtarget_jtag[4]; @@ -3110,8 +3110,7 @@ static void stk500v2_print_parms1(const PROGRAMMER *pgm, const char *p) { pgmcp->cookie = PDATA(pgm)->chained_pdata; jtagmkII_getparm(pgmcp, PAR_OCD_VTARGET, vtarget_jtag); pgm_free(pgmcp); - msg_info("%sVtarget : %.1f V\n", p, - b2_to_u16(vtarget_jtag) / 1000.0); + fmsg_out(fp, "%sVtarget : %.1f V\n", p, b2_to_u16(vtarget_jtag) / 1000.0); } else if (PDATA(pgm)->pgmtype == PGMTYPE_JTAGICE3) { PROGRAMMER *pgmcp = pgm_dup(pgm); pgmcp->cookie = PDATA(pgm)->chained_pdata; @@ -3119,11 +3118,11 @@ static void stk500v2_print_parms1(const PROGRAMMER *pgm, const char *p) { // Copy pgm->id contents over to pgmcp->id for(LNODEID ln=lfirst(pgm->id); ln; ln=lnext(ln)) ladd(pgmcp->id, cfg_strdup("stk500v2_print_parms1()", ldata(ln))); - jtag3_print_parms1(pgmcp, p); + jtag3_print_parms1(pgmcp, p, fp); pgm_free(pgmcp); } else { stk500v2_getparm(pgm, PARAM_VTARGET, &vtarget); - msg_info("%sVtarget : %.1f V\n", p, vtarget / 10.0); + fmsg_out(fp, "%sVtarget : %.1f V\n", p, vtarget / 10.0); } switch (PDATA(pgm)->pgmtype) { @@ -3132,12 +3131,12 @@ static void stk500v2_print_parms1(const PROGRAMMER *pgm, const char *p) { stk500v2_getparm(pgm, PARAM_VADJUST, &vadjust); stk500v2_getparm(pgm, PARAM_OSC_PSCALE, &osc_pscale); stk500v2_getparm(pgm, PARAM_OSC_CMATCH, &osc_cmatch); - msg_info("%sSCK period : %.1f us\n", p, + fmsg_out(fp, "%sSCK period : %.1f us\n", p, stk500v2_sck_to_us(pgm, sck_duration)); - msg_info("%sVaref : %.1f V\n", p, vadjust / 10.0); - msg_info("%sOscillator : ", p); + fmsg_out(fp, "%sVaref : %.1f V\n", p, vadjust / 10.0); + fmsg_out(fp, "%sOscillator : ", p); if (osc_pscale == 0) - msg_info("Off\n"); + fmsg_out(fp, "Off\n"); else { prescale = 1; f = STK500V2_XTAL / 2; @@ -3153,14 +3152,14 @@ static void stk500v2_print_parms1(const PROGRAMMER *pgm, const char *p) { f /= prescale; f /= (osc_cmatch + 1); f = f_to_kHz_MHz(f, &unit); - msg_info("%.3f %s\n", f, unit); + fmsg_out(fp, "%.3f %s\n", f, unit); } break; case PGMTYPE_AVRISP_MKII: case PGMTYPE_JTAGICE_MKII: stk500v2_getparm(pgm, PARAM_SCK_DURATION, &sck_duration); - msg_info("%sSCK period : %.2f us\n", p, + fmsg_out(fp, "%sSCK period : %.2f us\n", p, (float) 1000000 / avrispmkIIfreqs[sck_duration]); break; @@ -3172,7 +3171,7 @@ static void stk500v2_print_parms1(const PROGRAMMER *pgm, const char *p) { if (stk500v2_jtag3_send(pgm, cmd, 1) >= 0 && stk500v2_jtag3_recv(pgm, cmd, 4) >= 2) { unsigned int sck = cmd[1] | (cmd[2] << 8); - msg_info("%sSCK period : %.2f us\n", p, + fmsg_out(fp, "%sSCK period : %.2f us\n", p, (float)(1E6 / (1000.0 * sck))); } } @@ -3180,23 +3179,23 @@ static void stk500v2_print_parms1(const PROGRAMMER *pgm, const char *p) { case PGMTYPE_STK600: stk500v2_getparm2(pgm, PARAM2_AREF0, &varef); - msg_info("%sVaref 0 : %.2f V\n", p, varef / 100.0); + fmsg_out(fp, "%sVaref 0 : %.2f V\n", p, varef / 100.0); stk500v2_getparm2(pgm, PARAM2_AREF1, &varef); - msg_info("%sVaref 1 : %.2f V\n", p, varef / 100.0); + fmsg_out(fp, "%sVaref 1 : %.2f V\n", p, varef / 100.0); stk500v2_getparm2(pgm, PARAM2_SCK_DURATION, &sck_stk600); - msg_info("%sSCK period : %.2f us\n", p, + fmsg_out(fp, "%sSCK period : %.2f us\n", p, (float) (sck_stk600 + 1) / 8.0); stk500v2_getparm2(pgm, PARAM2_CLOCK_CONF, &clock_conf); oct = (clock_conf & 0xf000) >> 12u; dac = (clock_conf & 0x0ffc) >> 2u; f = pow(2, (double)oct) * 2078.0 / (2 - (double)dac / 1024.0); f = f_to_kHz_MHz(f, &unit); - msg_info("%sOscillator : %.3f %s\n", + fmsg_out(fp, "%sOscillator : %.3f %s\n", p, f, unit); break; default: - msg_info("%sSCK period : %.1f us\n", p, + fmsg_out(fp, "%sSCK period : %.1f us\n", p, sck_duration * 8.0e6 / STK500V2_XTAL + 0.05); break; } @@ -3205,8 +3204,8 @@ static void stk500v2_print_parms1(const PROGRAMMER *pgm, const char *p) { } -static void stk500v2_print_parms(const PROGRAMMER *pgm) { - stk500v2_print_parms1(pgm, ""); +static void stk500v2_print_parms(const PROGRAMMER *pgm, FILE *fp) { + stk500v2_print_parms1(pgm, "", fp); } static int stk500v2_perform_osccal(const PROGRAMMER *pgm) { diff --git a/src/term.c b/src/term.c index 321722f7..cd0cdc16 100644 --- a/src/term.c +++ b/src/term.c @@ -33,10 +33,21 @@ #include #if defined(HAVE_LIBREADLINE) -# include -# include +#include +#include + +#ifdef _MSC_VER +#include "msvc/unistd.h" +#else +#include #endif +#ifdef WIN32 +#include +#endif +#endif + + #include "avrdude.h" #include "term.h" @@ -114,7 +125,7 @@ static int nexttok(char *buf, char **tok, char **next) { n = q; uint8_t quotes = 0; while (*n && (!isspace(*n) || quotes)) { - // poor man's quote and escape processing + // Poor man's quote and escape processing if (*n == '"' || *n == '\'') quotes++; else if(*n == '\\' && n[1]) @@ -173,7 +184,7 @@ static int chardump_line(char *buffer, unsigned char *p, int n, int pad) { int i; unsigned char b[128]; - // sanity check + // Sanity check n = n < 1? 1: n > sizeof b? sizeof b: n; memcpy(b, p, n); @@ -202,7 +213,7 @@ static int hexdump_buf(FILE *f, int startaddr, unsigned char *buf, int len) { n = len; hexdump_line(dst1, p, n, 48); chardump_line(dst2, p, n, 16); - fprintf(f, "%04x %s |%s|\n", addr, dst1, dst2); + term_out("%04x %s |%s|\n", addr, dst1, dst2); len -= n; addr += n; p += n; @@ -214,7 +225,7 @@ static int hexdump_buf(FILE *f, int startaddr, unsigned char *buf, int len) { static int cmd_dump(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { if (argc < 2 || argc > 4) { - terminal_message(MSG_INFO, + msg_error( "Usage: %s \n" " %s ...\n" " %s \n" @@ -229,8 +240,7 @@ static int cmd_dump(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { char *memtype = argv[1]; AVRMEM *mem = avr_locate_mem(p, memtype); if (mem == NULL) { - terminal_message(MSG_INFO, "%s (dump): %s memory type not defined for part %s\n", - progname, memtype, p->desc); + pmsg_error("(dump) %s memory type not defined for part %s\n", memtype, p->desc); return -1; } int maxsize = mem->size; @@ -242,12 +252,10 @@ static int cmd_dump(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { if (argc >= 3 && strcmp(argv[2], "...") != 0) { addr = strtoul(argv[2], &end_ptr, 0); if (*end_ptr || (end_ptr == argv[2])) { - terminal_message(MSG_INFO, "%s (dump): can't parse address %s\n", - progname, argv[2]); + pmsg_error("(dump) cannot parse address %s\n", argv[2]); return -1; } else if (addr < 0 || addr >= maxsize) { - terminal_message(MSG_INFO, "%s (dump): %s address 0x%05x is out of range [0, 0x%05x]\n", - progname, mem->desc, addr, maxsize-1); + pmsg_error("(dump) %s address 0x%05x is out of range [0, 0x%05x]\n", mem->desc, addr, maxsize-1); return -1; } } @@ -263,8 +271,7 @@ static int cmd_dump(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { } else if (argc == 4) { len = strtol(argv[3], &end_ptr, 0); if (*end_ptr || (end_ptr == argv[3])) { - terminal_message(MSG_INFO, "%s (dump): can't parse length %s\n", - progname, argv[3]); + pmsg_error("(dump) cannot parse length %s\n", argv[3]); return -1; } } else { @@ -288,7 +295,7 @@ static int cmd_dump(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { uint8_t *buf = malloc(len); if (buf == NULL) { - terminal_message(MSG_INFO, "%s (dump): out of memory\n", progname); + pmsg_error("(dump) out of memory\n"); return -1; } @@ -297,11 +304,9 @@ static int cmd_dump(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { int rc = pgm->read_byte_cached(pgm, p, mem, addr + i, &buf[i]); if (rc != 0) { report_progress(1, -1, NULL); - terminal_message(MSG_INFO, "%s (dump): error reading %s address 0x%05lx of part %s\n", - progname, mem->desc, (long) addr + i, p->desc); + pmsg_error("(dump) error reading %s address 0x%05lx of part %s\n", mem->desc, (long) addr + i, p->desc); if (rc == -1) - terminal_message(MSG_INFO, "%*sread operation not supported on memory type %s\n", - (int) strlen(progname)+9, "", mem->desc); + imsg_error("%*sread operation not supported on memory type %s\n", 7, "", mem->desc); return -1; } report_progress(i, len, NULL); @@ -309,7 +314,7 @@ static int cmd_dump(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { report_progress(1, 1, NULL); hexdump_buf(stdout, addr, buf, len); - fprintf(stdout, "\n"); + term_out("\n"); free(buf); @@ -365,7 +370,7 @@ static int is_mantissa_only(char *p) { static int cmd_write(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { if (argc < 4) { - terminal_message(MSG_INFO, + msg_error( "Usage: write [,] {[,]}\n" " write [,] {[,]} ...\n" "\n" @@ -399,14 +404,13 @@ static int cmd_write(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { } int i; - uint8_t write_mode; // Operation mode, "standard" or "fill" - uint8_t start_offset; // Which argc argument - int len; // Number of bytes to write to memory - char *memtype = argv[1]; // Memory name string + uint8_t write_mode; // Operation mode, "standard" or "fill" + uint8_t start_offset; // Which argc argument + int len; // Number of bytes to write to memory + char *memtype = argv[1]; // Memory name string AVRMEM *mem = avr_locate_mem(p, memtype); if (mem == NULL) { - terminal_message(MSG_INFO, "%s (write): %s memory type not defined for part %s\n", - progname, memtype, p->desc); + pmsg_error("(write) %s memory type not defined for part %s\n", memtype, p->desc); return -1; } int maxsize = mem->size; @@ -414,21 +418,19 @@ static int cmd_write(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { char *end_ptr; int addr = strtoul(argv[2], &end_ptr, 0); if (*end_ptr || (end_ptr == argv[2])) { - terminal_message(MSG_INFO, "%s (write): can't parse address %s\n", - progname, argv[2]); + pmsg_error("(write) cannot parse address %s\n", argv[2]); return -1; } if (addr < 0 || addr >= maxsize) { - terminal_message(MSG_INFO, "%s (write): %s address 0x%05x is out of range [0, 0x%05x]\n", - progname, mem->desc, addr, maxsize-1); + pmsg_error("(write) %s address 0x%05x is out of range [0, 0x%05x]\n", mem->desc, addr, maxsize-1); return -1; } // Allocate a buffer guaranteed to be large enough uint8_t *buf = calloc(mem->size + 8 + maxstrlen(argc-3, argv+3)+1, sizeof(uint8_t)); if (buf == NULL) { - terminal_message(MSG_INFO, "%s (write): out of memory\n", progname); + pmsg_error("(write) out of memory\n"); return -1; } @@ -438,8 +440,7 @@ static int cmd_write(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { start_offset = 4; len = strtoul(argv[3], &end_ptr, 0); if (*end_ptr || (end_ptr == argv[3])) { - terminal_message(MSG_INFO, "%s (write ...): can't parse length %s\n", - progname, argv[3]); + pmsg_error("(write ...) cannot parse length %s\n", argv[3]); free(buf); return -1; } @@ -471,8 +472,8 @@ static int cmd_write(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { }; if(sizeof(long long) != sizeof(int64_t) || (data.a[0]^data.a[7]) != 1) - terminal_message(MSG_INFO, "%s (write): assumption on data types not met? " - "Check source and recompile\n", progname); + pmsg_error("(write) assumption on data types not met? " + "Check source and recompile\n"); bool is_big_endian = data.a[7]; for (i = start_offset; i < len + start_offset; i++) { @@ -518,7 +519,7 @@ static int cmd_write(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { bool is_out_of_range = 0; int nhexdigs = p-argi-2; - if(is_signed) { // Is input in range for int64_t? + if(is_signed) { // Is input in range for int64_t? errno = 0; (void) strtoll(argi, NULL, 0); is_outside_int64_t = errno == ERANGE; } @@ -566,9 +567,8 @@ static int cmd_write(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { } if(is_outside_int64_t || is_out_of_range) - terminal_message(MSG_INFO, "%s (write): %s out of int%d_t range, " - "interpreted as %d-byte %lld; consider 'U' suffix\n", - progname, argi, data.size*8, data.size, data.ll); + pmsg_error("(write) %s out of int%d_t range, " + "interpreted as %d-byte %lld; consider 'U' suffix\n", argi, data.size*8, data.size, (long long int) data.ll); } } } @@ -583,8 +583,8 @@ static int cmd_write(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { data.f = strtof(argi, &end_ptr); if (end_ptr != argi && toupper(*end_ptr) == 'F' && end_ptr[1] == 0) data.size = 4; - if (end_ptr != argi && *end_ptr == 0) // no suffix defaults to float but ... - // ... do not accept valid mantissa-only floats that are integer rejects (eg, 078 or ULL overflows) + if (end_ptr != argi && *end_ptr == 0) // No suffix defaults to float but ... + // ... do not accept valid mantissa-only floats that are integer rejects (eg, 078 or ULL overflows) if (!is_mantissa_only(argi)) data.size = 4; } @@ -593,29 +593,27 @@ static int cmd_write(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { if ((*argi == '\'' && argi[arglen-1] == '\'') || (*argi == '\"' && argi[arglen-1] == '\"')) { char *s = calloc(arglen-1, 1); if (s == NULL) { - terminal_message(MSG_INFO, "%s (write str): out of memory\n", progname); + pmsg_error("(write str) out of memory\n"); free(buf); return -1; } // Strip start and end quotes, and unescape C string strncpy(s, argi+1, arglen-2); cfg_unescape(s, s); - if (*argi == '\'') { // Single C-style character + if (*argi == '\'') { // Single C-style character if(*s && s[1]) - terminal_message(MSG_INFO, "%s (write): only using first character of %s\n", - progname, argi); + pmsg_error("(write) only using first character of %s\n", argi); data.ll = *s; data.size = 1; free(s); - } else { // C-style string + } else { // C-style string data.str_ptr = s; } } } if(!data.size && !data.str_ptr) { - terminal_message(MSG_INFO, "%s (write): can't parse data %s\n", - progname, argi); + pmsg_error("(write) cannot parse data %s\n", argi); free(buf); return -1; } @@ -644,8 +642,8 @@ static int cmd_write(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { data.bytes_grown = 0; if ((addr + len + data.bytes_grown) > maxsize) { - terminal_message(MSG_INFO, "%s (write): selected address and # bytes exceed " - "range for %s memory\n", progname, memtype); + pmsg_error("(write) selected address and # bytes exceed " + "range for %s memory\n", memtype); free(buf); return -1; } @@ -653,11 +651,11 @@ static int cmd_write(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { if(data.str_ptr) free(data.str_ptr); - terminal_message(MSG_NOTICE, "Info: writing %d bytes starting from address 0x%02lx", + pmsg_notice2("(write) writing %d bytes starting from address 0x%02lx", len + data.bytes_grown, (long) addr); if (write_mode == WRITE_MODE_FILL) - terminal_message(MSG_NOTICE, "; remaining space filled with %s", argv[argc - 2]); - terminal_message(MSG_NOTICE, "\n"); + msg_notice2("; remaining space filled with %s", argv[argc - 2]); + msg_notice2("\n"); pgm->err_led(pgm, OFF); bool werror = false; @@ -665,19 +663,16 @@ static int cmd_write(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { for (i = 0; i < len + data.bytes_grown; i++) { int rc = pgm->write_byte_cached(pgm, p, mem, addr+i, buf[i]); if (rc) { - terminal_message(MSG_INFO, "%s (write): error writing 0x%02x at 0x%05lx, rc=%d\n", - progname, buf[i], (long) addr+i, (int) rc); + pmsg_error("(write) error writing 0x%02x at 0x%05lx, rc=%d\n", buf[i], (long) addr+i, (int) rc); if (rc == -1) - terminal_message(MSG_INFO, "%*swrite operation not supported on memory type %s\n", - (int) strlen(progname)+10, "", mem->desc); + imsg_error("%*swrite operation not supported on memory type %s\n", 8, "", mem->desc); werror = true; } uint8_t b; rc = pgm->read_byte_cached(pgm, p, mem, addr+i, &b); if (b != buf[i]) { - terminal_message(MSG_INFO, "%s (write): error writing 0x%02x at 0x%05lx cell=0x%02x\n", - progname, buf[i], (long) addr+i, b); + pmsg_error("(write) error writing 0x%02x at 0x%05lx cell=0x%02x\n", buf[i], (long) addr+i, b); werror = true; } @@ -713,14 +708,13 @@ static int cmd_send(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { int len; if (spi_mode && (pgm->spi == NULL)) { - terminal_message(MSG_INFO, "%s (send): the %s programmer does not support direct SPI transfers\n", - progname, pgm->type); + pmsg_error("(send) the %s programmer does not support direct SPI transfers\n", pgm->type); return -1; } if ((argc > 5) || ((argc < 5) && (!spi_mode))) { - terminal_message(MSG_INFO, spi_mode? + msg_error(spi_mode? "Usage: send [ [ []]]\n": "Usage: send \n"); return -1; @@ -733,8 +727,7 @@ static int cmd_send(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { for (i=1; ichip_erase_cached(pgm, p); @@ -771,20 +762,18 @@ static int cmd_erase(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { static int cmd_pgerase(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { if(argc < 3) { - terminal_message(MSG_INFO, "Usage: pgerase \n"); + msg_error("Usage: pgerase \n"); return -1; } char *memtype = argv[1]; AVRMEM *mem = avr_locate_mem(p, memtype); if(!mem) { - terminal_message(MSG_INFO, "%s (pgerase): %s memory type not defined for part %s\n", - progname, memtype, p->desc); + pmsg_error("(pgerase) %s memory type not defined for part %s\n", memtype, p->desc); return -1; } if(!avr_has_paged_access(pgm, mem)) { - terminal_message(MSG_INFO, "%s (pgerase): %s memory cannot be paged addressed by %s\n", - progname, memtype, ldata(lfirst(pgm->id))); + pmsg_error("(pgerase) %s memory cannot be paged addressed by %s\n", memtype, (char *) ldata(lfirst(pgm->id))); return -1; } @@ -793,21 +782,17 @@ static int cmd_pgerase(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { char *end_ptr; int addr = strtoul(argv[2], &end_ptr, 0); if(*end_ptr || (end_ptr == argv[2])) { - terminal_message(MSG_INFO, "%s (pgerase): can't parse address %s\n", - progname, argv[2]); + pmsg_error("(pgerase) cannot parse address %s\n", argv[2]); return -1; } if (addr < 0 || addr >= maxsize) { - terminal_message(MSG_INFO, "%s (pgerase): %s address 0x%05x is out of range [0, 0x%05x]\n", - progname, mem->desc, addr, maxsize-1); + pmsg_error("(pgerase) %s address 0x%05x is out of range [0, 0x%05x]\n", mem->desc, addr, maxsize-1); return -1; } - // terminal_message(MSG_INFO, "%s: %s page erase 0x%05x\n", progname, mem->desc, addr & ~(mem->page_size-1)); if(pgm->page_erase_cached(pgm, p, mem, (unsigned int) addr) < 0) { - terminal_message(MSG_INFO, "%s (pgerase): unable to erase %s page at 0x%05x\n", - progname, mem->desc, addr); + pmsg_error("(pgerase) unable to erase %s page at 0x%05x\n", mem->desc, addr); return -1; } @@ -816,9 +801,9 @@ static int cmd_pgerase(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { static int cmd_part(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { - fprintf(stdout, "\n"); + term_out("\n"); avr_display(stdout, p, "", 0); - fprintf(stdout, "\n"); + term_out("\n"); return 0; } @@ -831,20 +816,18 @@ static int cmd_sig(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { rc = avr_signature(pgm, p); if (rc != 0) { - terminal_message(MSG_INFO, "%s (sig): error reading signature data, rc=%d\n", - progname, rc); + pmsg_error("(sig) error reading signature data, rc=%d\n", rc); } m = avr_locate_mem(p, "signature"); if (m == NULL) { - terminal_message(MSG_INFO, "%s (sig): signature data not defined for device %s\n", - progname, p->desc); + pmsg_error("(sig) signature data not defined for device %s\n", p->desc); } else { - fprintf(stdout, "Device signature = 0x"); + term_out("Device signature = 0x"); for (i=0; isize; i++) - fprintf(stdout, "%02x", m->buf[i]); - fprintf(stdout, "\n\n"); + term_out("%02x", m->buf[i]); + term_out("\n\n"); } return 0; @@ -861,8 +844,8 @@ static int cmd_quit(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { static int cmd_parms(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { - pgm->print_parms(pgm); - terminal_message(MSG_INFO, "\n"); + pgm->print_parms(pgm, stdout); + term_out("\n"); return 0; } @@ -873,18 +856,16 @@ static int cmd_vtarg(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { char *endp; if (argc != 2) { - terminal_message(MSG_INFO, "Usage: vtarg \n"); + msg_error("Usage: vtarg \n"); return -1; } v = strtod(argv[1], &endp); if (endp == argv[1]) { - terminal_message(MSG_INFO, "%s (vtarg): can't parse voltage %s\n", - progname, argv[1]); + pmsg_error("(vtarg) cannot parse voltage %s\n", argv[1]); return -1; } if ((rc = pgm->set_vtarget(pgm, v)) != 0) { - terminal_message(MSG_INFO, "%s (vtarg): unable to set V[target] (rc = %d)\n", - progname, rc); + pmsg_error("(vtarg) unable to set V[target] (rc = %d)\n", rc); return -3; } return 0; @@ -897,7 +878,7 @@ static int cmd_fosc(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { char *endp; if (argc != 2) { - terminal_message(MSG_INFO, "Usage: fosc [M|k] | off\n"); + msg_error("Usage: fosc [M|k] | off\n"); return -1; } v = strtod(argv[1], &endp); @@ -905,8 +886,7 @@ static int cmd_fosc(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { if (strcmp(argv[1], "off") == 0) v = 0.0; else { - terminal_message(MSG_INFO, "%s (fosc): can't parse frequency %s\n", - progname, argv[1]); + pmsg_error("(fosc) cannot parse frequency %s\n", argv[1]); return -1; } } @@ -915,8 +895,7 @@ static int cmd_fosc(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { else if (*endp == 'k' || *endp == 'K') v *= 1e3; if ((rc = pgm->set_fosc(pgm, v)) != 0) { - terminal_message(MSG_INFO, "%s (fosc): unable to set oscillator frequency (rc = %d)\n", - progname, rc); + pmsg_error("(fosc) unable to set oscillator frequency (rc = %d)\n", rc); return -3; } return 0; @@ -929,19 +908,17 @@ static int cmd_sck(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { char *endp; if (argc != 2) { - terminal_message(MSG_INFO, "Usage: sck \n"); + msg_error("Usage: sck \n"); return -1; } v = strtod(argv[1], &endp); if (endp == argv[1]) { - terminal_message(MSG_INFO, "%s (sck): can't parse period %s\n", - progname, argv[1]); + pmsg_error("(sck) cannot parse period %s\n", argv[1]); return -1; } - v *= 1e-6; /* Convert from microseconds to seconds. */ + v *= 1e-6; // Convert from microseconds to seconds if ((rc = pgm->set_sck_period(pgm, v)) != 0) { - terminal_message(MSG_INFO, "%s (sck): unable to set SCK period (rc = %d)\n", - progname, rc); + pmsg_error("(sck) unable to set SCK period (rc = %d)\n", rc); return -3; } return 0; @@ -955,34 +932,30 @@ static int cmd_varef(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { char *endp; if (argc != 2 && argc != 3) { - terminal_message(MSG_INFO, "Usage: varef [channel] \n"); + msg_error("Usage: varef [channel] \n"); return -1; } if (argc == 2) { chan = 0; v = strtod(argv[1], &endp); if (endp == argv[1]) { - terminal_message(MSG_INFO, "%s (varef): can't parse voltage %s\n", - progname, argv[1]); + pmsg_error("(varef) cannot parse voltage %s\n", argv[1]); return -1; } } else { chan = strtoul(argv[1], &endp, 10); if (endp == argv[1]) { - terminal_message(MSG_INFO, "%s (varef): can't parse channel %s\n", - progname, argv[1]); + pmsg_error("(varef) cannot parse channel %s\n", argv[1]); return -1; } v = strtod(argv[2], &endp); if (endp == argv[2]) { - terminal_message(MSG_INFO, "%s (varef): can't parse voltage %s\n", - progname, argv[2]); + pmsg_error("(varef) cannot parse voltage %s\n", argv[2]); return -1; } } if ((rc = pgm->set_varef(pgm, chan, v)) != 0) { - terminal_message(MSG_INFO, "%s (varef): unable to set V[aref] (rc = %d)\n", - progname, rc); + pmsg_error("(varef) unable to set V[aref] (rc = %d)\n", rc); return -3; } return 0; @@ -992,19 +965,19 @@ static int cmd_varef(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { static int cmd_help(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { int i; - fprintf(stdout, "Valid commands:\n"); + term_out("Valid commands:\n"); for (i=0; i]\n"); + msg_error("Usage: verbose []\n"); return -1; } if (argc == 1) { - terminal_message(MSG_INFO, "Verbosity level: %d\n", verbose); + msg_error("Verbosity level: %d\n", verbose); return 0; } nverb = strtol(argv[1], &endp, 0); if (endp == argv[1] || *endp) { - terminal_message(MSG_INFO, "%s (verbose): can't parse verbosity level %s\n", - progname, argv[1]); + pmsg_error("(verbose) cannot parse verbosity level %s\n", argv[1]); return -1; } if (nverb < 0) { - terminal_message(MSG_INFO, "%s: verbosity level must not be negative: %d\n", - progname, nverb); + pmsg_error("(verbose) level must not be negative: %d\n", nverb); return -1; } verbose = nverb; - terminal_message(MSG_INFO, "New verbosity level: %d\n", verbose); + term_out("New verbosity level: %d\n", verbose); return 0; } @@ -1055,26 +1026,24 @@ static int cmd_quell(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { char *endp; if (argc != 1 && argc != 2) { - terminal_message(MSG_INFO, "Usage: quell []\n"); + msg_error("Usage: quell []\n"); return -1; } if (argc == 1) { - terminal_message(MSG_INFO, "Quell level: %d\n", quell_progress); + msg_error("Quell level: %d\n", quell_progress); return 0; } nquell = strtol(argv[1], &endp, 0); if (endp == argv[1] || *endp) { - terminal_message(MSG_INFO, "%s (quell): can't parse quell level %s\n", - progname, argv[1]); + pmsg_error("(quell) cannot parse quell level %s\n", argv[1]); return -1; } if (nquell < 0) { - terminal_message(MSG_INFO, "%s: quell level must not be negative: %d\n", - progname, nquell); + pmsg_error("(quell) level must not be negative: %d\n", nquell); return -1; } quell_progress = nquell; - terminal_message(MSG_INFO, "New quell level: %d\n", quell_progress); + term_out("New quell level: %d\n", quell_progress); if(quell_progress > 0) update_progress = NULL; @@ -1195,8 +1164,7 @@ static int do_cmd(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { return cmd[i].func(pgm, p, argc, argv); if (len && strncasecmp(argv[0], cmd[i].name, len)==0) { if (hold != -1) { - terminal_message(MSG_INFO, "%s (cmd): command %s is ambiguous\n", - progname, argv[0]); + pmsg_error("(cmd) command %s is ambiguous\n", argv[0]); return -1; } hold = i; @@ -1206,104 +1174,177 @@ static int do_cmd(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) { if (hold != -1) return cmd[hold].func(pgm, p, argc, argv); - terminal_message(MSG_INFO, "%s (cmd): invalid command %s\n", - progname, argv[0]); + pmsg_error("(cmd) invalid command %s\n", argv[0]); return -1; } char *terminal_get_input(const char *prompt) { -#if defined(HAVE_LIBREADLINE) && !defined(WIN32) - char *input; - input = readline(prompt); - if ((input != NULL) && (strlen(input) >= 1)) - add_history(input); - - return input; -#else char input[256]; - fprintf(stdout, "%s", prompt); - if (fgets(input, sizeof(input), stdin)) - { - /* FIXME: readline strips the '\n', should this too? */ - return strdup(input); + + term_out("%s", prompt); + if(fgets(input, sizeof(input), stdin)) { + int len = strlen(input); + if(len > 0 && input[len-1] == '\n') + input[len-1] = 0; + return cfg_strdup(__func__, input); } - else - return NULL; -#endif + + return NULL; } -int terminal_mode(PROGRAMMER *pgm, AVRPART *p) { - char *cmdbuf; - char *q; - int rc; - int argc; - char **argv; +static int process_line(char *cmdbuf, PROGRAMMER *pgm, struct avrpart *p) { + int argc, rc; + char **argv = NULL, *q; - rc = 0; - while ((cmdbuf = terminal_get_input("avrdude> ")) != NULL) { - /* - * find the start of the command, skipping any white space - */ - q = cmdbuf; - while (*q && isspace((unsigned char) *q)) - q++; + // Find the start of the command, skipping any white space + q = cmdbuf; + while(*q && isspace((unsigned char) *q)) + q++; - /* skip blank lines and comments */ - if (!*q || (*q == '#')) - continue; + // Skip blank lines and comments + if (!*q || (*q == '#')) + return 0; - /* tokenize command line */ - argc = tokenize(q, &argv); - if (argc < 0) { - free(cmdbuf); - return argc; - } + // Tokenize command line + argc = tokenize(q, &argv); + + if(!argv) + return -1; #if !defined(HAVE_LIBREADLINE) || defined(WIN32) || defined(__APPLE__) - fprintf(stdout, ">>> "); + term_out(">>> "); for (int i=0; i 0) { - rc = 0; - break; + // Run the command + rc = do_cmd(pgm, p, argc, argv); + free(argv); + + return rc; +} + + + +#if defined(HAVE_LIBREADLINE) + +static PROGRAMMER *term_pgm; +static struct avrpart *term_p; + +static int term_running; + +// Any character in standard input available (without sleeping)? +static int readytoread() { +#ifdef WIN32 + HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE); + + while(1) { + INPUT_RECORD input[1] = { 0 }; + DWORD dwNumberOfEventsRead = 0; + + if(!PeekConsoleInputA(hStdin, input, ARRAYSIZE(input), &dwNumberOfEventsRead)) { + DWORD dwError = GetLastError(); + + // Stdin redirected from a pipe or file (FIXME: reading from a pipe may sleep) + if(dwError == ERROR_INVALID_HANDLE) + return 1; + + pmsg_warning("PeekConsoleInputA() failed with error code %u\n", (unsigned int) dwError); + return -1; + } + + if(dwNumberOfEventsRead <= 0) // Nothing in the input buffer + return 0; + + // Filter out all the events that readline does not handle ... + if((input[0].EventType & KEY_EVENT) != 0 && input[0].Event.KeyEvent.bKeyDown) + return 1; + + // Drain other events not handled by readline + if(!ReadConsoleInputA(hStdin, input, ARRAYSIZE(input), &dwNumberOfEventsRead)) { + pmsg_warning("ReadConsoleInputA() failed with error code %u\n", (unsigned int) GetLastError()); + return -1; } - free(cmdbuf); } +#else + struct timeval tv = { 0L, 0L }; + fd_set fds; + FD_ZERO(&fds); + FD_SET(0, &fds); - pgm->flush_cache(pgm, p); + return select(1, &fds, NULL, NULL, &tv) > 0; +#endif +} - return rc; +// Callback processes commands whenever readline() has finished +void term_gotline(char *cmdstr) { + if(cmdstr) { + if(*cmdstr) { + add_history(cmdstr); + // only quit/abort returns a value > 0 + if(process_line(cmdstr, term_pgm, term_p) > 0) + term_running = 0; + } + free(cmdstr); + } else { + // call quit at end of file or terminal ^D + term_out("\n"); + cmd_quit(term_pgm, term_p, 0, NULL); + term_running = 0; + } } -int terminal_message(const int msglvl, const char *format, ...) { +int terminal_mode(PROGRAMMER *pgm, struct avrpart *p) { + term_pgm = pgm; // For callback routine + term_p = p; + + rl_callback_handler_install("avrdude> ", term_gotline); + + term_running = 1; + for(int n=1; term_running; n++) { + if(n%16 == 0) { // Every 100 ms (16*6.25 us) reset bootloader watchdog timer + if(pgm->term_keep_alive) + pgm->term_keep_alive(pgm, NULL); + } + usleep(6250); + if(readytoread() > 0 && term_running) + rl_callback_read_char(); + } + + rl_callback_handler_remove(); + + return pgm->flush_cache(pgm, p); +} + +#else + + +int terminal_mode(PROGRAMMER *pgm, struct avrpart *p) { + char *cmdbuf; int rc = 0; - va_list ap; - fflush(stdout); fflush(stderr); - if (verbose >= msglvl) { - va_start(ap, format); - rc = vfprintf(stderr, format, ap); - va_end(ap); + while((cmdbuf = terminal_get_input("avrdude> "))) { + int rc = process_line(cmdbuf, pgm, p); + free(cmdbuf); + if(rc > 0) + break; } - fflush(stderr); - return rc; + if(rc <= 0) + cmd_quit(pgm, p, 0, NULL); + return pgm->flush_cache(pgm, p); } +#endif static void update_progress_tty(int percent, double etime, const char *hdr, int finish) { static char *header; - static int last, done; + static int last, done = 1; int i; setvbuf(stderr, (char *) NULL, _IONBF, 0); @@ -1330,7 +1371,7 @@ static void update_progress_tty(int percent, double etime, const char *hdr, int hashes[i/2] = '#'; hashes[50] = 0; - msg_info("\r%s | %s | %d%% %0.2fs", header, hashes, showperc, etime); + msg_info("\r%s | %s | %d%% %0.2f s ", header, hashes, showperc, etime); if(percent == 100) { if(finish) msg_info("\n\n"); @@ -1343,7 +1384,7 @@ static void update_progress_tty(int percent, double etime, const char *hdr, int } static void update_progress_no_tty(int percent, double etime, const char *hdr, int finish) { - static int last, done; + static int last, done = 1; setvbuf(stderr, (char *) NULL, _IONBF, 0); diff --git a/src/term.h b/src/term.h index a89927ea..61c4916c 100644 --- a/src/term.h +++ b/src/term.h @@ -35,7 +35,6 @@ typedef enum { int terminal_mode(PROGRAMMER * pgm, struct avrpart * p); char * terminal_get_input(const char *prompt); void terminal_setup_update_progress(); -int terminal_message(const int msglvl, const char *format, ...); #ifdef __cplusplus } diff --git a/src/update.c b/src/update.c index e1a272c6..13580536 100644 --- a/src/update.c +++ b/src/update.c @@ -335,11 +335,11 @@ int update_is_readable(const char *fn) { static void ioerror(const char *iotype, UPDATE *upd) { int errnocp = errno; - pmsg_ext_error("file %s is not %s", update_outname(upd->filename), iotype); + pmsg_ext_error("file %s is not %s: ", update_outname(upd->filename), iotype); if(errnocp) - msg_ext_error("memstats(): %s", strerror(errnocp)); + msg_ext_error("%s", strerror(errnocp)); else if(upd->filename && *upd->filename) - msg_ext_error(" (not a regular or character file?)"); + msg_ext_error("(not a regular or character file?)"); msg_ext_error("\n"); } @@ -456,7 +456,8 @@ int do_op(PROGRAMMER * pgm, struct avrpart * p, UPDATE * upd, enum updateflags f } pmsg_info("reading %s%s memory ...\n", mem->desc, alias_mem_desc); - report_progress(0, 1, "Reading"); + if(mem->size > 32 || verbose > 1) + report_progress(0, 1, "Reading"); rc = avr_read(pgm, p, upd->memtype, 0); report_progress(1, 1, NULL); @@ -511,7 +512,8 @@ int do_op(PROGRAMMER * pgm, struct avrpart * p, UPDATE * upd, enum updateflags f update_plural(fs.nbytes), mem->desc, alias_mem_desc); if (!(flags & UF_NOWRITE)) { - report_progress(0, 1, "Writing"); + if(mem->size > 32 || verbose > 1) + report_progress(0, 1, "Writing"); rc = avr_write(pgm, p, upd->memtype, size, (flags & UF_AUTO_ERASE) != 0); report_progress(1, 1, NULL); } else { @@ -569,7 +571,8 @@ int do_op(PROGRAMMER * pgm, struct avrpart * p, UPDATE * upd, enum updateflags f pmsg_notice2("reading on-chip %s%s data ...\n", mem->desc, alias_mem_desc); } - report_progress (0,1,"Reading"); + if(mem->size > 32 || verbose > 1) + report_progress (0,1,"Reading"); rc = avr_read(pgm, p, upd->memtype, v); report_progress (1,1,NULL); if (rc < 0) { From 16922842be1d398a90ae87bfe2081fcd8cf73ecb Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Sun, 23 Oct 2022 22:26:07 +0100 Subject: [PATCH 15/18] Improve -B bitclock documentation --- src/avrdude.1 | 26 +++++++++++++++----------- src/doc/avrdude.texi | 28 +++++++++++++++------------- src/main.c | 4 ++-- 3 files changed, 32 insertions(+), 26 deletions(-) diff --git a/src/avrdude.1 b/src/avrdude.1 index c112a339..a2225a1a 100644 --- a/src/avrdude.1 +++ b/src/avrdude.1 @@ -332,18 +332,20 @@ programmed in high-voltage serial mode. Override the RS-232 connection baud rate specified in the respective programmer's entry of the configuration file. .It Fl B Ar bitclock -Specify the bit clock period for the JTAG interface or the ISP clock (JTAG ICE only). -The value is a floating-point number in microseconds. -Alternatively, the value might be suffixed with "Hz", "kHz", or "MHz", -in order to specify the bit clock frequency, rather than a period. -The default value of the JTAG ICE results in about 1 microsecond bit -clock period, suitable for target MCUs running at 4 MHz clock and -above. -Unlike certain parameters in the STK500, the JTAG ICE resets all its -parameters to default values when the programming software signs -off from the ICE, so for MCUs running at lower clock speeds, this -parameter must be specified on the command-line. +Specify the bit clock period for the JTAG, PDI, TPI, UPDI, or ISP +interface. The value is a floating-point number in microseconds. +Alternatively, the value might be suffixed with "Hz", "kHz" or +"MHz" in order to specify the bit clock frequency rather than a +period. Some programmers default their bit clock value to a 1 +microsecond bit clock period, suitable for target MCUs running at 4 +MHz clock and above. Slower MCUs need a correspondingly higher bit +clock period. Some programmers reset their bit clock value to the +default value when the programming software signs off, whilst others +store the last used bit clock value. It is recommended to always +specify the bit clock if read/write speed is important. You can use the 'default_bitclock' keyword in your +.Pa ${HOME}/.config/avrdude/avrdude.rc +or .Pa ${HOME}/.avrduderc file to assign a default value to keep from having to specify this option on every invocation. @@ -357,6 +359,8 @@ through the use of a config file to make work with different programmers as long as the programmer supports the Atmel AVR serial program method. You can use the 'default_programmer' keyword in your +.Pa ${HOME}/.config/avrdude/avrdude.rc +or .Pa ${HOME}/.avrduderc file to assign a default programmer to keep from having to specify this option on every invocation. diff --git a/src/doc/avrdude.texi b/src/doc/avrdude.texi index da8abcd3..cb8bd103 100644 --- a/src/doc/avrdude.texi +++ b/src/doc/avrdude.texi @@ -440,19 +440,21 @@ Override the RS-232 connection baud rate specified in the respective programmer's entry of the configuration file. @item -B @var{bitclock} -Specify the bit clock period for the JTAG interface or the ISP clock (JTAG ICE only). -The value is a floating-point number in microseconds. -Alternatively, the value might be suffixed with "Hz", "kHz", or "MHz", -in order to specify the bit clock frequency, rather than a period. -The default value of the JTAG ICE results in about 1 microsecond bit -clock period, suitable for target MCUs running at 4 MHz clock and -above. -Unlike certain parameters in the STK500, the JTAG ICE resets all its -parameters to default values when the programming software signs -off from the ICE, so for MCUs running at lower clock speeds, this -parameter must be specified on the command-line. -It can also be set in the configuration file by using the 'default_bitclock' -keyword. +Specify the bit clock period for the JTAG, PDI, TPI, UPDI, or ISP +interface. The value is a floating-point number in microseconds. +Alternatively, the value might be suffixed with "Hz", "kHz" or +"MHz" in order to specify the bit clock frequency rather than a +period. Some programmers default their bit clock value to a 1 +microsecond bit clock period, suitable for target MCUs running at 4 +MHz clock and above. Slower MCUs need a correspondingly higher bit +clock period. Some programmers reset their bit clock value to the +default value when the programming software signs off, whilst +others store the last used bit clock value. It is recommended to +always specify the bit clock if read/write speed is important. You +can use the 'default_bitclock' keyword in your +@code{~/.config/avrdude/avrdude.rc} or @code{~/.avrduderc} +configuration file to assign a default value to keep from having to +specify this option on every invocation. @item -c @var{programmer-id} Specify the programmer to be used. AVRDUDE knows about several common diff --git a/src/main.c b/src/main.c index 602b1adc..d1d0ebca 100644 --- a/src/main.c +++ b/src/main.c @@ -167,14 +167,14 @@ static void usage(void) "Options:\n" " -p Specify AVR device\n" " -b Override RS-232 baud rate\n" - " -B Specify JTAG/STK500v2 bit clock period (us)\n" + " -B Specify bit clock period (us)\n" " -C Specify location of configuration file\n" " -c Specify programmer type\n" " -A Disable trailing-0xff removal from file and AVR read\n" " -D Disable auto erase for flash memory; implies -A\n" " -i ISP Clock Delay [in microseconds]\n" " -P Specify connection port\n" - " -F Override invalid signature check\n" + " -F Override invalid signature or initialisation check\n" " -e Perform a chip erase\n" " -O Perform RC oscillator calibration (see AVR053)\n" " -U :r|w|v:[:format]\n" From baaad71aa5eb447470f768b5842c76caea1e7c4b Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Sun, 23 Oct 2022 22:32:29 +0100 Subject: [PATCH 16/18] Support optiboot, optiboot_dx and optiboot_x bootloaders for -c arduino (#1140) * If bootloaders are served, send word addresses for classic parts and byte addresses for newer parts, eg, UPDI and PDI * Load ext addr for stk500v1 bootloaders after grazing 64k boundaries * Fix bootloader stk500v1 EEPROM r/w for classic parts with page size 1 --- src/stk500.c | 120 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 76 insertions(+), 44 deletions(-) diff --git a/src/stk500.c b/src/stk500.c index 35fff2c5..7f26691a 100644 --- a/src/stk500.c +++ b/src/stk500.c @@ -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; From 960bf7b959e4981f8a96ed71de8709b2e8d5952d Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Sun, 23 Oct 2022 23:04:16 +0100 Subject: [PATCH 17/18] Revert "Add readline for MSYS2 mingw32/mingw64 build" --- .github/workflows/build.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6d8ae55a..2ac4313c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -266,7 +266,6 @@ jobs: mingw-w64-${{matrix.env}}-libusb-compat-git mingw-w64-${{matrix.env}}-hidapi mingw-w64-${{matrix.env}}-libftdi - mingw-w64-${{matrix.env}}-readline - name: Configure run: >- cmake From 1dba916e06e9e52a064e2a259b771f0c9cd27000 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Sun, 23 Oct 2022 23:33:56 +0100 Subject: [PATCH 18/18] Update NEWS --- NEWS | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/NEWS b/NEWS index 85a65c84..899e9373 100644 --- a/NEWS +++ b/NEWS @@ -58,6 +58,12 @@ Changes since version 7.0: - Make UPDI programmers less verbose during initialization #1084 - Quell mode isn't handled systematically #1114 + - Mixing the progress bar with warning messages #1136 + - Inconsistent terminal output re stdout and stderr #1130 + - Supress the warning for Microchip SNAP #1135 + - ATtiny85 communication problem with default bitclock #1133 + - [Regression] Optiboot for "modern AVRs" no longer works #1120 + - Cannot access EEPROM on some bootloader/part combos #970 * Pull requests: @@ -153,6 +159,16 @@ Changes since version 7.0: - Suppress Teensy USB communication error message on reboot #1122 - Fix UPDI erase when target is locked #1125 - Review and overhaul AVRDUDE's messaging system #1126 + - Look for ~/.config/avrdude/avrdude.rc then ~/.avrduderc #1131 + - Revamp terminal output (progress bar, callback and + stdout/stderr) #1132 + - Detect PICkit4 and SNAP in PIC mode #1138 + - Mention -B in the error message #1139 + - Support optiboot, optiboot_dx and optiboot_x bootloaders for + -c arduino #1140 + - Always use paged access for programmers that serve + bootloaders #1141 + - Add libreadline-dev for Linux github action build #1146 * Internals: