From 625027a807f97eedf6339e033a7b10cadb56f415 Mon Sep 17 00:00:00 2001 From: MCUdude Date: Sat, 5 Feb 2022 14:44:13 +0100 Subject: [PATCH 01/57] Add HV UPDI pulse command --- src/jtag3.c | 4 ++++ src/jtag3_private.h | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/src/jtag3.c b/src/jtag3.c index 1681a001..b0815986 100644 --- a/src/jtag3.c +++ b/src/jtag3.c @@ -1247,6 +1247,10 @@ static int jtag3_initialize(PROGRAMMER * pgm, AVRPART * p) } } + parm[0] = PARM3_UPDI_HV_SIMPLE_PULSE; + if (jtag3_setparm(pgm, SCOPE_AVR, 3, PARM3_OPT_12V_UPDI_ENABLE, parm, 1) < 0) + return -1; + u16_to_b2(xd.default_min_div1_voltage, DEFAULT_MINIMUM_CHARACTERISED_DIV1_VOLTAGE_MV); u16_to_b2(xd.default_min_div2_voltage, DEFAULT_MINIMUM_CHARACTERISED_DIV2_VOLTAGE_MV); u16_to_b2(xd.default_min_div4_voltage, DEFAULT_MINIMUM_CHARACTERISED_DIV4_VOLTAGE_MV); diff --git a/src/jtag3_private.h b/src/jtag3_private.h index a3e7fb08..3eeb61b3 100644 --- a/src/jtag3_private.h +++ b/src/jtag3_private.h @@ -236,6 +236,14 @@ #define PARM3_OPT_12V_UPDI_ENABLE 0x06 #define PARM3_OPT_CHIP_ERASE_TO_ENTER 0x07 +/* + * UPDI high-voltage enable modes + */ +#define PARM3_UPDI_HV_NONE 0x00 /* Do not use high-voltage */ +#define PARM3_UPDI_HV_SIMPLE_PULSE 0x01 /* Issue a single high-voltage pulse immediately*/ +#define PARM3_UPDI_HV_AUTO_POWER_TOGGLE 0x02 /* Toggle power automatically and then apply a high-voltage pulse */ +#define PARM3_UPDI_HV_USER_POWER_TOGGLE 0x03 /* The user toggles power, and the tool applies a high-voltage pulse on power-up */ + /* Xmega erase memory types, for CMND_XMEGA_ERASE */ #define XMEGA_ERASE_CHIP 0x00 #define XMEGA_ERASE_APP 0x01 From 6fceea8f71a531178eeb964f0e12f93a0f7e81dd Mon Sep 17 00:00:00 2001 From: MCUdude Date: Sun, 10 Apr 2022 23:36:53 +0200 Subject: [PATCH 02/57] Fix linuxspi default port If no port is specified, Avrdude will try to use the default port specified in avrdude.conf. If not present, use port specified in linuxspi.c --- src/avrdude.conf.in | 4 +++- src/config.c | 1 + src/config_gram.y | 11 ++++++++++- src/lexer.l | 2 ++ src/libavrdude.h | 4 +++- src/main.c | 7 +++++++ 6 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/avrdude.conf.in b/src/avrdude.conf.in index 096751d0..13f8034c 100644 --- a/src/avrdude.conf.in +++ b/src/avrdude.conf.in @@ -22,7 +22,7 @@ # desc = ; # quoted string # type = ; # programmer type, quoted string # # supported programmer types can be listed by "-c ?type" -# connection_type = parallel | serial | usb +# connection_type = parallel | serial | usb | spi # baudrate = ; # baudrate for avr910-programmer # vcc = [, ... ] ; # pin number(s) # buff = [, ... ] ; # pin number(s) @@ -337,6 +337,7 @@ # default_parallel = "@DEFAULT_PAR_PORT@"; default_serial = "@DEFAULT_SER_PORT@"; +default_spi = "@DEFAULT_SPI_PORT@"; # default_bitclock = 2.5; # @@ -1609,6 +1610,7 @@ programmer id = "linuxspi"; desc = "Use Linux SPI device in /dev/spidev*"; type = "linuxspi"; + connection_type = spi; reset = 25; # Pi GPIO number - this is J8:22 ; @HAVE_LINUXSPI_END@ diff --git a/src/config.c b/src/config.c index 3d8a760e..00ac8b0e 100644 --- a/src/config.c +++ b/src/config.c @@ -35,6 +35,7 @@ char default_programmer[MAX_STR_CONST]; char default_parallel[PATH_MAX]; char default_serial[PATH_MAX]; +char default_spi[PATH_MAX]; double default_bitclock; char string_buf[MAX_STR_CONST]; diff --git a/src/config_gram.y b/src/config_gram.y index a8416162..20830ca7 100644 --- a/src/config_gram.y +++ b/src/config_gram.y @@ -79,6 +79,7 @@ static int pin_name; %token K_DEFAULT_PARALLEL %token K_DEFAULT_PROGRAMMER %token K_DEFAULT_SERIAL +%token K_DEFAULT_SPI %token K_DESC %token K_FAMILY_ID %token K_DEVICECODE @@ -115,6 +116,7 @@ static int pin_name; %token K_RESET %token K_RETRY_PULSE %token K_SERIAL +%token K_SPI %token K_SCK %token K_SIGNATURE %token K_SIZE @@ -254,6 +256,12 @@ def : free_token($3); } | + K_DEFAULT_SPI TKN_EQUAL TKN_STRING TKN_SEMI { + strncpy(default_spi, $3->value.string, PATH_MAX); + default_spi[PATH_MAX-1] = 0; + free_token($3); + } | + K_DEFAULT_BITCLOCK TKN_EQUAL number_real TKN_SEMI { default_bitclock = $3->value.number_real; free_token($3); @@ -507,7 +515,8 @@ prog_parm_conntype: prog_parm_conntype_id: K_PARALLEL { current_prog->conntype = CONNTYPE_PARALLEL; } | K_SERIAL { current_prog->conntype = CONNTYPE_SERIAL; } | - K_USB { current_prog->conntype = CONNTYPE_USB; } + K_USB { current_prog->conntype = CONNTYPE_USB; } | + K_SPI { current_prog->conntype = CONNTYPE_SPI; } ; prog_parm_usb: diff --git a/src/lexer.l b/src/lexer.l index 0b31eb21..00e83d6b 100644 --- a/src/lexer.l +++ b/src/lexer.l @@ -139,6 +139,7 @@ default_bitclock { yylval=NULL; return K_DEFAULT_BITCLOCK; } default_parallel { yylval=NULL; return K_DEFAULT_PARALLEL; } default_programmer { yylval=NULL; return K_DEFAULT_PROGRAMMER; } default_serial { yylval=NULL; return K_DEFAULT_SERIAL; } +default_spi { yylval=NULL; return K_DEFAULT_SPI; } delay { yylval=NULL; return K_DELAY; } desc { yylval=NULL; return K_DESC; } family_id { yylval=NULL; return K_FAMILY_ID; } @@ -222,6 +223,7 @@ sck { yylval=new_token(K_SCK); return K_SCK; } serial { yylval=NULL; return K_SERIAL; } signature { yylval=NULL; return K_SIGNATURE; } size { yylval=NULL; return K_SIZE; } +spi { yylval=NULL; return K_SPI; } spmcr { yylval=NULL; return K_SPMCR; } stabdelay { yylval=NULL; return K_STABDELAY; } stk500_devcode { yylval=NULL; return K_STK500_DEVCODE; } diff --git a/src/libavrdude.h b/src/libavrdude.h index ddb72b48..7ec7dd85 100644 --- a/src/libavrdude.h +++ b/src/libavrdude.h @@ -635,7 +635,8 @@ typedef enum { typedef enum { CONNTYPE_PARALLEL, CONNTYPE_SERIAL, - CONNTYPE_USB + CONNTYPE_USB, + CONNTYPE_SPI } conntype_t; typedef struct programmer_t { @@ -912,6 +913,7 @@ extern LISTID programmers; extern char default_programmer[]; extern char default_parallel[]; extern char default_serial[]; +extern char default_spi[]; extern double default_bitclock; /* This name is fixed, it's only here for symmetry with diff --git a/src/main.c b/src/main.c index 253c6e51..7198c42d 100644 --- a/src/main.c +++ b/src/main.c @@ -382,6 +382,7 @@ int main(int argc, char * argv []) default_parallel[0] = 0; default_serial[0] = 0; + default_spi[0] = 0; default_bitclock = 0.0; init_config(); @@ -921,6 +922,12 @@ int main(int argc, char * argv []) case CONNTYPE_USB: port = DEFAULT_USB; break; + +#ifdef HAVE_LINUXSPI + case CONNTYPE_SPI: + port = *default_spi ? default_spi : "unknown"; + break; +#endif } } From ba98e48880c030d90d9d4dd752a895fa29295607 Mon Sep 17 00:00:00 2001 From: MCUdude Date: Sun, 26 Jun 2022 00:11:51 +0200 Subject: [PATCH 03/57] add "hvupdi_variant" property to avrdude.conf --- src/avrdude.conf.in | 44 ++++++++++++++++++++++++++------------------ src/config_gram.y | 7 +++++++ src/lexer.l | 1 + src/libavrdude.h | 1 + 4 files changed, 35 insertions(+), 18 deletions(-) diff --git a/src/avrdude.conf.in b/src/avrdude.conf.in index ba7f4f8e..2fc59ecd 100644 --- a/src/avrdude.conf.in +++ b/src/avrdude.conf.in @@ -17114,13 +17114,15 @@ part # AVR8X tiny family common values #------------------------------------------------------------ -part parent ".avr8x" - id = ".avr8x_tiny"; - desc = "AVR8X tiny family common values"; - family_id = "tinyAVR"; +part parent ".avr8x" + id = ".avr8x_tiny"; + desc = "AVR8X tiny family common values"; + family_id = "tinyAVR"; + # Shared UPDI pin, HV on UPDI pin + hvupdi_variant = 0; memory "userrow" - size = 0x20; + size = 0x20; offset = 0x1300; page_size = 0x20; readsize = 0x100; @@ -17135,13 +17137,15 @@ part parent ".avr8x" # AVR8X mega family common values #------------------------------------------------------------ -part parent ".avr8x" - id = ".avr8x_mega"; - desc = "AVR8X mega family common values"; - family_id = "megaAVR"; +part parent ".avr8x" + id = ".avr8x_mega"; + desc = "AVR8X mega family common values"; + family_id = "megaAVR"; + # Dedicated UPDI pin, no HV + hvupdi_variant = 1; memory "userrow" - size = 0x40; + size = 0x40; offset = 0x1300; page_size = 0x40; readsize = 0x100; @@ -18240,11 +18244,13 @@ part parent ".avr8x_mega" #------------------------------------------------------------ part - id = ".avrdx"; - desc = "AVR-Dx family common values"; - has_updi = yes; - nvm_base = 0x1000; - ocd_base = 0x0F80; + id = ".avrdx"; + desc = "AVR-Dx family common values"; + has_updi = yes; + nvm_base = 0x1000; + ocd_base = 0x0F80; + # Dedicated UPDI pin, no HV + hvupdi_variant = 1; memory "signature" size = 3; @@ -19210,9 +19216,11 @@ part parent ".avrdx" # AVR-Ex family common values #------------------------------------------------------------ -part parent ".avrdx" - id = ".avrex"; - desc = "AVR-Ex family common values"; +part parent ".avrdx" + id = ".avrex"; + desc = "AVR-Ex family common values"; + # Shared UPDI pin, HV on _RESET + hvupdi_variant = 2; memory "userrow" size = 0x40; diff --git a/src/config_gram.y b/src/config_gram.y index a8416162..126b9b54 100644 --- a/src/config_gram.y +++ b/src/config_gram.y @@ -81,6 +81,7 @@ static int pin_name; %token K_DEFAULT_SERIAL %token K_DESC %token K_FAMILY_ID +%token K_HVUPDI_VARIANT %token K_DEVICECODE %token K_STK500_DEVCODE %token K_AVR910_DEVCODE @@ -676,6 +677,12 @@ part_parm : free_token($3); } | + K_HVUPDI_VARIANT TKN_EQUAL TKN_NUMBER + { + current_part->hvupdi_variant = $3->value.number; + free_token($3); + } | + K_DEVICECODE TKN_EQUAL TKN_NUMBER { { yyerror("devicecode is deprecated, use " diff --git a/src/lexer.l b/src/lexer.l index 0b31eb21..dd5c081a 100644 --- a/src/lexer.l +++ b/src/lexer.l @@ -159,6 +159,7 @@ hventerstabdelay { yylval=NULL; return K_HVENTERSTABDELAY; } hvleavestabdelay { yylval=NULL; return K_HVLEAVESTABDELAY; } hvsp_controlstack { yylval=NULL; return K_HVSP_CONTROLSTACK; } hvspcmdexedelay { yylval=NULL; return K_HVSPCMDEXEDELAY; } +hvupdi_variant { yylval=NULL; return K_HVUPDI_VARIANT; } id { yylval=NULL; return K_ID; } idr { yylval=NULL; return K_IDR; } io { yylval=new_token(K_IO); return K_IO; } diff --git a/src/libavrdude.h b/src/libavrdude.h index ddb72b48..2b87ddf1 100644 --- a/src/libavrdude.h +++ b/src/libavrdude.h @@ -202,6 +202,7 @@ typedef struct avrpart { char desc[AVR_DESCLEN]; /* long part name */ char id[AVR_IDLEN]; /* short part name */ char family_id[AVR_FAMILYIDLEN+1]; /* family id in the SIB (avr8x) */ + int hvupdi_variant; /* 12V pulse on UPDI pin, no pin or RESET pin */ int stk500_devcode; /* stk500 device code */ int avr910_devcode; /* avr910 device code */ int chip_erase_delay; /* microseconds */ From f67c35744e7522a61ff1d67efef4adc27278e1b0 Mon Sep 17 00:00:00 2001 From: MCUdude Date: Sun, 26 Jun 2022 00:13:56 +0200 Subject: [PATCH 04/57] add support for "-x hvupdi" that triggers HV UPDI --- src/jtag3.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/jtag3.c b/src/jtag3.c index 4e3ef8c2..976291f4 100644 --- a/src/jtag3.c +++ b/src/jtag3.c @@ -71,6 +71,9 @@ struct pdata /* Start address of Xmega boot area */ unsigned long boot_start; + /* Flag for triggering HV UPDI */ + bool use_hvupdi; + /* Function to set the appropriate clock parameter */ int (*set_sck)(PROGRAMMER *, unsigned char *); }; @@ -1249,10 +1252,12 @@ static int jtag3_initialize(PROGRAMMER * pgm, AVRPART * p) } } - parm[0] = PARM3_UPDI_HV_SIMPLE_PULSE; - if (jtag3_setparm(pgm, SCOPE_AVR, 3, PARM3_OPT_12V_UPDI_ENABLE, parm, 1) < 0) - return -1; - + // Generate 12V UPDI pulse if user asks for it and hardware supports it + if(p->flags & AVRPART_HAS_UPDI && PDATA(pgm)->use_hvupdi == true && p->hvupdi_variant == 0) { + parm[0] = PARM3_UPDI_HV_SIMPLE_PULSE; + if (jtag3_setparm(pgm, SCOPE_AVR, 3, PARM3_OPT_12V_UPDI_ENABLE, parm, 1) < 0) + return -1; + } u16_to_b2(xd.default_min_div1_voltage, DEFAULT_MINIMUM_CHARACTERISED_DIV1_VOLTAGE_MV); u16_to_b2(xd.default_min_div2_voltage, DEFAULT_MINIMUM_CHARACTERISED_DIV2_VOLTAGE_MV); u16_to_b2(xd.default_min_div4_voltage, DEFAULT_MINIMUM_CHARACTERISED_DIV4_VOLTAGE_MV); @@ -1477,6 +1482,10 @@ static int jtag3_parseextparms(PROGRAMMER * pgm, LISTID extparms) continue; } + else if (matches(extended_param, "hvupdi") || matches(extended_param, "hvupdi=1")) { + PDATA(pgm)->use_hvupdi = true; + continue; + } avrdude_message(MSG_INFO, "%s: jtag3_parseextparms(): invalid extended parameter '%s'\n", progname, extended_param); @@ -2601,6 +2610,7 @@ void jtag3_updi_initpgm(PROGRAMMER * pgm) * mandatory functions */ pgm->initialize = jtag3_initialize; + pgm->parseextparams = jtag3_parseextparms; pgm->display = jtag3_display; pgm->enable = jtag3_enable; pgm->disable = jtag3_disable; From e0683417163d1563cedbfeb0a2c23e4d783d4940 Mon Sep 17 00:00:00 2001 From: MCUdude Date: Sun, 26 Jun 2022 10:19:27 +0200 Subject: [PATCH 05/57] Make sure "-x hvupdi" is only valid for Pickit4 and Powerdebugger --- src/jtag3.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/jtag3.c b/src/jtag3.c index 976291f4..5e971a28 100644 --- a/src/jtag3.c +++ b/src/jtag3.c @@ -1458,6 +1458,7 @@ static int jtag3_parseextparms(PROGRAMMER * pgm, LISTID extparms) LNODEID ln; const char *extended_param; int rv = 0; + avrdude_message(MSG_INFO, "id: %s, desc: %s, type: %s\n", ldata(lfirst(pgm->id)), pgm->desc, pgm->type); for (ln = lfirst(extparms); ln; ln = lnext(ln)) { extended_param = ldata(ln); @@ -1482,7 +1483,9 @@ static int jtag3_parseextparms(PROGRAMMER * pgm, LISTID extparms) continue; } - else if (matches(extended_param, "hvupdi") || matches(extended_param, "hvupdi=1")) { + + else if ((matches(extended_param, "hvupdi") || matches(extended_param, "hvupdi=1")) && + (matches(ldata(lfirst(pgm->id)), "pickit4_updi") || matches(ldata(lfirst(pgm->id)), "powerdebugger_updi"))) { PDATA(pgm)->use_hvupdi = true; continue; } From 50220289bb8b369ccb89fade961f60d8c593d556 Mon Sep 17 00:00:00 2001 From: MCUdude Date: Sun, 26 Jun 2022 19:35:39 +0200 Subject: [PATCH 06/57] Add high-voltage UPDI info to docs --- src/avrdude.1 | 20 ++++++++++++++++---- src/doc/avrdude.texi | 20 +++++++++++++++++--- 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/src/avrdude.1 b/src/avrdude.1 index 81834d30..5ecccb6b 100644 --- a/src/avrdude.1 +++ b/src/avrdude.1 @@ -179,7 +179,7 @@ has a revision 1 hardware and firmware version of at least 5.37 (decimal). For ATxmega devices, the JTAGICE3 is supported in PDI mode. .Pp Atmel-ICE (ARM/AVR) is supported in all modes (JTAG, PDI for Xmega, debugWIRE, -ISP). +ISP, UPDI). .Pp Atmel's XplainedPro boards, using the EDBG protocol (CMSIS-DAP compatible), are supported using the "jtag3" programmer type. @@ -225,7 +225,7 @@ thus the name SerialUPDI programmer implementation is based on Microchip's .Em pymcuprog Li https://github.com/microchip-pic-avr-tools/pymcuprog utility, but it also contains some performance improvements included in -Spence Kohde's +Spence Konde's .Em DxCore Arduino core .Li https://github.com/SpenceKonde/DxCore . @@ -959,9 +959,13 @@ versions of the bootloader. .It Ar JTAG ICE mkII .It Ar JTAGICE3 .It Ar Atmel-ICE +.It Ar Power Debugger +.It Ar PICkit 4 +.It Ar MPLAB SNAP .It Ar AVR Dragon -When using the JTAG ICE mkII, JTAGICE3, Atmel-ICE or AVR Dragon in JTAG mode, the -following extended parameter is accepted: +When using the JTAG ICE mkII, JTAGICE3, Atmel-ICE, PICkit 4, MPLAB SNAP, +Power Debugger or AVR Dragon in JTAG mode, the following extended parameter +is accepted: .Bl -tag -offset indent -width indent .It Ar jtagchain=UB,UA,BB,BA Setup the JTAG scan chain for @@ -976,6 +980,14 @@ bits after the target AVR, respectively. Each AVR unit within the chain shifts by 4 bits. Other JTAG units might require a different bit shift count. .El +.Pp +The PICkit 4 and the Power Debugger also supports high-voltage UPDI programming. +This is used to enable a UPDI pin that has previously been set to RESET or +GPIO mode. High-voltage UPDI can be utilized by using an extended parameter: +.Bl -tag -offset indent -width indent +.It Ar hvupdi +Enable high-voltage UPDI initialization for targets that supports this. +.El .It Ar AVR910 .Bl -tag -offset indent -width indent .It Ar devcode=VALUE diff --git a/src/doc/avrdude.texi b/src/doc/avrdude.texi index 92cf4df4..20c8612a 100644 --- a/src/doc/avrdude.texi +++ b/src/doc/avrdude.texi @@ -250,7 +250,8 @@ See below for the limitations of debugWire. For ATxmega devices, the JTAG ICE mkII/3 is supported in PDI mode, provided it has a revision 1 hardware and firmware version of at least 5.37 (decimal). -The Atmel-ICE (ARM/AVR) is supported (JTAG, PDI for Xmega, debugWIRE, ISP modes). +The Atmel-ICE (ARM/AVR) is supported (JTAG, PDI for Xmega, debugWIRE, ISP, +UPDI). Atmel's XplainedPro boards, using EDBG protocol (CMSIS-DAP compliant), are supported by the ``jtag3'' programmer type. @@ -843,10 +844,15 @@ accepting extended parameters. @table @code @item JTAG ICE mkII/3 +@itemx Atmel-ICE +@itemx PICkit 4 +@itemx MPLAB SNAP +@itemx Power Debugger @itemx AVR Dragon -When using the JTAG ICE mkII/3 or AVR Dragon in JTAG mode, the -following extended parameter is accepted: +When using the JTAG ICE mkII, JTAGICE3, Atmel-ICE, PICkit 4, MPLAB SNAP, +Power Debugger or AVR Dragon in JTAG mode, the following extended parameter +is accepted: @table @code @item @samp{jtagchain=UB,UA,BB,BA} Setup the JTAG scan chain for @var{UB} units before, @var{UA} units @@ -856,6 +862,14 @@ Each AVR unit within the chain shifts by 4 bits. Other JTAG units might require a different bit shift count. @end table +The PICkit 4 and the Power Debugger also supports high-voltage UPDI programming. +This is used to enable a UPDI pin that has previously been set to RESET or +GPIO mode. High-voltage UPDI can be utilized by using an extended parameter: +@table @code +@item @samp{hvupdi} +Enable high-voltage UPDI initialization for targets that supports this. +@end table + @cindex @code{-x} AVR910 @item AVR910 From 577856cf15700c048f1dd1cac7ca3a92d2f12b4d Mon Sep 17 00:00:00 2001 From: MCUdude Date: Sun, 26 Jun 2022 19:54:40 +0200 Subject: [PATCH 07/57] Use HV UPDI constants rather than arbitrary numbers --- src/jtag3.c | 7 ++++--- src/libavrdude.h | 4 ++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/jtag3.c b/src/jtag3.c index 5e971a28..8eed8c29 100644 --- a/src/jtag3.c +++ b/src/jtag3.c @@ -1252,8 +1252,10 @@ static int jtag3_initialize(PROGRAMMER * pgm, AVRPART * p) } } - // Generate 12V UPDI pulse if user asks for it and hardware supports it - if(p->flags & AVRPART_HAS_UPDI && PDATA(pgm)->use_hvupdi == true && p->hvupdi_variant == 0) { + // Generate 12V UPDI pulse if user asks for it and hardware supports it + if (p->flags & AVRPART_HAS_UPDI && + PDATA(pgm)->use_hvupdi == true && + p->hvupdi_variant == HV_UPDI_VARIANT_0) { parm[0] = PARM3_UPDI_HV_SIMPLE_PULSE; if (jtag3_setparm(pgm, SCOPE_AVR, 3, PARM3_OPT_12V_UPDI_ENABLE, parm, 1) < 0) return -1; @@ -1458,7 +1460,6 @@ static int jtag3_parseextparms(PROGRAMMER * pgm, LISTID extparms) LNODEID ln; const char *extended_param; int rv = 0; - avrdude_message(MSG_INFO, "id: %s, desc: %s, type: %s\n", ldata(lfirst(pgm->id)), pgm->desc, pgm->type); for (ln = lfirst(extparms); ln; ln = lnext(ln)) { extended_param = ldata(ln); diff --git a/src/libavrdude.h b/src/libavrdude.h index 2b87ddf1..c3e89a7e 100644 --- a/src/libavrdude.h +++ b/src/libavrdude.h @@ -188,6 +188,10 @@ typedef struct opcode { #define AVRPART_IS_AT90S1200 0x1000 /* part is an AT90S1200 (needs special treatment) */ #define AVRPART_HAS_UPDI 0x2000 /* part has UPDI i/f (AVR8X) */ +#define HV_UPDI_VARIANT_0 0 /* Shared UPDI/GPIO/RESET pin, HV on UPDI pin (tinyAVR0/1/2)*/ +#define HV_UPDI_VARIANT_1 1 /* Dedicated UPDI pin, no HV (megaAVR0/AVR-Dx) */ +#define HV_UPDI_VARIANT_2 2 /* Shared UPDI pin, HV on _RESET (AVR-Ex) */ + #define AVR_DESCLEN 64 #define AVR_IDLEN 32 #define AVR_FAMILYIDLEN 7 From 39008ac2c1008ca377cd605a754796ccc3cb3223 Mon Sep 17 00:00:00 2001 From: "Ruud, Jan Egil" Date: Tue, 28 Jun 2022 11:55:33 +0200 Subject: [PATCH 08/57] Add UPDI HV type to device description. --- src/jtag3.c | 1 + src/jtag3_private.h | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/jtag3.c b/src/jtag3.c index 8eed8c29..a371a6a9 100644 --- a/src/jtag3.c +++ b/src/jtag3.c @@ -1198,6 +1198,7 @@ static int jtag3_initialize(PROGRAMMER * pgm, AVRPART * p) u16_to_b2(xd.nvm_base_addr, p->nvm_base); u16_to_b2(xd.ocd_base_addr, p->ocd_base); + xd.hvupdi_variant = p->hvupdi_variant; for (ln = lfirst(p->mem); ln; ln = lnext(ln)) { diff --git a/src/jtag3_private.h b/src/jtag3_private.h index 3eeb61b3..677d2289 100644 --- a/src/jtag3_private.h +++ b/src/jtag3_private.h @@ -400,5 +400,7 @@ struct updi_device_desc { unsigned char flash_page_size_msb; // Extends flash_page_size, used in 24-bit mode unsigned char address_mode; // 0x00 = 16-bit mode, 0x01 = 24-bit mode + + unsigned char hvupdi_variant; // Indicates the target UPDI HV implementation }; #endif /* JTAG3_PRIVATE_EXPORTED */ From 65763b5700c0f7dc627fece050f8c7369e47aadf Mon Sep 17 00:00:00 2001 From: "Ruud, Jan Egil" Date: Tue, 28 Jun 2022 12:21:45 +0200 Subject: [PATCH 09/57] Correct hvupdi_variant for AVR DD devices. --- src/avrdude.conf.in | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/avrdude.conf.in b/src/avrdude.conf.in index 2fc59ecd..2e66c360 100644 --- a/src/avrdude.conf.in +++ b/src/avrdude.conf.in @@ -18932,6 +18932,7 @@ part parent ".avrdx" id = "avr16dd14"; desc = "AVR16DD14"; signature = 0x1E 0x94 0x34; + hvupdi_variant = 2; memory "flash" size = 0x4000; @@ -18956,6 +18957,7 @@ part parent ".avrdx" id = "avr16dd20"; desc = "AVR16DD20"; signature = 0x1E 0x94 0x33; + hvupdi_variant = 2; memory "flash" size = 0x4000; @@ -18980,6 +18982,7 @@ part parent ".avrdx" id = "avr16dd28"; desc = "AVR16DD28"; signature = 0x1E 0x94 0x32; + hvupdi_variant = 2; memory "flash" size = 0x4000; @@ -19004,6 +19007,7 @@ part parent ".avrdx" id = "avr16dd32"; desc = "AVR16DD32"; signature = 0x1E 0x94 0x31; + hvupdi_variant = 2; memory "flash" size = 0x4000; @@ -19028,6 +19032,7 @@ part parent ".avrdx" id = "avr32dd14"; desc = "AVR32DD14"; signature = 0x1E 0x95 0x3B; + hvupdi_variant = 2; memory "flash" size = 0x8000; @@ -19052,6 +19057,7 @@ part parent ".avrdx" id = "avr32dd20"; desc = "AVR32DD20"; signature = 0x1E 0x95 0x3A; + hvupdi_variant = 2; memory "flash" size = 0x8000; @@ -19076,6 +19082,7 @@ part parent ".avrdx" id = "avr32dd28"; desc = "AVR32DD28"; signature = 0x1E 0x95 0x39; + hvupdi_variant = 2; memory "flash" size = 0x8000; @@ -19100,6 +19107,7 @@ part parent ".avrdx" id = "avr32dd32"; desc = "AVR32DD32"; signature = 0x1E 0x95 0x38; + hvupdi_variant = 2; memory "flash" size = 0x8000; @@ -19124,6 +19132,7 @@ part parent ".avrdx" id = "avr64dd14"; desc = "AVR64DD14"; signature = 0x1E 0x96 0x1D; + hvupdi_variant = 2; memory "flash" size = 0x10000; @@ -19148,6 +19157,7 @@ part parent ".avrdx" id = "avr64dd20"; desc = "AVR64DD20"; signature = 0x1E 0x96 0x1C; + hvupdi_variant = 2; memory "flash" size = 0x10000; @@ -19172,6 +19182,7 @@ part parent ".avrdx" id = "avr64dd28"; desc = "AVR64DD28"; signature = 0x1E 0x96 0x1B; + hvupdi_variant = 2; memory "flash" size = 0x10000; @@ -19196,6 +19207,7 @@ part parent ".avrdx" id = "avr64dd32"; desc = "AVR64DD32"; signature = 0x1E 0x96 0x1A; + hvupdi_variant = 2; memory "flash" size = 0x10000; From 30c1b31b8d8c6572e608f379f7e6e00f6e45bf17 Mon Sep 17 00:00:00 2001 From: MCUdude Date: Tue, 28 Jun 2022 13:59:54 +0200 Subject: [PATCH 10/57] Send 12V pulse to HV_UPDI_VARIANT_2 targets as well --- src/jtag3.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/jtag3.c b/src/jtag3.c index a371a6a9..f1cd2fc9 100644 --- a/src/jtag3.c +++ b/src/jtag3.c @@ -1256,7 +1256,8 @@ static int jtag3_initialize(PROGRAMMER * pgm, AVRPART * p) // Generate 12V UPDI pulse if user asks for it and hardware supports it if (p->flags & AVRPART_HAS_UPDI && PDATA(pgm)->use_hvupdi == true && - p->hvupdi_variant == HV_UPDI_VARIANT_0) { + (p->hvupdi_variant == HV_UPDI_VARIANT_0 || + p->hvupdi_variant == HV_UPDI_VARIANT_2)) { parm[0] = PARM3_UPDI_HV_SIMPLE_PULSE; if (jtag3_setparm(pgm, SCOPE_AVR, 3, PARM3_OPT_12V_UPDI_ENABLE, parm, 1) < 0) return -1; From 6473a6d71ab53e732babb90ed010d216d15b90c9 Mon Sep 17 00:00:00 2001 From: MCUdude Date: Wed, 29 Jun 2022 19:55:23 +0200 Subject: [PATCH 11/57] Add avrdude_message to verbose mode --- src/jtag3.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/jtag3.c b/src/jtag3.c index f1cd2fc9..5a333991 100644 --- a/src/jtag3.c +++ b/src/jtag3.c @@ -1258,10 +1258,13 @@ static int jtag3_initialize(PROGRAMMER * pgm, AVRPART * p) PDATA(pgm)->use_hvupdi == true && (p->hvupdi_variant == HV_UPDI_VARIANT_0 || p->hvupdi_variant == HV_UPDI_VARIANT_2)) { + avrdude_message(MSG_NOTICE, "%s: Sending HV pulse to %s pin\n", + progname, p->hvupdi_variant == HV_UPDI_VARIANT_0 ? "UPDI" : "RESET"); parm[0] = PARM3_UPDI_HV_SIMPLE_PULSE; if (jtag3_setparm(pgm, SCOPE_AVR, 3, PARM3_OPT_12V_UPDI_ENABLE, parm, 1) < 0) return -1; } + u16_to_b2(xd.default_min_div1_voltage, DEFAULT_MINIMUM_CHARACTERISED_DIV1_VOLTAGE_MV); u16_to_b2(xd.default_min_div2_voltage, DEFAULT_MINIMUM_CHARACTERISED_DIV2_VOLTAGE_MV); u16_to_b2(xd.default_min_div4_voltage, DEFAULT_MINIMUM_CHARACTERISED_DIV4_VOLTAGE_MV); From 9e5ea25b9e2d57c67decdbd524be1d4706ed124e Mon Sep 17 00:00:00 2001 From: "Ruud, Jan Egil" Date: Thu, 30 Jun 2022 16:15:24 +0200 Subject: [PATCH 12/57] Add HVUPDI_SUPPORT list for programmers. --- src/avrdude.conf.in | 11 +++++++++++ src/config_gram.y | 30 ++++++++++++++++++++++++++++++ src/jtag3.c | 18 ++++++++++++------ src/lexer.l | 1 + src/libavrdude.h | 1 + 5 files changed, 55 insertions(+), 6 deletions(-) diff --git a/src/avrdude.conf.in b/src/avrdude.conf.in index 2e66c360..9d4f8dbd 100644 --- a/src/avrdude.conf.in +++ b/src/avrdude.conf.in @@ -40,6 +40,7 @@ # usbvendor = ; # USB Vendor Name # usbproduct = ; # USB Product Name # usbsn = ; # USB Serial Number +# hvupdi_support = , , ...; # UPDI HV Variants Support # # To invert a bit, use = ~ , the spaces are important. # For a pin list all pins must be inverted. @@ -630,6 +631,7 @@ programmer desc = "SerialUPDI"; type = "serialupdi"; connection_type = serial; + hvupdi_support = 1; ; programmer @@ -1177,6 +1179,7 @@ programmer type = "jtagice3_updi"; connection_type = usb; usbpid = 0x2110, 0x2140; + hvupdi_support = 1; ; programmer @@ -1209,6 +1212,7 @@ programmer type = "jtagice3_updi"; connection_type = usb; usbpid = 0x2111; + hvupdi_support = 1; ; programmer @@ -1233,6 +1237,7 @@ programmer type = "jtagice3_updi"; connection_type = usb; usbpid = 0x2145; + hvupdi_support = 1; ; programmer @@ -1257,6 +1262,7 @@ programmer type = "jtagice3_updi"; connection_type = usb; usbpid = 0x2141; + hvupdi_support = 1; ; programmer @@ -1297,6 +1303,7 @@ programmer type = "jtagice3_updi"; connection_type = usb; usbpid = 0x2144; + hvupdi_support = 0, 1; ; programmer @@ -1321,6 +1328,7 @@ programmer type = "jtagice3_updi"; connection_type = usb; usbpid = 0x2177, 0x2178, 0x2179; + hvupdi_support = 0, 1, 2; ; programmer @@ -1345,6 +1353,7 @@ programmer type = "jtagice3_updi"; connection_type = usb; usbpid = 0x217F, 0x2180, 0x2181; + hvupdi_support = 1; ; programmer @@ -1369,6 +1378,7 @@ programmer type = "jtagice3_updi"; connection_type = usb; usbpid = 0x2175; + hvupdi_support = 1; ; programmer @@ -1737,6 +1747,7 @@ programmer type = "jtagmkii_pdi"; connection_type = serial; baudrate = 115200; + hvupdi_support = 1; ; # diff --git a/src/config_gram.y b/src/config_gram.y index 126b9b54..5db2a475 100644 --- a/src/config_gram.y +++ b/src/config_gram.y @@ -81,6 +81,7 @@ static int pin_name; %token K_DEFAULT_SERIAL %token K_DESC %token K_FAMILY_ID +%token K_HVUPDI_SUPPORT %token K_HVUPDI_VARIANT %token K_DEVICECODE %token K_STK500_DEVCODE @@ -547,6 +548,7 @@ prog_parm_usb: free_token($3); } } + K_HVUPDI_SUPPORT TKN_EQUAL hvupdi_support_list ; usb_pid_list: @@ -577,6 +579,34 @@ usb_pid_list: } ; +hvupdi_support_list: + TKN_NUMBER { + { + /* overwrite pids, so clear the existing entries */ + ldestroy_cb(current_prog->hvupdi_support, free); + current_prog->hvupdi_support = lcreat(NULL, 0); + } + { + int *ip = malloc(sizeof(int)); + if (ip) { + *ip = $1->value.number; + ladd(current_prog->hvupdi_support, ip); + } + free_token($1); + } + } | + hvupdi_support_list TKN_COMMA TKN_NUMBER { + { + int *ip = malloc(sizeof(int)); + if (ip) { + *ip = $3->value.number; + ladd(current_prog->hvupdi_support, ip); + } + free_token($3); + } + } +; + pin_number_non_empty: TKN_NUMBER { if(0 != assign_pin(pin_name, $1, 0)) YYABORT; } | diff --git a/src/jtag3.c b/src/jtag3.c index 5a333991..efb9b702 100644 --- a/src/jtag3.c +++ b/src/jtag3.c @@ -1253,14 +1253,20 @@ static int jtag3_initialize(PROGRAMMER * pgm, AVRPART * p) } } - // Generate 12V UPDI pulse if user asks for it and hardware supports it + // Generate UPDI high-voltage pulse if user asks for it and hardware supports it + LNODEID hvupdi_support; if (p->flags & AVRPART_HAS_UPDI && PDATA(pgm)->use_hvupdi == true && - (p->hvupdi_variant == HV_UPDI_VARIANT_0 || - p->hvupdi_variant == HV_UPDI_VARIANT_2)) { - avrdude_message(MSG_NOTICE, "%s: Sending HV pulse to %s pin\n", - progname, p->hvupdi_variant == HV_UPDI_VARIANT_0 ? "UPDI" : "RESET"); - parm[0] = PARM3_UPDI_HV_SIMPLE_PULSE; + p->hvupdi_variant != HV_UPDI_VARIANT_1) { + for (hvupdi_support = lfirst(pgm->hvupdi_support); hvupdi_support != NULL; hvupdi_support = lnext(hvupdi_support)) { + unsigned int sup = (unsigned int)(*(int *)(ldata(hvupdi_support))); + if(sup == p->hvupdi_variant) { + avrdude_message(MSG_NOTICE, "%s: Sending HV pulse to targets %s pin\n", + progname, p->hvupdi_variant == HV_UPDI_VARIANT_0 ? "UPDI" : "RESET"); + parm[0] = PARM3_UPDI_HV_SIMPLE_PULSE; + break; + } + } if (jtag3_setparm(pgm, SCOPE_AVR, 3, PARM3_OPT_12V_UPDI_ENABLE, parm, 1) < 0) return -1; } diff --git a/src/lexer.l b/src/lexer.l index dd5c081a..1693886c 100644 --- a/src/lexer.l +++ b/src/lexer.l @@ -159,6 +159,7 @@ hventerstabdelay { yylval=NULL; return K_HVENTERSTABDELAY; } hvleavestabdelay { yylval=NULL; return K_HVLEAVESTABDELAY; } hvsp_controlstack { yylval=NULL; return K_HVSP_CONTROLSTACK; } hvspcmdexedelay { yylval=NULL; return K_HVSPCMDEXEDELAY; } +hvupdi_support { yylval=NULL; return K_HVUPDI_SUPPORT; } hvupdi_variant { yylval=NULL; return K_HVUPDI_VARIANT; } id { yylval=NULL; return K_ID; } idr { yylval=NULL; return K_IDR; } diff --git a/src/libavrdude.h b/src/libavrdude.h index c3e89a7e..4a7a66b0 100644 --- a/src/libavrdude.h +++ b/src/libavrdude.h @@ -719,6 +719,7 @@ typedef struct programmer_t { int lineno; /* config file line number */ void *cookie; /* for private use by the programmer */ char flag; /* for private use of the programmer */ + LISTID hvupdi_support; /* List of UPDI HV variants the tool supports. See HV_UPDI_VARIANT_ */ } PROGRAMMER; #ifdef __cplusplus From 91310e6f505c1e8eba9c739ee9b0d0a93c790b03 Mon Sep 17 00:00:00 2001 From: Jan Egil Ruud Date: Thu, 7 Jul 2022 12:23:05 +0200 Subject: [PATCH 13/57] Move hvupdi_support list to a new prog_parm_updi group, and initialize the list. --- src/avrdude.conf.in | 2 +- src/config_gram.y | 10 +++++++--- src/jtag3.c | 9 +++++++++ src/libavrdude.h | 2 +- src/pgm.c | 1 + 5 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/avrdude.conf.in b/src/avrdude.conf.in index 9d4f8dbd..6cb314da 100644 --- a/src/avrdude.conf.in +++ b/src/avrdude.conf.in @@ -40,7 +40,7 @@ # usbvendor = ; # USB Vendor Name # usbproduct = ; # USB Product Name # usbsn = ; # USB Serial Number -# hvupdi_support = , , ...; # UPDI HV Variants Support +# hvupdi_support = [, , ... ] ; # UPDI HV Variants Support # # To invert a bit, use = ~ , the spaces are important. # For a pin list all pins must be inverted. diff --git a/src/config_gram.y b/src/config_gram.y index 5db2a475..b0a8e36e 100644 --- a/src/config_gram.y +++ b/src/config_gram.y @@ -477,7 +477,8 @@ prog_parm : current_prog->baudrate = $3->value.number; free_token($3); } - } + } | + prog_parm_updi ; prog_parm_type: @@ -548,7 +549,6 @@ prog_parm_usb: free_token($3); } } - K_HVUPDI_SUPPORT TKN_EQUAL hvupdi_support_list ; usb_pid_list: @@ -579,10 +579,14 @@ usb_pid_list: } ; +prog_parm_updi: + K_HVUPDI_SUPPORT TKN_EQUAL hvupdi_support_list +; + hvupdi_support_list: TKN_NUMBER { { - /* overwrite pids, so clear the existing entries */ + /* overwrite list entries, so clear the existing entries */ ldestroy_cb(current_prog->hvupdi_support, free); current_prog->hvupdi_support = lcreat(NULL, 0); } diff --git a/src/jtag3.c b/src/jtag3.c index efb9b702..1c003a82 100644 --- a/src/jtag3.c +++ b/src/jtag3.c @@ -1649,6 +1649,15 @@ static int jtag3_open_updi(PROGRAMMER * pgm, char * port) { avrdude_message(MSG_NOTICE2, "%s: jtag3_open_updi()\n", progname); + LNODEID ln; + unsigned int hv_sup; + avrdude_message(MSG_NOTICE2, "%s: HV UPDI support:", progname); + for (ln = lfirst(pgm->hvupdi_support); ln; ln = lnext(ln)) { + hv_sup = (unsigned int)(*(int *)ldata(ln)); + avrdude_message(MSG_NOTICE2, " %d", hv_sup); + } + avrdude_message(MSG_NOTICE2, "\n", progname); + if (jtag3_open_common(pgm, port) < 0) return -1; diff --git a/src/libavrdude.h b/src/libavrdude.h index 4a7a66b0..1259977f 100644 --- a/src/libavrdude.h +++ b/src/libavrdude.h @@ -206,7 +206,7 @@ typedef struct avrpart { char desc[AVR_DESCLEN]; /* long part name */ char id[AVR_IDLEN]; /* short part name */ char family_id[AVR_FAMILYIDLEN+1]; /* family id in the SIB (avr8x) */ - int hvupdi_variant; /* 12V pulse on UPDI pin, no pin or RESET pin */ + int hvupdi_variant; /* HV pulse on UPDI pin, no pin or RESET pin */ int stk500_devcode; /* stk500 device code */ int avr910_devcode; /* avr910 device code */ int chip_erase_delay; /* microseconds */ diff --git a/src/pgm.c b/src/pgm.c index 851ac5a8..4580cbbd 100644 --- a/src/pgm.c +++ b/src/pgm.c @@ -83,6 +83,7 @@ PROGRAMMER * pgm_new(void) pgm->lineno = 0; pgm->baudrate = 0; pgm->initpgm = NULL; + pgm->hvupdi_support = lcreat(NULL, 0); for (i=0; ipinno[i] = 0; From 173b4f9d0ac90924764d8c3174ad3e3ab934a0cd Mon Sep 17 00:00:00 2001 From: Jan Egil Ruud Date: Mon, 11 Jul 2022 14:07:45 +0200 Subject: [PATCH 14/57] Clean up and simplify hvupdi handling, and set default hvupdi_variant to -1. --- src/avrpart.c | 1 + src/jtag3.c | 13 ++++--------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/avrpart.c b/src/avrpart.c index dc6def44..5a192e2d 100644 --- a/src/avrpart.c +++ b/src/avrpart.c @@ -573,6 +573,7 @@ AVRPART * avr_new_part(void) memset(p->signature, 0xFF, 3); p->ctl_stack_type = CTL_STACK_NONE; p->ocdrev = -1; + p->hvupdi_variant = -1; p->mem = lcreat(NULL, 0); p->mem_alias = lcreat(NULL, 0); diff --git a/src/jtag3.c b/src/jtag3.c index 1c003a82..ae5d1912 100644 --- a/src/jtag3.c +++ b/src/jtag3.c @@ -1259,8 +1259,7 @@ static int jtag3_initialize(PROGRAMMER * pgm, AVRPART * p) PDATA(pgm)->use_hvupdi == true && p->hvupdi_variant != HV_UPDI_VARIANT_1) { for (hvupdi_support = lfirst(pgm->hvupdi_support); hvupdi_support != NULL; hvupdi_support = lnext(hvupdi_support)) { - unsigned int sup = (unsigned int)(*(int *)(ldata(hvupdi_support))); - if(sup == p->hvupdi_variant) { + if(*(int *) ldata(hvupdi_support) == p->hvupdi_variant) { avrdude_message(MSG_NOTICE, "%s: Sending HV pulse to targets %s pin\n", progname, p->hvupdi_variant == HV_UPDI_VARIANT_0 ? "UPDI" : "RESET"); parm[0] = PARM3_UPDI_HV_SIMPLE_PULSE; @@ -1496,8 +1495,7 @@ static int jtag3_parseextparms(PROGRAMMER * pgm, LISTID extparms) continue; } - else if ((matches(extended_param, "hvupdi") || matches(extended_param, "hvupdi=1")) && - (matches(ldata(lfirst(pgm->id)), "pickit4_updi") || matches(ldata(lfirst(pgm->id)), "powerdebugger_updi"))) { + else if (matches(extended_param, "hvupdi")) { PDATA(pgm)->use_hvupdi = true; continue; } @@ -1650,12 +1648,9 @@ static int jtag3_open_updi(PROGRAMMER * pgm, char * port) avrdude_message(MSG_NOTICE2, "%s: jtag3_open_updi()\n", progname); LNODEID ln; - unsigned int hv_sup; avrdude_message(MSG_NOTICE2, "%s: HV UPDI support:", progname); - for (ln = lfirst(pgm->hvupdi_support); ln; ln = lnext(ln)) { - hv_sup = (unsigned int)(*(int *)ldata(ln)); - avrdude_message(MSG_NOTICE2, " %d", hv_sup); - } + for (ln = lfirst(pgm->hvupdi_support); ln; ln = lnext(ln)) + avrdude_message(MSG_NOTICE2, " %d", *(int *) ldata(ln)); avrdude_message(MSG_NOTICE2, "\n", progname); if (jtag3_open_common(pgm, port) < 0) From 2478c1874591693ccff4c689e39238687bc2bc93 Mon Sep 17 00:00:00 2001 From: Jan Egil Ruud Date: Mon, 11 Jul 2022 15:26:41 +0200 Subject: [PATCH 15/57] Do not let the hvupdi extended option take any configuration values. The hvupdi type is implied by the part configuration. --- src/jtag3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jtag3.c b/src/jtag3.c index ae5d1912..f07e0319 100644 --- a/src/jtag3.c +++ b/src/jtag3.c @@ -1495,7 +1495,7 @@ static int jtag3_parseextparms(PROGRAMMER * pgm, LISTID extparms) continue; } - else if (matches(extended_param, "hvupdi")) { + else if (strcmp(extended_param, "hvupdi") == 0) { PDATA(pgm)->use_hvupdi = true; continue; } From 69ee5da6130471d62bf170735b7f82cc93128107 Mon Sep 17 00:00:00 2001 From: Jan Egil Ruud Date: Tue, 12 Jul 2022 12:01:17 +0200 Subject: [PATCH 16/57] Improve error handling for devices that does not support HVUPDI. --- src/jtag3.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/jtag3.c b/src/jtag3.c index f07e0319..becfd8a1 100644 --- a/src/jtag3.c +++ b/src/jtag3.c @@ -1254,17 +1254,21 @@ static int jtag3_initialize(PROGRAMMER * pgm, AVRPART * p) } // Generate UPDI high-voltage pulse if user asks for it and hardware supports it - LNODEID hvupdi_support; + LNODEID support; if (p->flags & AVRPART_HAS_UPDI && PDATA(pgm)->use_hvupdi == true && p->hvupdi_variant != HV_UPDI_VARIANT_1) { - for (hvupdi_support = lfirst(pgm->hvupdi_support); hvupdi_support != NULL; hvupdi_support = lnext(hvupdi_support)) { - if(*(int *) ldata(hvupdi_support) == p->hvupdi_variant) { + parm[0] = PARM3_UPDI_HV_NONE; + for (support = lfirst(pgm->hvupdi_support); support != NULL; support = lnext(support)) { + if(*(int *) ldata(support) == p->hvupdi_variant) { avrdude_message(MSG_NOTICE, "%s: Sending HV pulse to targets %s pin\n", progname, p->hvupdi_variant == HV_UPDI_VARIANT_0 ? "UPDI" : "RESET"); parm[0] = PARM3_UPDI_HV_SIMPLE_PULSE; break; } + if (parm[0] == PARM3_UPDI_HV_NONE) + avrdude_message(MSG_INFO, "%s: %s does not support sending HV pulse to target %s\n", + progname, pgm->desc, p->desc); } if (jtag3_setparm(pgm, SCOPE_AVR, 3, PARM3_OPT_12V_UPDI_ENABLE, parm, 1) < 0) return -1; @@ -1495,7 +1499,8 @@ static int jtag3_parseextparms(PROGRAMMER * pgm, LISTID extparms) continue; } - else if (strcmp(extended_param, "hvupdi") == 0) { + else if ((strcmp(extended_param, "hvupdi") == 0) && + (lsize(pgm->hvupdi_support) > 1)) { PDATA(pgm)->use_hvupdi = true; continue; } From d9450058c8667d9d3fe5ce467210305d93ad1159 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 12 Jul 2022 11:12:20 +0100 Subject: [PATCH 17/57] Cache strlen(argv[i]) in term.c cmd_write() and prevent negative array index --- src/term.c | 84 +++++++++++++++++++++++++++++------------------------- 1 file changed, 45 insertions(+), 39 deletions(-) diff --git a/src/term.c b/src/term.c index dc771273..1ddaf885 100644 --- a/src/term.c +++ b/src/term.c @@ -426,6 +426,9 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, // Handle the next argument if (i < argc - start_offset + 3) { + char *argi = argv[i]; + size_t arglen = strlen(argi); + // Free string pointer if already allocated if(data.str_ptr) { free(data.str_ptr); @@ -433,52 +436,55 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, } // Get suffix if present - char suffix = argv[i][strlen(argv[i]) - 1]; - char lsuffix = argv[i][strlen(argv[i]) - 2]; - if ((suffix == 'L' && lsuffix == 'L') || (suffix == 'l' && lsuffix == 'l')) { - argv[i][strlen(argv[i]) - 2] = '\0'; - data.size = 8; - } else if (suffix == 'L' || suffix == 'l') { - argv[i][strlen(argv[i]) - 1] = '\0'; - data.size = 4; - } else if ((suffix == 'F' || suffix == 'f') && - strncmp(argv[i], "0x", 2) != 0 && strncmp(argv[i], "-0x", 3) != 0) { - argv[i][strlen(argv[i]) - 1] = '\0'; - data.size = 4; - } else if ((suffix == 'H' && lsuffix == 'H') || (suffix == 'h' && lsuffix == 'h')) { - argv[i][strlen(argv[i]) - 2] = '\0'; - data.size = 1; - } else if (suffix == 'H' || suffix == 'h' || suffix == 'S' || suffix == 's') { - argv[i][strlen(argv[i]) - 1] = '\0'; - data.size = 2; - } else if (suffix == '\'') { - data.size = 1; + char suffix = 0, lsuffix = 0; + if(arglen > 1) { + suffix = argi[arglen - 1]; + lsuffix = argi[arglen - 2]; + if ((suffix == 'L' && lsuffix == 'L') || (suffix == 'l' && lsuffix == 'l')) { + argi[arglen -= 2] = '\0'; + data.size = 8; + } else if (suffix == 'L' || suffix == 'l') { + argi[--arglen] = '\0'; + data.size = 4; + } else if ((suffix == 'F' || suffix == 'f') && + strncmp(argi, "0x", 2) != 0 && strncmp(argi, "-0x", 3) != 0) { + argi[--arglen] = '\0'; + data.size = 4; + } else if ((suffix == 'H' && lsuffix == 'H') || (suffix == 'h' && lsuffix == 'h')) { + argi[arglen -= 2] = '\0'; + data.size = 1; + } else if (suffix == 'H' || suffix == 'h' || suffix == 'S' || suffix == 's') { + argi[--arglen] = '\0'; + data.size = 2; + } else if (suffix == '\'') { + data.size = 1; + } } // Try integers - data.ll = strtoll(argv[i], &end_ptr, 0); - if (*end_ptr || (end_ptr == argv[i])) { + data.ll = strtoll(argi, &end_ptr, 0); + if (*end_ptr || (end_ptr == argi)) { // Try float - data.f = strtof(argv[i], &end_ptr); + data.f = strtof(argi, &end_ptr); data.is_float = true; - if (*end_ptr || (end_ptr == argv[i])) { + if (*end_ptr || (end_ptr == argi)) { data.is_float = false; // Try single character - if (argv[i][0] == '\'' && argv[i][2] == '\'') { - data.ll = argv[i][1]; + if (argi[0] == '\'' && argi[2] == '\'') { + data.ll = argi[1]; } else { // Try string that starts and ends with quotes - if (argv[i][0] == '\"' && argv[i][strlen(argv[i]) - 1] == '\"') { - data.str_ptr = calloc(strlen(argv[i]), sizeof(char)); + if (argi[0] == '\"' && argi[arglen - 1] == '\"') { + data.str_ptr = calloc(arglen, sizeof(char)); if (data.str_ptr == NULL) { avrdude_message(MSG_INFO, "%s (write str): out of memory\n", progname); return -1; } // Strip start and end quotes - strncpy(data.str_ptr, argv[i] + 1, strlen(argv[i]) - 2); + strncpy(data.str_ptr, argi + 1, arglen - 2); } else { avrdude_message(MSG_INFO, "\n%s (write): can't parse data '%s'\n", - progname, argv[i]); + progname, argi); free(buf); if(data.str_ptr != NULL) free(data.str_ptr); @@ -489,18 +495,18 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, } // Print warning if data size might be ambiguous - bool is_hex = (strncmp(argv[i], "0x", 2) == 0); - bool is_neg_hex = (strncmp(argv[i], "-0x", 3) == 0); - bool leading_zero = (strncmp(argv[i], "0x0", 3) == 0); - int8_t hex_digits = (strlen(argv[i]) - 2); - if(!data.size // No pre-defined size - && (is_neg_hex // Hex with - sign in front - || (is_hex && leading_zero && (hex_digits & (hex_digits - 1))) // Hex with 3, 5, 6 or 7 digits - || (!is_hex && !data.is_float && llabs(data.ll) > 0xFF && strlen(argv[i]) > 2))) // Base10 int greater than 255 + bool is_hex = (strncmp(argi, "0x", 2) == 0); + bool is_neg_hex = (strncmp(argi, "-0x", 3) == 0); + bool leading_zero = (strncmp(argi, "0x0", 3) == 0); + int8_t hex_digits = (arglen - 2); + if(!data.size // No pre-defined size + && (is_neg_hex // Hex with - sign in front + || (is_hex && leading_zero && (hex_digits & (hex_digits - 1))) // Hex with 3, 5, 6 or 7 digits + || (!is_hex && !data.is_float && llabs(data.ll) > 0xFF && arglen > 2))) // Base10 int greater than 255 { avrdude_message(MSG_INFO, "Warning: no size suffix specified for \"%s\". " "Writing %d byte(s)\n", - argv[i], + argi, llabs(data.ll) > UINT32_MAX ? 8 : llabs(data.ll) > UINT16_MAX || data.is_float ? 4 : \ llabs(data.ll) > UINT8_MAX ? 2 : 1); From 360d7c502b69920124d6eb51c39ec08951274363 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 12 Jul 2022 11:13:46 +0100 Subject: [PATCH 18/57] Make suffix fully case insensitive (allow Hh, Ll, ...) in terminal write --- src/term.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/term.c b/src/term.c index 1ddaf885..534cf67b 100644 --- a/src/term.c +++ b/src/term.c @@ -438,22 +438,22 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, // Get suffix if present char suffix = 0, lsuffix = 0; if(arglen > 1) { - suffix = argi[arglen - 1]; - lsuffix = argi[arglen - 2]; - if ((suffix == 'L' && lsuffix == 'L') || (suffix == 'l' && lsuffix == 'l')) { + suffix = toupper(argi[arglen - 1]); + lsuffix = toupper(argi[arglen - 2]); + if (suffix == 'L' && lsuffix == 'L') { argi[arglen -= 2] = '\0'; data.size = 8; } else if (suffix == 'L' || suffix == 'l') { argi[--arglen] = '\0'; data.size = 4; - } else if ((suffix == 'F' || suffix == 'f') && + } else if ((suffix == 'F') && strncmp(argi, "0x", 2) != 0 && strncmp(argi, "-0x", 3) != 0) { argi[--arglen] = '\0'; data.size = 4; - } else if ((suffix == 'H' && lsuffix == 'H') || (suffix == 'h' && lsuffix == 'h')) { + } else if (suffix == 'H' && lsuffix == 'H') { argi[arglen -= 2] = '\0'; data.size = 1; - } else if (suffix == 'H' || suffix == 'h' || suffix == 'S' || suffix == 's') { + } else if (suffix == 'H' || suffix == 'S') { argi[--arglen] = '\0'; data.size = 2; } else if (suffix == '\'') { From 39a00bc71ed2527ad1953f1465df22f4961c6d5a Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 12 Jul 2022 11:14:41 +0100 Subject: [PATCH 19/57] Ensure +0x...f does not strip suffix f in terminal write --- src/term.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/term.c b/src/term.c index 534cf67b..ce6c6157 100644 --- a/src/term.c +++ b/src/term.c @@ -447,7 +447,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, argi[--arglen] = '\0'; data.size = 4; } else if ((suffix == 'F') && - strncmp(argi, "0x", 2) != 0 && strncmp(argi, "-0x", 3) != 0) { + strncmp(argi, "0x", 2) && strncmp(argi, "-0x", 3) && strncmp(argi, "+0x", 3)) { argi[--arglen] = '\0'; data.size = 4; } else if (suffix == 'H' && lsuffix == 'H') { From d3ad078577b07833e0a40be32f84e7850ff4898b Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 12 Jul 2022 11:15:30 +0100 Subject: [PATCH 20/57] Ensure terminal write fill mode ... always fills with last data item --- src/term.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/term.c b/src/term.c index ce6c6157..881207fc 100644 --- a/src/term.c +++ b/src/term.c @@ -421,14 +421,14 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, }; for (i = start_offset; i < len + start_offset; i++) { - data.is_float = false; - data.size = 0; - // Handle the next argument if (i < argc - start_offset + 3) { char *argi = argv[i]; size_t arglen = strlen(argi); + data.is_float = false; + data.size = 0; + // Free string pointer if already allocated if(data.str_ptr) { free(data.str_ptr); From 177834ae7c72bc0738af41dc32cd3b0dfb14fdb7 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 12 Jul 2022 11:16:16 +0100 Subject: [PATCH 21/57] Ensure enough memory is allocated for buf in terminal write --- src/term.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/term.c b/src/term.c index 881207fc..64bee430 100644 --- a/src/term.c +++ b/src/term.c @@ -334,6 +334,16 @@ static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p, } +static size_t maxstrlen(int argc, char **argv) { + size_t max = 0; + + for(int i=0; i max) + max = strlen(argv[i]); + + return max; +} + static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, int argc, char * argv[]) { @@ -374,7 +384,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, } // Allocate a buffer guaranteed to be large enough - uint8_t * buf = calloc(mem->size + 0x10 + strlen(argv[argc - 2]), sizeof(uint8_t)); + uint8_t * buf = calloc(mem->size + 0x10 + maxstrlen(argc-3, argv+3), sizeof(uint8_t)); if (buf == NULL) { avrdude_message(MSG_INFO, "%s (write): out of memory\n", progname); return -1; From ff43e0544d40e70bc911f5a85090f1c354e6b2f9 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 12 Jul 2022 11:18:15 +0100 Subject: [PATCH 22/57] Correct a parse message in terminal write --- src/term.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/term.c b/src/term.c index 64bee430..7e635463 100644 --- a/src/term.c +++ b/src/term.c @@ -396,7 +396,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, start_offset = 4; len = strtoul(argv[3], &end_ptr, 0); if (*end_ptr || (end_ptr == argv[3])) { - avrdude_message(MSG_INFO, "%s (write ...): can't parse address \"%s\"\n", + avrdude_message(MSG_INFO, "%s (write ...): can't parse length \"%s\"\n", progname, argv[3]); free(buf); return -1; From 9afa56381e2c60158f84ccdcbe9789120815317d Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 12 Jul 2022 11:19:05 +0100 Subject: [PATCH 23/57] Remove unused component is_signed in terminal write --- src/term.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/term.c b/src/term.c index 7e635463..ac36e3bf 100644 --- a/src/term.c +++ b/src/term.c @@ -413,7 +413,6 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, int32_t bytes_grown; uint8_t size; bool is_float; - bool is_signed; char * str_ptr; // Data union union { @@ -425,7 +424,6 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, .bytes_grown = 0, .size = 0, .is_float = false, - .is_signed = false, .str_ptr = NULL, .ll = 0 }; @@ -521,9 +519,8 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, llabs(data.ll) > UINT16_MAX || data.is_float ? 4 : \ llabs(data.ll) > UINT8_MAX ? 2 : 1); } - // Flag if signed integer and adjust size + // Adjust size if signed integer if (data.ll < 0 && !data.is_float) { - data.is_signed = true; if (data.ll < INT32_MIN) data.size = 8; else if (data.ll < INT16_MIN) From 62d3eebd568c2078428a55485675a8411d97f415 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 12 Jul 2022 11:19:47 +0100 Subject: [PATCH 24/57] Fix 64-bit integer terminal write where high bit set Using strtoll() can only return numbers in the range [-2^63, 2^63-1]. This means that 0xffffFFFFffffFFFF (2^64-1) will be out of range and is written as max LL. Actually, every 64-bit number with high-bit set will wrongly be written as max LL. This commit uses strtoull() instead to fix this, and checks for unsiged out- of-range error. strtoull() also has the neat benefit that input with a minus sign is treated like C unsigned numbers, ie, -u is also a valid unsigned number if only u is one. In case the input is meant to be treated as signed, it is therefore still OK to use strtoull() in the first instance only that in this case a second check against the range of the signed domain is necessary. --- src/term.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/term.c b/src/term.c index ac36e3bf..203168de 100644 --- a/src/term.c +++ b/src/term.c @@ -26,6 +26,7 @@ #include #include #include +#include #if defined(HAVE_LIBREADLINE) # include @@ -470,8 +471,9 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, } // Try integers - data.ll = strtoll(argi, &end_ptr, 0); - if (*end_ptr || (end_ptr == argi)) { + errno = 0; + data.ll = strtoull(argi, &end_ptr, 0); + if (!(end_ptr == argi || errno)) { // Try float data.f = strtof(argi, &end_ptr); data.is_float = true; From 51355d04fb34805a2b352475f01f13e8270f0822 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 12 Jul 2022 11:32:38 +0100 Subject: [PATCH 25/57] Remodel logic of the size that integer items occupy in terminal write Integers can be hexadecimal, decimal or octal. An optional case-insensitive suffix specifies their size: HH: 8 bit, H/S: 16 bit, L: 32 bit, LL: 64 bit An optional U suffix makes a number unsigned. Ordinary 0x hex numbers are always treated as unsigned. +0x or -0x hex numbers are treated as signed unless they have a U suffix. Unsigned integers cannot be larger than 2^64-1. If n is an unsigned integer then -n is also a valid unsigned integer as in C. Signed integers must fall into the [-2^63, 2^63-1] range or a correspondingly smaller range when a suffix specifies a smaller type. Out of range signed numbers trigger a warning. Ordinary 0x hex numbers with n hex digits (counting leading zeros) use the smallest size of 1, 2, 4 and 8 bytes that can accommodate any n-digit hex number. If a suffix specifies a size explicitly the corresponding number of least significant bytes are written. Otherwise, signed and unsigned integers alike occupy the smallest of 1, 2, 4, or 8 bytes needed to accommodate them in their respective representation. --- src/term.c | 157 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 91 insertions(+), 66 deletions(-) diff --git a/src/term.c b/src/term.c index 203168de..96ed8e57 100644 --- a/src/term.c +++ b/src/term.c @@ -419,6 +419,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, union { float f; int64_t ll; + uint64_t ull; uint8_t a[8]; }; } data = { @@ -444,44 +445,99 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, data.str_ptr = NULL; } - // Get suffix if present - char suffix = 0, lsuffix = 0; - if(arglen > 1) { - suffix = toupper(argi[arglen - 1]); - lsuffix = toupper(argi[arglen - 2]); - if (suffix == 'L' && lsuffix == 'L') { - argi[arglen -= 2] = '\0'; - data.size = 8; - } else if (suffix == 'L' || suffix == 'l') { - argi[--arglen] = '\0'; - data.size = 4; - } else if ((suffix == 'F') && - strncmp(argi, "0x", 2) && strncmp(argi, "-0x", 3) && strncmp(argi, "+0x", 3)) { - argi[--arglen] = '\0'; - data.size = 4; - } else if (suffix == 'H' && lsuffix == 'H') { - argi[arglen -= 2] = '\0'; - data.size = 1; - } else if (suffix == 'H' || suffix == 'S') { - argi[--arglen] = '\0'; - data.size = 2; - } else if (suffix == '\'') { - data.size = 1; + // Try integers and assign data size + errno = 0; + data.ull = strtoull(argi, &end_ptr, 0); + if (!(end_ptr == argi || errno)) { + unsigned int nu=0, nl=0, nh=0, ns=0, nx=0; + char *p; + + // parse suffixes: ULL, LL, UL, L ... UHH, HH + for(p=end_ptr; *p; p++) + switch(toupper(*p)) { + case 'U': nu++; break; + case 'L': nl++; break; + case 'H': nh++; break; + case 'S': ns++; break; + default: nx++; + } + + if(nx==0 && nu<2 && nl<3 && nh<3 && ns<2) { // could be valid integer suffix + if(nu==0 || toupper(*end_ptr) == 'U' || toupper(p[-1]) == 'U') { // if U, then must be at start or end + bool is_hex = strncasecmp(argi, "0x", 2) == 0; // ordinary hex: "0x..." without explicit +/- sign + bool is_signed = !(nu || is_hex); // neither explicitly unsigned nor ordinary hex + bool is_outside_int64_t = 0; + bool is_out_of_range = 0; + int nhexdigs = p-argi-2; + + if(is_signed) { // Is input in range for int64_t? + errno = 0; (void) strtoll(argi, NULL, 0); + is_outside_int64_t = errno == ERANGE; + } + + if(nl==0 && ns==0 && nh==0) { // no explicit data size + // ordinary hex numbers have "implicit" size, given by number of hex digits, including leading zeros + if(is_hex) { + data.size = nhexdigs > 8? 8: nhexdigs > 4? 4: nhexdigs > 2? 2: 1; + + } else if(is_signed) { + // smallest size that fits signed representation + data.size = + is_outside_int64_t? 8: + data.ll < INT32_MIN || data.ll > INT32_MAX? 8: + data.ll < INT16_MIN || data.ll > INT16_MAX? 4: + data.ll < INT8_MIN || data.ll > INT8_MAX? 2: 1; + + } else { + // smallest size that fits unsigned representation + data.size = + data.ull > UINT32_MAX? 8: + data.ull > UINT16_MAX? 4: + data.ull > UINT8_MAX? 2: 1; + } + } else if(nl==0 && nh==2 && ns==0) { // HH + data.size = 1; + if(is_outside_int64_t || (is_signed && (data.ll < INT8_MIN || data.ll > INT8_MAX))) { + is_out_of_range = 1; + data.ll = (int8_t) data.ll; + } + } else if(nl==0 && ((nh==1 && ns==0) || (nh==0 && ns==1))) { // H or S + data.size = 2; + if(is_outside_int64_t || (is_signed && (data.ll < INT16_MIN || data.ll > INT16_MAX))) { + is_out_of_range = 1; + data.ll = (int16_t) data.ll; + } + } else if(nl==1 && nh==0 && ns==0) { // L + data.size = 4; + if(is_outside_int64_t || (is_signed && (data.ll < INT32_MIN || data.ll > INT32_MAX))) { + is_out_of_range = 1; + data.ll = (int32_t) data.ll; + } + } else if(nl==2 && nh==0 && ns==0) { // LL + data.size = 8; + } + + if(is_outside_int64_t || is_out_of_range) + avrdude_message(MSG_INFO, "%s (write): %s out of int%d_t range, " + "interpreted as %d-byte %lld%s; consider 'U' suffix\n", + progname, argi, data.size*8, data.size, data.ll, + is_out_of_range? " (unlikely what you want)": "" + ); + } } } - // Try integers - errno = 0; - data.ll = strtoull(argi, &end_ptr, 0); - if (!(end_ptr == argi || errno)) { + if(!data.size) { // Data item was not recognised as integer // Try float data.f = strtof(argi, &end_ptr); - data.is_float = true; - if (*end_ptr || (end_ptr == argi)) { - data.is_float = false; + if (end_ptr != argi && toupper(*end_ptr) == 'F' && end_ptr[1] == 0) { + data.is_float = true; + data.size = 4; + } else { // Try single character if (argi[0] == '\'' && argi[2] == '\'') { data.ll = argi[1]; + data.size = 1; } else { // Try string that starts and ends with quotes if (argi[0] == '\"' && argi[arglen - 1] == '\"') { @@ -503,35 +559,6 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, } } } - - // Print warning if data size might be ambiguous - bool is_hex = (strncmp(argi, "0x", 2) == 0); - bool is_neg_hex = (strncmp(argi, "-0x", 3) == 0); - bool leading_zero = (strncmp(argi, "0x0", 3) == 0); - int8_t hex_digits = (arglen - 2); - if(!data.size // No pre-defined size - && (is_neg_hex // Hex with - sign in front - || (is_hex && leading_zero && (hex_digits & (hex_digits - 1))) // Hex with 3, 5, 6 or 7 digits - || (!is_hex && !data.is_float && llabs(data.ll) > 0xFF && arglen > 2))) // Base10 int greater than 255 - { - avrdude_message(MSG_INFO, "Warning: no size suffix specified for \"%s\". " - "Writing %d byte(s)\n", - argi, - llabs(data.ll) > UINT32_MAX ? 8 : - llabs(data.ll) > UINT16_MAX || data.is_float ? 4 : \ - llabs(data.ll) > UINT8_MAX ? 2 : 1); - } - // Adjust size if signed integer - if (data.ll < 0 && !data.is_float) { - if (data.ll < INT32_MIN) - data.size = 8; - else if (data.ll < INT16_MIN) - data.size = 4; - else if (data.ll < INT8_MIN) - data.size = 2; - else - data.size = 1; - } } if(data.str_ptr) { for(int16_t j = 0; j < strlen(data.str_ptr); j++) @@ -912,7 +939,7 @@ static int cmd_help(PROGRAMMER * pgm, struct avrpart * p, fprintf(stdout, cmd[i].desc, cmd[i].name); fprintf(stdout, "\n"); } - fprintf(stdout, + fprintf(stdout, "\nUse the 'part' command to display valid memory types for use with the\n" "'dump' and 'write' commands.\n\n"); @@ -989,9 +1016,9 @@ static int tokenize(char * s, char *** argv) slen = strlen(s); - /* + /* * initialize allow for 20 arguments, use realloc to grow this if - * necessary + * necessary */ nargs = 20; bufsize = slen + 20; @@ -1047,7 +1074,7 @@ static int tokenize(char * s, char *** argv) } } - /* + /* * We have parsed all the args, n == argc, bufv contains an array of * pointers to each arg, and buf points to one memory block that * contains all the args, back to back, seperated by a nul @@ -1140,7 +1167,7 @@ int terminal_mode(PROGRAMMER * pgm, struct avrpart * p) rc = 0; while ((cmdbuf = terminal_get_input("avrdude> ")) != NULL) { - /* + /* * find the start of the command, skipping any white space */ q = cmdbuf; @@ -1175,5 +1202,3 @@ int terminal_mode(PROGRAMMER * pgm, struct avrpart * p) return rc; } - - From feda75b60a20c3bfdc06af3c739e26c9c3b106c5 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 12 Jul 2022 11:35:27 +0100 Subject: [PATCH 26/57] Remove unnecessary bool is_float in terminal write --- src/term.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/term.c b/src/term.c index 96ed8e57..7481f0ee 100644 --- a/src/term.c +++ b/src/term.c @@ -413,7 +413,6 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, // Data info int32_t bytes_grown; uint8_t size; - bool is_float; char * str_ptr; // Data union union { @@ -425,7 +424,6 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, } data = { .bytes_grown = 0, .size = 0, - .is_float = false, .str_ptr = NULL, .ll = 0 }; @@ -436,7 +434,6 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, char *argi = argv[i]; size_t arglen = strlen(argi); - data.is_float = false; data.size = 0; // Free string pointer if already allocated @@ -531,7 +528,6 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, // Try float data.f = strtof(argi, &end_ptr); if (end_ptr != argi && toupper(*end_ptr) == 'F' && end_ptr[1] == 0) { - data.is_float = true; data.size = 4; } else { // Try single character @@ -565,9 +561,9 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, buf[i - start_offset + data.bytes_grown++] = (uint8_t)data.str_ptr[j]; } else { buf[i - start_offset + data.bytes_grown] = data.a[0]; - if (llabs(data.ll) > 0x000000FF || data.size >= 2 || data.is_float) + if (llabs(data.ll) > 0x000000FF || data.size >= 2) buf[i - start_offset + ++data.bytes_grown] = data.a[1]; - if (llabs(data.ll) > 0x0000FFFF || data.size >= 4 || data.is_float) { + if (llabs(data.ll) > 0x0000FFFF || data.size >= 4) { buf[i - start_offset + ++data.bytes_grown] = data.a[2]; buf[i - start_offset + ++data.bytes_grown] = data.a[3]; } From 9fe6820236169bd154bb54cff867351900795fcf Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 12 Jul 2022 11:36:57 +0100 Subject: [PATCH 27/57] Add double type for terminal write in anticipation of future avr-libc extension --- src/term.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/term.c b/src/term.c index 7481f0ee..6efa380a 100644 --- a/src/term.c +++ b/src/term.c @@ -417,6 +417,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, // Data union union { float f; + double d; int64_t ll; uint64_t ull; uint8_t a[8]; @@ -524,12 +525,19 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, } } - if(!data.size) { // Data item was not recognised as integer - // Try float + if(!data.size) { // Try float data.f = strtof(argi, &end_ptr); - if (end_ptr != argi && toupper(*end_ptr) == 'F' && end_ptr[1] == 0) { + if (end_ptr != argi && toupper(*end_ptr) == 'F' && end_ptr[1] == 0) data.size = 4; - } else { + } + + if(!data.size) { // Try double + data.d = strtod(argi, &end_ptr); + if (end_ptr != argi && *end_ptr == 0) + data.size = 8; + } + + if(!data.size) { // Try single character if (argi[0] == '\'' && argi[2] == '\'') { data.ll = argi[1]; @@ -553,7 +561,6 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, return -1; } } - } } } if(data.str_ptr) { From 5c4cfa642aa32d268224c503555e3a1b196b38df Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 12 Jul 2022 11:39:02 +0100 Subject: [PATCH 28/57] Parse terminal writes of string and character constants in C-style --- src/term.c | 221 ++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 200 insertions(+), 21 deletions(-) diff --git a/src/term.c b/src/term.c index 6efa380a..cd7e3b45 100644 --- a/src/term.c +++ b/src/term.c @@ -335,6 +335,179 @@ static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p, } + +// convert the next n hex digits of s to a hex number +static unsigned int tohex(const char *s, unsigned int n) { + int ret, c; + + ret = 0; + while(n--) { + ret *= 16; + c = *s++; + ret += c >= '0' && c <= '9'? c - '0': c >= 'a' && c <= 'f'? c - 'a' + 10: c - 'A' + 10; + } + + return ret; +} + +/* + * Create a utf-8 character sequence from a single unicode character. + * Permissive for some invalid unicode sequences but not for those with + * high bit set). Returns numbers of characters written (0-6). + */ +static int wc_to_utf8str(unsigned int wc, char *str) { + if(!(wc & ~0x7fu)) { + *str = (char) wc; + return 1; + } + if(!(wc & ~0x7ffu)) { + *str++ = (char) ((wc >> 6) | 0xc0); + *str++ = (char) ((wc & 0x3f) | 0x80); + return 2; + } + if(!(wc & ~0xffffu)) { + *str++ = (char) ((wc >> 12) | 0xe0); + *str++ = (char) (((wc >> 6) & 0x3f) | 0x80); + *str++ = (char) ((wc & 0x3f) | 0x80); + return 3; + } + if(!(wc & ~0x1fffffu)) { + *str++ = (char) ((wc >> 18) | 0xf0); + *str++ = (char) (((wc >> 12) & 0x3f) | 0x80); + *str++ = (char) (((wc >> 6) & 0x3f) | 0x80); + *str++ = (char) ((wc & 0x3f) | 0x80); + return 4; + } + if(!(wc & ~0x3ffffffu)) { + *str++ = (char) ((wc >> 24) | 0xf8); + *str++ = (char) (((wc >> 18) & 0x3f) | 0x80); + *str++ = (char) (((wc >> 12) & 0x3f) | 0x80); + *str++ = (char) (((wc >> 6) & 0x3f) | 0x80); + *str++ = (char) ((wc & 0x3f) | 0x80); + return 5; + } + if(!(wc & ~0x7fffffffu)) { + *str++ = (char) ((wc >> 30) | 0xfc); + *str++ = (char) (((wc >> 24) & 0x3f) | 0x80); + *str++ = (char) (((wc >> 18) & 0x3f) | 0x80); + *str++ = (char) (((wc >> 12) & 0x3f) | 0x80); + *str++ = (char) (((wc >> 6) & 0x3f) | 0x80); + *str++ = (char) ((wc & 0x3f) | 0x80); + return 6; + } + return 0; +} + +// Unescape C-style strings, destination d must hold enough space (and can be source s) +static char *unescape(char *d, const char *s) { + char *ret = d; + int n, k; + + while(*s) { + switch (*s) { + case '\\': + switch (*++s) { + case 'n': + *d = '\n'; + break; + case 't': + *d = '\t'; + break; + case 'a': + *d = '\a'; + break; + case 'b': + *d = '\b'; + break; + case 'e': // non-standard ESC + *d = 27; + break; + case 'f': + *d = '\f'; + break; + case 'r': + *d = '\r'; + break; + case 'v': + *d = '\v'; + break; + case '?': + *d = '?'; + break; + case '`': + *d = '`'; + break; + case '"': + *d = '"'; + break; + case '\'': + *d = '\''; + break; + case '\\': + *d = '\\'; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': // 1-3 octal digits + n = *s - '0'; + for(k = 0; k < 2 && s[1] >= '0' && s[1] <= '7'; k++) // max 2 more octal characters + n *= 8, n += s[1] - '0', s++; + *d = n; + break; + case 'x': // unlimited hex digits + for(k = 0; isxdigit(s[k + 1]); k++) + continue; + if(k > 0) { + *d = tohex(s + 1, k); + s += k; + } else { // no hex digits after \x? copy \x + *d++ = '\\'; + *d = 'x'; + } + break; + case 'u': // exactly 4 hex digits and valid unicode + if(isxdigit(s[1]) && isxdigit(s[2]) && isxdigit(s[3]) && isxdigit(s[4]) && + (n = wc_to_utf8str(tohex(s+1, 4), d))) { + d += n - 1; + s += 4; + } else { // invalid \u sequence? copy \u + *d++ = '\\'; + *d = 'u'; + } + break; + case 'U': // exactly 6 hex digits and valid unicode + if(isxdigit(s[1]) && isxdigit(s[2]) && isxdigit(s[3]) && isxdigit(s[4]) && isxdigit(s[5]) && isxdigit(s[6]) && + (n = wc_to_utf8str(tohex(s+1, 6), d))) { + d += n - 1; + s += 6; + } else { // invalid \U sequence? copy \U + *d++ = '\\'; + *d = 'U'; + } + break; + default: // keep the escape sequence (C would warn and remove \) + *d++ = '\\'; + *d = *s; + } + break; + + default: // not an escape sequence: just copy the character + *d = *s; + } + d++; + s++; + } + *d = *s; // terminate + + return ret; +} + + static size_t maxstrlen(int argc, char **argv) { size_t max = 0; @@ -537,32 +710,38 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, data.size = 8; } - if(!data.size) { - // Try single character - if (argi[0] == '\'' && argi[2] == '\'') { - data.ll = argi[1]; - data.size = 1; - } else { - // Try string that starts and ends with quotes - if (argi[0] == '\"' && argi[arglen - 1] == '\"') { - data.str_ptr = calloc(arglen, sizeof(char)); - if (data.str_ptr == NULL) { - avrdude_message(MSG_INFO, "%s (write str): out of memory\n", progname); - return -1; - } - // Strip start and end quotes - strncpy(data.str_ptr, argi + 1, arglen - 2); - } else { - avrdude_message(MSG_INFO, "\n%s (write): can't parse data '%s'\n", - progname, argi); + if(!data.size) { // Try C-style string or single character + if ((*argi == '\'' && argi[arglen-1] == '\'') || (*argi == '\"' && argi[arglen-1] == '\"')) { + char *s = calloc(arglen-1, 1); + if (s == NULL) { + avrdude_message(MSG_INFO, "%s (write str): out of memory\n", progname); free(buf); - if(data.str_ptr != NULL) - free(data.str_ptr); return -1; - } } + // Strip start and end quotes, and unescape C string + strncpy(s, argi+1, arglen-2); + unescape(s, s); + if (*argi == '\'') { // single C-style character + if(*s && s[1]) + avrdude_message(MSG_INFO, "%s (write): only using first character of %s\n", + progname, argi); + data.ll = *s; + data.size = 1; + free(s); + } else { // C-style string + data.str_ptr = s; + } + } else { + avrdude_message(MSG_INFO, "\n%s (write): can't parse data '%s'\n", + progname, argi); + free(buf); + if(data.str_ptr != NULL) + free(data.str_ptr); + return -1; + } } } + if(data.str_ptr) { for(int16_t j = 0; j < strlen(data.str_ptr); j++) buf[i - start_offset + data.bytes_grown++] = (uint8_t)data.str_ptr[j]; From 0b2f38c67d3501f997a7840ff2f0791cfc3e06cd Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 12 Jul 2022 11:39:52 +0100 Subject: [PATCH 29/57] Allow optional comma separators for data items in terminal write --- src/term.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/term.c b/src/term.c index cd7e3b45..f4472452 100644 --- a/src/term.c +++ b/src/term.c @@ -616,6 +616,10 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, data.str_ptr = NULL; } + // remove trailing comma to allow cut and paste of lists + if(arglen > 0 && argi[arglen-1] == ',') + argi[--arglen] = 0; + // Try integers and assign data size errno = 0; data.ull = strtoull(argi, &end_ptr, 0); From ddffabe86adb3aa3aabc24ea2f7829725602e5b9 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 12 Jul 2022 11:40:40 +0100 Subject: [PATCH 30/57] Improve terminal write usage message --- src/term.c | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/src/term.c b/src/term.c index f4472452..1b563f46 100644 --- a/src/term.c +++ b/src/term.c @@ -523,10 +523,33 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, { if (argc < 4) { avrdude_message(MSG_INFO, - "Usage: write \n" - " write <...>\n\n" - " Add a suffix to manually specify the size for each field:\n" - " HH/hh: 8-bit, H/h/S/s: 16-bit, L/l: 32-bit, LL/ll: 64-bit, F/f: 32-bit float\n"); + "Usage: write [,] {[,]} \n" + " write [,] {[,]} ...\n" + "\n" + "Ellipsis ... writes bytes padded by repeating the last item.\n" + "\n" + " can be hexadecimal, octal or decimal integers, double, float or\n" + "C-style strings and chars. For numbers, an optional case-insensitive suffix\n" + "specifies the data size: HH: 8 bit, H/S: 16 bit, L: 32 bit, LL: 64 bit, F:\n" + "32-bit float. Hexadecimal floating point notation is supported. The\n" + "ambiguous trailing F in 0x1.8F makes the number be interpreted as double;\n" + "use a zero exponent as in 0x1.8p0F to denote a hexadecimal float.\n" + "\n" + "An optional U suffix makes a number unsigned. Ordinary 0x hex numbers are\n" + "always treated as unsigned. +0x or -0x hex numbers are treated as signed\n" + "unless they have a U suffix. Unsigned integers cannot be larger than 2^64-1.\n" + "If n is an unsigned integer then -n is also a valid unsigned integer as in C.\n" + "Signed integers must fall into the [-2^63, 2^63-1] range or a correspondingly\n" + "smaller range when a suffix specifies a smaller type. Out of range signed\n" + "numbers trigger a warning.\n" + "\n" + "Ordinary 0x hex numbers with n hex digits (counting leading zeros) use\n" + "the smallest size of 1, 2, 4 and 8 bytes that can accommodate any n-digit hex\n" + "number. If a suffix specifies a size explicitly the corresponding number of\n" + "least significant bytes are written. Otherwise, signed and unsigned integers\n" + "alike occupy the smallest of 1, 2, 4, or 8 bytes needed to accommodate them\n" + "in their respective representation.\n" + ); return -1; } From aa09bcf9007481791f19ed3ac9e531aa1a04c54c Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 12 Jul 2022 11:42:59 +0100 Subject: [PATCH 31/57] Ensure terminal writes little endian numbers --- src/term.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/term.c b/src/term.c index 1b563f46..65e5c850 100644 --- a/src/term.c +++ b/src/term.c @@ -518,6 +518,16 @@ static size_t maxstrlen(int argc, char **argv) { return max; } + +// Change data item p of size bytes from big endian to little endian and vice versa +static void change_endian(void *p, int size) { + uint8_t tmp, *w = p; + + for(int i=0; i 1) + change_endian(data.a, data.size); } if(data.str_ptr) { From 7205bbae80eb033978bd1c3ffc26d81c0b424522 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 12 Jul 2022 11:43:45 +0100 Subject: [PATCH 32/57] Enhance terminal read with new mode: read --- src/term.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/term.c b/src/term.c index 65e5c850..441868e0 100644 --- a/src/term.c +++ b/src/term.c @@ -255,7 +255,8 @@ static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p, // Get start address if present char * end_ptr; static uint32_t addr = 0; - if (argc == 4) { + + if (argc >= 3 && strcmp(argv[2], "...") != 0) { addr = strtoul(argv[2], &end_ptr, 0); if (*end_ptr || (end_ptr == argv[2])) { avrdude_message(MSG_INFO, "%s (%s): can't parse address \"%s\"\n", From 602e9bb80c85c162a2c448b42c341e4249369640 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 12 Jul 2022 11:44:20 +0100 Subject: [PATCH 33/57] Change size for memory type variable in terminal read --- src/term.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/term.c b/src/term.c index 441868e0..fe3cebfc 100644 --- a/src/term.c +++ b/src/term.c @@ -242,7 +242,7 @@ static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p, } enum { read_size = 256 }; - static char prevmem[128] = {0x00}; + static char prevmem[AVR_MEMDESCLEN] = {0x00}; char * memtype = argv[1]; AVRMEM * mem = avr_locate_mem(p, memtype); if (mem == NULL) { From 92425af0cc004ee5466ec0c576d8152d10a3b5c5 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 12 Jul 2022 11:47:33 +0100 Subject: [PATCH 34/57] Improve terminal dump usage message --- src/term.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/term.c b/src/term.c index fe3cebfc..01fb2560 100644 --- a/src/term.c +++ b/src/term.c @@ -232,13 +232,15 @@ static int hexdump_buf(FILE * f, int startaddr, unsigned char * buf, int len) static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p, int argc, char * argv[]) { - if (argc < 2) { - avrdude_message(MSG_INFO, "Usage: %s [ ]\n" - " %s [ <...>]\n" - " %s <...>\n" - " %s \n", - argv[0], argv[0], argv[0], argv[0]); - return -1; + if (argc < 2 || argc > 4) { + avrdude_message(MSG_INFO, + "Usage: %s \n" + " %s ...\n" + " %s \n" + " %s ...\n" + " %s \n", + argv[0], argv[0], argv[0], argv[0], argv[0]); + return -1; } enum { read_size = 256 }; From c5f522342d394bb8a6b22879dc79be413ea93558 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 12 Jul 2022 11:50:23 +0100 Subject: [PATCH 35/57] Improve terminal help message --- src/term.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/term.c b/src/term.c index 01fb2560..3e9fdd59 100644 --- a/src/term.c +++ b/src/term.c @@ -92,13 +92,13 @@ static int cmd_verbose (PROGRAMMER * pgm, struct avrpart * p, int argc, char *argv[]); struct command cmd[] = { - { "dump", cmd_dump, "dump memory : %s " }, + { "dump", cmd_dump, "%s [ | ... | | ...]" }, { "read", cmd_dump, "alias for dump" }, - { "write", cmd_write, "write memory : %s ... " }, + { "write", cmd_write, "%s [[,] {[,]} | [,] {[,]} ...]" }, { "erase", cmd_erase, "perform a chip erase" }, { "sig", cmd_sig, "display device signature bytes" }, { "part", cmd_part, "display the current part information" }, - { "send", cmd_send, "send a raw command : %s " }, + { "send", cmd_send, "send a raw command: %s " }, { "parms", cmd_parms, "display adjustable parameters (STK500 and Curiosity Nano only)" }, { "vtarg", cmd_vtarg, "set (STK500 and Curiosity Nano only)" }, { "varef", cmd_varef, "set (STK500 only)" }, @@ -1162,9 +1162,9 @@ static int cmd_help(PROGRAMMER * pgm, struct avrpart * p, { int i; - fprintf(stdout, "Valid commands:\n\n"); + fprintf(stdout, "Valid commands:\n"); for (i=0; i Date: Tue, 12 Jul 2022 11:51:04 +0100 Subject: [PATCH 36/57] Remove echo of tokenised terminal command --- src/term.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/term.c b/src/term.c index 3e9fdd59..e7185593 100644 --- a/src/term.c +++ b/src/term.c @@ -1388,7 +1388,6 @@ char * terminal_get_input(const char *prompt) int terminal_mode(PROGRAMMER * pgm, struct avrpart * p) { char * cmdbuf; - int i; char * q; int rc; int argc; @@ -1414,10 +1413,12 @@ int terminal_mode(PROGRAMMER * pgm, struct avrpart * p) return argc; } +#if 0 fprintf(stdout, ">>> "); - for (i=0; i Date: Tue, 12 Jul 2022 11:58:51 +0100 Subject: [PATCH 37/57] Consolidate error messages in term.c --- src/term.c | 149 ++++++++++++++++++++++++++--------------------------- 1 file changed, 74 insertions(+), 75 deletions(-) diff --git a/src/term.c b/src/term.c index e7185593..6d146c66 100644 --- a/src/term.c +++ b/src/term.c @@ -248,8 +248,8 @@ static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p, char * memtype = argv[1]; AVRMEM * mem = avr_locate_mem(p, memtype); if (mem == NULL) { - avrdude_message(MSG_INFO, "\"%s\" memory type not defined for part \"%s\"\n", - memtype, p->desc); + avrdude_message(MSG_INFO, "%s (dump): %s memory type not defined for part %s\n", + progname, memtype, p->desc); return -1; } uint32_t maxsize = mem->size; @@ -261,12 +261,12 @@ static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p, if (argc >= 3 && strcmp(argv[2], "...") != 0) { addr = strtoul(argv[2], &end_ptr, 0); if (*end_ptr || (end_ptr == argv[2])) { - avrdude_message(MSG_INFO, "%s (%s): can't parse address \"%s\"\n", - progname, argv[0], argv[2]); + avrdude_message(MSG_INFO, "%s (dump): can't parse address %s\n", + progname, argv[2]); return -1; } else if (addr >= maxsize) { - avrdude_message(MSG_INFO, "%s (%s): address 0x%05lx is out of range for %s memory\n", - progname, argv[0], addr, mem->desc); + avrdude_message(MSG_INFO, "%s (dump): address 0x%05lx is out of range for %s memory\n", + progname, (long) addr, mem->desc); return -1; } } @@ -282,8 +282,8 @@ static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p, } else if (argc == 4) { len = strtol(argv[3], &end_ptr, 0); if (*end_ptr || (end_ptr == argv[3])) { - avrdude_message(MSG_INFO, "%s (%s): can't parse length \"%s\"\n", - progname, argv[0], argv[3]); + avrdude_message(MSG_INFO, "%s (dump): can't parse length %s\n", + progname, argv[3]); return -1; } } else { @@ -317,10 +317,10 @@ static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p, int32_t rc = pgm->read_byte(pgm, p, mem, addr + i, &buf[i]); if (rc != 0) { avrdude_message(MSG_INFO, "error reading %s address 0x%05lx of part %s\n", - mem->desc, addr + i, p->desc); + mem->desc, (long) addr + i, p->desc); if (rc == -1) - avrdude_message(MSG_INFO, "read operation not supported on memory type \"%s\"\n", - mem->desc); + avrdude_message(MSG_INFO, "read operation not supported on memory type %s\n", + mem->desc); return -1; } report_progress(i, len, NULL); @@ -573,8 +573,8 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, char * memtype = argv[1]; // Memory name string AVRMEM * mem = avr_locate_mem(p, memtype); if (mem == NULL) { - avrdude_message(MSG_INFO, "\"%s\" memory type not defined for part \"%s\"\n", - memtype, p->desc); + avrdude_message(MSG_INFO, "%s memory type not defined for part %s\n", + memtype, p->desc); return -1; } uint32_t maxsize = mem->size; @@ -582,14 +582,14 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, char * end_ptr; int32_t addr = strtoul(argv[2], &end_ptr, 0); if (*end_ptr || (end_ptr == argv[2])) { - avrdude_message(MSG_INFO, "%s (write): can't parse address \"%s\"\n", - progname, argv[2]); + avrdude_message(MSG_INFO, "%s (write): can't parse address %s\n", + progname, argv[2]); return -1; } if (addr > maxsize) { avrdude_message(MSG_INFO, "%s (write): address 0x%05lx is out of range for %s memory\n", - progname, addr, memtype); + progname, (long) addr, memtype); return -1; } @@ -606,8 +606,8 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, start_offset = 4; len = strtoul(argv[3], &end_ptr, 0); if (*end_ptr || (end_ptr == argv[3])) { - avrdude_message(MSG_INFO, "%s (write ...): can't parse length \"%s\"\n", - progname, argv[3]); + avrdude_message(MSG_INFO, "%s (write ...): can't parse length %s\n", + progname, argv[3]); free(buf); return -1; } @@ -639,7 +639,8 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, }; if(sizeof(long long) != sizeof(int64_t) || (data.a[0]^data.a[7]) != 1) - avrdude_message(MSG_INFO, "%s (write): assumption on data types not met? check source and recompile\n", progname); + avrdude_message(MSG_INFO, "%s (write): assumption on data types not met? " + "Check source and recompile\n", progname); bool is_big_endian = data.a[7]; for (i = start_offset; i < len + start_offset; i++) { @@ -734,10 +735,8 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, if(is_outside_int64_t || is_out_of_range) avrdude_message(MSG_INFO, "%s (write): %s out of int%d_t range, " - "interpreted as %d-byte %lld%s; consider 'U' suffix\n", - progname, argi, data.size*8, data.size, data.ll, - is_out_of_range? " (unlikely what you want)": "" - ); + "interpreted as %d-byte %lld; consider 'U' suffix\n", + progname, argi, data.size*8, data.size, data.ll); } } } @@ -768,7 +767,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, if (*argi == '\'') { // single C-style character if(*s && s[1]) avrdude_message(MSG_INFO, "%s (write): only using first character of %s\n", - progname, argi); + progname, argi); data.ll = *s; data.size = 1; free(s); @@ -776,8 +775,8 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, data.str_ptr = s; } } else { - avrdude_message(MSG_INFO, "\n%s (write): can't parse data '%s'\n", - progname, argi); + avrdude_message(MSG_INFO, "%s (write): can't parse data %s\n", + progname, argi); free(buf); if(data.str_ptr != NULL) free(data.str_ptr); @@ -819,8 +818,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, if ((addr + len + data.bytes_grown) > maxsize) { avrdude_message(MSG_INFO, "%s (write): selected address and # bytes exceed " - "range for %s memory\n", - progname, memtype); + "range for %s memory\n", progname, memtype); free(buf); return -1; } @@ -828,8 +826,8 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, if(data.str_ptr) free(data.str_ptr); - avrdude_message(MSG_NOTICE, "\nInfo: Writing %d bytes starting from address 0x%02x", - len + data.bytes_grown, addr); + avrdude_message(MSG_NOTICE, "\nInfo: Writing %d bytes starting from address 0x%02lx", + len + data.bytes_grown, (long) addr); if (write_mode == WRITE_MODE_FILL) avrdude_message(MSG_NOTICE, ". Remaining space filled with %s", argv[argc - 2]); avrdude_message(MSG_NOTICE, "\n"); @@ -841,10 +839,10 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, int32_t rc = avr_write_byte(pgm, p, mem, addr+i, buf[i]); if (rc) { avrdude_message(MSG_INFO, "%s (write): error writing 0x%02x at 0x%05lx, rc=%d\n", - progname, buf[i], addr+i, rc); + progname, buf[i], (long) addr+i, (int) rc); if (rc == -1) - avrdude_message(MSG_INFO, "write operation not supported on memory type \"%s\"\n", - mem->desc); + avrdude_message(MSG_INFO, "write operation not supported on memory type %s\n", + mem->desc); werror = true; } @@ -852,7 +850,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, rc = pgm->read_byte(pgm, p, mem, addr+i, &b); if (b != buf[i]) { avrdude_message(MSG_INFO, "%s (write): error writing 0x%02x at 0x%05lx cell=0x%02x\n", - progname, buf[i], addr+i, b); + progname, buf[i], (long) addr+i, b); werror = true; } @@ -879,14 +877,14 @@ static int cmd_send(PROGRAMMER * pgm, struct avrpart * p, int len; if (pgm->cmd == NULL) { - avrdude_message(MSG_INFO, "The %s programmer does not support direct ISP commands.\n", - pgm->type); + avrdude_message(MSG_INFO, "%s (send): the %s programmer does not support direct ISP commands\n", + progname, pgm->type); return -1; } if (spi_mode && (pgm->spi == NULL)) { - avrdude_message(MSG_INFO, "The %s programmer does not support direct SPI transfers.\n", - pgm->type); + avrdude_message(MSG_INFO, "%s (send): the %s programmer does not support direct SPI transfers\n", + progname, pgm->type); return -1; } @@ -905,8 +903,8 @@ static int cmd_send(PROGRAMMER * pgm, struct avrpart * p, for (i=1; idesc); + avrdude_message(MSG_INFO, "%s (sig): signature data not defined for device %s\n", + progname, p->desc); } else { fprintf(stdout, "Device signature = 0x"); @@ -997,8 +995,7 @@ static int cmd_parms(PROGRAMMER * pgm, struct avrpart * p, { if (pgm->print_parms == NULL) { avrdude_message(MSG_INFO, "%s (parms): the %s programmer does not support " - "adjustable parameters\n", - progname, pgm->type); + "adjustable parameters\n", progname, pgm->type); return -1; } pgm->print_parms(pgm); @@ -1020,18 +1017,18 @@ static int cmd_vtarg(PROGRAMMER * pgm, struct avrpart * p, } v = strtod(argv[1], &endp); if (endp == argv[1]) { - avrdude_message(MSG_INFO, "%s (vtarg): can't parse voltage \"%s\"\n", - progname, argv[1]); + avrdude_message(MSG_INFO, "%s (vtarg): can't parse voltage %s\n", + progname, argv[1]); return -1; } if (pgm->set_vtarget == NULL) { avrdude_message(MSG_INFO, "%s (vtarg): the %s programmer cannot set V[target]\n", - progname, pgm->type); + progname, pgm->type); return -2; } if ((rc = pgm->set_vtarget(pgm, v)) != 0) { avrdude_message(MSG_INFO, "%s (vtarg): failed to set V[target] (rc = %d)\n", - progname, rc); + progname, rc); return -3; } return 0; @@ -1054,8 +1051,8 @@ static int cmd_fosc(PROGRAMMER * pgm, struct avrpart * p, if (strcmp(argv[1], "off") == 0) v = 0.0; else { - avrdude_message(MSG_INFO, "%s (fosc): can't parse frequency \"%s\"\n", - progname, argv[1]); + avrdude_message(MSG_INFO, "%s (fosc): can't parse frequency %s\n", + progname, argv[1]); return -1; } } @@ -1065,12 +1062,12 @@ static int cmd_fosc(PROGRAMMER * pgm, struct avrpart * p, v *= 1e3; if (pgm->set_fosc == NULL) { avrdude_message(MSG_INFO, "%s (fosc): the %s programmer cannot set oscillator frequency\n", - progname, pgm->type); + progname, pgm->type); return -2; } if ((rc = pgm->set_fosc(pgm, v)) != 0) { avrdude_message(MSG_INFO, "%s (fosc): failed to set oscillator frequency (rc = %d)\n", - progname, rc); + progname, rc); return -3; } return 0; @@ -1090,19 +1087,19 @@ static int cmd_sck(PROGRAMMER * pgm, struct avrpart * p, } v = strtod(argv[1], &endp); if (endp == argv[1]) { - avrdude_message(MSG_INFO, "%s (sck): can't parse period \"%s\"\n", - progname, argv[1]); + avrdude_message(MSG_INFO, "%s (sck): can't parse period %s\n", + progname, argv[1]); return -1; } v *= 1e-6; /* Convert from microseconds to seconds. */ if (pgm->set_sck_period == NULL) { avrdude_message(MSG_INFO, "%s (sck): the %s programmer cannot set SCK period\n", - progname, pgm->type); + progname, pgm->type); return -2; } if ((rc = pgm->set_sck_period(pgm, v)) != 0) { avrdude_message(MSG_INFO, "%s (sck): failed to set SCK period (rc = %d)\n", - progname, rc); + progname, rc); return -3; } return 0; @@ -1125,32 +1122,32 @@ static int cmd_varef(PROGRAMMER * pgm, struct avrpart * p, chan = 0; v = strtod(argv[1], &endp); if (endp == argv[1]) { - avrdude_message(MSG_INFO, "%s (varef): can't parse voltage \"%s\"\n", - progname, argv[1]); + avrdude_message(MSG_INFO, "%s (varef): can't parse voltage %s\n", + progname, argv[1]); return -1; } } else { chan = strtoul(argv[1], &endp, 10); if (endp == argv[1]) { - avrdude_message(MSG_INFO, "%s (varef): can't parse channel \"%s\"\n", - progname, argv[1]); + avrdude_message(MSG_INFO, "%s (varef): can't parse channel %s\n", + progname, argv[1]); return -1; } v = strtod(argv[2], &endp); if (endp == argv[2]) { - avrdude_message(MSG_INFO, "%s (varef): can't parse voltage \"%s\"\n", - progname, argv[2]); + avrdude_message(MSG_INFO, "%s (varef): can't parse voltage %s\n", + progname, argv[2]); return -1; } } if (pgm->set_varef == NULL) { avrdude_message(MSG_INFO, "%s (varef): the %s programmer cannot set V[aref]\n", - progname, pgm->type); + progname, pgm->type); return -2; } if ((rc = pgm->set_varef(pgm, chan, v)) != 0) { avrdude_message(MSG_INFO, "%s (varef): failed to set V[aref] (rc = %d)\n", - progname, rc); + progname, rc); return -3; } return 0; @@ -1183,7 +1180,8 @@ static int cmd_spi(PROGRAMMER * pgm, struct avrpart * p, spi_mode = 1; return 0; } - avrdude_message(MSG_INFO, "`spi' command unavailable for this programmer type\n"); + avrdude_message(MSG_INFO, "%s: spi command unavailable for this programmer type\n", + progname); return -1; } @@ -1196,7 +1194,8 @@ static int cmd_pgm(PROGRAMMER * pgm, struct avrpart * p, pgm->initialize(pgm, p); return 0; } - avrdude_message(MSG_INFO, "`pgm' command unavailable for this programmer type\n"); + avrdude_message(MSG_INFO, "%s: pgm command unavailable for this programmer type\n", + progname); return -1; } @@ -1216,13 +1215,13 @@ static int cmd_verbose(PROGRAMMER * pgm, struct avrpart * p, } nverb = strtol(argv[1], &endp, 0); if (endp == argv[2]) { - avrdude_message(MSG_INFO, "%s: can't parse verbosity level \"%s\"\n", - progname, argv[2]); + avrdude_message(MSG_INFO, "%s: can't parse verbosity level %s\n", + progname, argv[2]); return -1; } if (nverb < 0) { avrdude_message(MSG_INFO, "%s: verbosity level must be positive: %d\n", - progname, nverb); + progname, nverb); return -1; } verbose = nverb; @@ -1344,8 +1343,8 @@ static int do_cmd(PROGRAMMER * pgm, struct avrpart * p, } else if (strncasecmp(argv[0], cmd[i].name, len)==0) { if (hold != -1) { - avrdude_message(MSG_INFO, "%s: command \"%s\" is ambiguous\n", - progname, argv[0]); + avrdude_message(MSG_INFO, "%s (cmd): command %s is ambiguous\n", + progname, argv[0]); return -1; } hold = i; @@ -1355,8 +1354,8 @@ static int do_cmd(PROGRAMMER * pgm, struct avrpart * p, if (hold != -1) return cmd[hold].func(pgm, p, argc, argv); - avrdude_message(MSG_INFO, "%s: invalid command \"%s\"\n", - progname, argv[0]); + avrdude_message(MSG_INFO, "%s (cmd): invalid command %s\n", + progname, argv[0]); return -1; } From 704d2536368a421da11a1d57c55907bbc027b3c2 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 12 Jul 2022 11:59:42 +0100 Subject: [PATCH 38/57] Remove comparisons between signed and unsigned integers in term.c --- src/term.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/term.c b/src/term.c index 6d146c66..865a413c 100644 --- a/src/term.c +++ b/src/term.c @@ -112,7 +112,7 @@ struct command cmd[] = { { "quit", cmd_quit, "quit" } }; -#define NCMDS (sizeof(cmd)/sizeof(struct command)) +#define NCMDS ((int)(sizeof(cmd)/sizeof(struct command))) @@ -157,8 +157,8 @@ static int hexdump_line(char * buffer, unsigned char * p, int n, int pad) { char * hexdata = "0123456789abcdef"; char * b = buffer; - int32_t i = 0; - int32_t j = 0; + int i = 0; + int j = 0; for (i=0; i len) n = len; hexdump_line(dst1, p, n, 48); @@ -252,11 +252,11 @@ static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p, progname, memtype, p->desc); return -1; } - uint32_t maxsize = mem->size; + int maxsize = mem->size; // Get start address if present char * end_ptr; - static uint32_t addr = 0; + static int addr = 0; if (argc >= 3 && strcmp(argv[2], "...") != 0) { addr = strtoul(argv[2], &end_ptr, 0); @@ -272,7 +272,7 @@ static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p, } // Get no. bytes to read if present - static int32_t len = read_size; + static int len = read_size; if (argc >= 3) { memset(prevmem, 0x00, sizeof(prevmem)); if (strcmp(argv[argc - 1], "...") == 0) { @@ -313,8 +313,8 @@ static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p, } report_progress(0, 1, "Reading"); - for (uint32_t i = 0; i < len; i++) { - int32_t rc = pgm->read_byte(pgm, p, mem, addr + i, &buf[i]); + for (int i = 0; i < len; i++) { + int rc = pgm->read_byte(pgm, p, mem, addr + i, &buf[i]); if (rc != 0) { avrdude_message(MSG_INFO, "error reading %s address 0x%05lx of part %s\n", mem->desc, (long) addr + i, p->desc); @@ -566,10 +566,10 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, return -1; } - int32_t i; + int i; uint8_t write_mode; // Operation mode, "standard" or "fill" uint8_t start_offset; // Which argc argument - int32_t len; // Number of bytes to write to memory + 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) { @@ -577,10 +577,10 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, memtype, p->desc); return -1; } - uint32_t maxsize = mem->size; + int maxsize = mem->size; char * end_ptr; - int32_t addr = strtoul(argv[2], &end_ptr, 0); + int addr = strtoul(argv[2], &end_ptr, 0); if (*end_ptr || (end_ptr == argv[2])) { avrdude_message(MSG_INFO, "%s (write): can't parse address %s\n", progname, argv[2]); @@ -620,7 +620,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, // Structure related to data that is being written to memory struct Data { // Data info - int32_t bytes_grown; + int bytes_grown; uint8_t size; char * str_ptr; // Data union @@ -789,7 +789,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, } if(data.str_ptr) { - for(int16_t j = 0; j < strlen(data.str_ptr); j++) + for(size_t j = 0; j < strlen(data.str_ptr); j++) buf[i - start_offset + data.bytes_grown++] = (uint8_t)data.str_ptr[j]; } else { buf[i - start_offset + data.bytes_grown] = data.a[0]; @@ -836,7 +836,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, bool werror = false; report_progress(0, 1, "Writing"); for (i = 0; i < (len + data.bytes_grown); i++) { - int32_t rc = avr_write_byte(pgm, p, mem, addr+i, buf[i]); + int rc = avr_write_byte(pgm, p, mem, addr+i, buf[i]); if (rc) { avrdude_message(MSG_INFO, "%s (write): error writing 0x%02x at 0x%05lx, rc=%d\n", progname, buf[i], (long) addr+i, (int) rc); @@ -960,7 +960,7 @@ static int cmd_sig(PROGRAMMER * pgm, struct avrpart * p, rc = avr_signature(pgm, p); if (rc != 0) { avrdude_message(MSG_INFO, "%s (sig): error reading signature data, rc=%d\n", - prgname, rc); + progname, rc); } m = avr_locate_mem(p, "signature"); From 7c766ef9bd9dd35c011ad583351909d744222985 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 12 Jul 2022 12:01:14 +0100 Subject: [PATCH 39/57] Refine type detection in terminal write The code no longer accepts valid mantissa-only doubles that are integer rejects, eg, 078 or ULL overflows. These are most likely input errors by the user: 8 is not an octal digit, they might have typed 17 hex digits, not 16. It's just too hard to explain that 0xffffFFFFffffFFFFf writes 0x4430000000000000, which is the correct double representation of the valid 17-digit hex mantissa that strtod() is perfectly happy to accept. --- src/term.c | 55 ++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 41 insertions(+), 14 deletions(-) diff --git a/src/term.c b/src/term.c index 865a413c..1f5ec4b4 100644 --- a/src/term.c +++ b/src/term.c @@ -531,6 +531,30 @@ static void change_endian(void *p, int size) { } +// Looks like a double mantissa in hex or dec notation +static int is_mantissa_only(char *p) { + char *digs; + + if(*p == '+' || *p == '-') + p++; + + if(*p == '0' && (p[1] == 'x' || p[1] == 'X')) { + p += 2; + digs = "0123456789abcdefABCDEF"; + } else + digs = "0123456789"; + + if(!*p) + return 0; + + while(*p) + if(!strchr(digs, *p++)) + return 0; + + return 1; +} + + static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, int argc, char * argv[]) { @@ -741,18 +765,20 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, } } + if(!data.size) { // Try double now that input was rejected as integer + data.d = strtod(argi, &end_ptr); + // Do not accept valid doubles that are integer rejects (eg, 078 or ULL overflows) + if (end_ptr != argi && *end_ptr == 0) + if (!is_mantissa_only(argi)) + data.size = 8; + } + if(!data.size) { // Try float data.f = strtof(argi, &end_ptr); if (end_ptr != argi && toupper(*end_ptr) == 'F' && end_ptr[1] == 0) data.size = 4; } - if(!data.size) { // Try double - data.d = strtod(argi, &end_ptr); - if (end_ptr != argi && *end_ptr == 0) - data.size = 8; - } - if(!data.size) { // Try C-style string or single character if ((*argi == '\'' && argi[arglen-1] == '\'') || (*argi == '\"' && argi[arglen-1] == '\"')) { char *s = calloc(arglen-1, 1); @@ -774,16 +800,17 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, } else { // C-style string data.str_ptr = s; } - } else { - avrdude_message(MSG_INFO, "%s (write): can't parse data %s\n", - progname, argi); - free(buf); - if(data.str_ptr != NULL) - free(data.str_ptr); - return -1; } } - // ensure we have little endian representation in data.a + + if(!data.size && !data.str_ptr) { + avrdude_message(MSG_INFO, "%s (write): can't parse data %s\n", + progname, argi); + free(buf); + return -1; + } + + // Assume endianness is the same for double and int, and ensure little endian representation if(is_big_endian && data.size > 1) change_endian(data.a, data.size); } From f871a4dc1ea57c417b9c8fe4c2731fa330853f73 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 12 Jul 2022 12:02:33 +0100 Subject: [PATCH 40/57] Adapt capitalisation of comments in term.c to existing style --- src/term.c | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/term.c b/src/term.c index 1f5ec4b4..181a3b4a 100644 --- a/src/term.c +++ b/src/term.c @@ -339,7 +339,7 @@ static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p, -// convert the next n hex digits of s to a hex number +// Convert the next n hex digits of s to a hex number static unsigned int tohex(const char *s, unsigned int n) { int ret, c; @@ -422,7 +422,7 @@ static char *unescape(char *d, const char *s) { case 'b': *d = '\b'; break; - case 'e': // non-standard ESC + case 'e': // Non-standard ESC *d = 27; break; case 'f': @@ -458,54 +458,54 @@ static char *unescape(char *d, const char *s) { case '6': case '7': // 1-3 octal digits n = *s - '0'; - for(k = 0; k < 2 && s[1] >= '0' && s[1] <= '7'; k++) // max 2 more octal characters + for(k = 0; k < 2 && s[1] >= '0' && s[1] <= '7'; k++) // Max 2 more octal characters n *= 8, n += s[1] - '0', s++; *d = n; break; - case 'x': // unlimited hex digits + case 'x': // Unlimited hex digits for(k = 0; isxdigit(s[k + 1]); k++) continue; if(k > 0) { *d = tohex(s + 1, k); s += k; - } else { // no hex digits after \x? copy \x + } else { // No hex digits after \x? copy \x *d++ = '\\'; *d = 'x'; } break; - case 'u': // exactly 4 hex digits and valid unicode + case 'u': // Exactly 4 hex digits and valid unicode if(isxdigit(s[1]) && isxdigit(s[2]) && isxdigit(s[3]) && isxdigit(s[4]) && (n = wc_to_utf8str(tohex(s+1, 4), d))) { d += n - 1; s += 4; - } else { // invalid \u sequence? copy \u + } else { // Invalid \u sequence? copy \u *d++ = '\\'; *d = 'u'; } break; - case 'U': // exactly 6 hex digits and valid unicode + case 'U': // Exactly 6 hex digits and valid unicode if(isxdigit(s[1]) && isxdigit(s[2]) && isxdigit(s[3]) && isxdigit(s[4]) && isxdigit(s[5]) && isxdigit(s[6]) && (n = wc_to_utf8str(tohex(s+1, 6), d))) { d += n - 1; s += 6; - } else { // invalid \U sequence? copy \U + } else { // Invalid \U sequence? copy \U *d++ = '\\'; *d = 'U'; } break; - default: // keep the escape sequence (C would warn and remove \) + default: // Keep the escape sequence (C would warn and remove \) *d++ = '\\'; *d = *s; } break; - default: // not an escape sequence: just copy the character + default: // Not an escape sequence: just copy the character *d = *s; } d++; s++; } - *d = *s; // terminate + *d = *s; // Terminate return ret; } @@ -681,7 +681,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, data.str_ptr = NULL; } - // remove trailing comma to allow cut and paste of lists + // Remove trailing comma to allow cut and paste of lists if(arglen > 0 && argi[arglen-1] == ',') argi[--arglen] = 0; @@ -692,7 +692,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, unsigned int nu=0, nl=0, nh=0, ns=0, nx=0; char *p; - // parse suffixes: ULL, LL, UL, L ... UHH, HH + // Parse suffixes: ULL, LL, UL, L ... UHH, HH for(p=end_ptr; *p; p++) switch(toupper(*p)) { case 'U': nu++; break; @@ -702,10 +702,10 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, default: nx++; } - if(nx==0 && nu<2 && nl<3 && nh<3 && ns<2) { // could be valid integer suffix - if(nu==0 || toupper(*end_ptr) == 'U' || toupper(p[-1]) == 'U') { // if U, then must be at start or end - bool is_hex = strncasecmp(argi, "0x", 2) == 0; // ordinary hex: "0x..." without explicit +/- sign - bool is_signed = !(nu || is_hex); // neither explicitly unsigned nor ordinary hex + if(nx==0 && nu<2 && nl<3 && nh<3 && ns<2) { // Could be valid integer suffix + if(nu==0 || toupper(*end_ptr) == 'U' || toupper(p[-1]) == 'U') { // If U, then must be at start or end + bool is_hex = strncasecmp(argi, "0x", 2) == 0; // Ordinary hex: 0x... without explicit +/- sign + bool is_signed = !(nu || is_hex); // Neither explicitly unsigned nor ordinary hex bool is_outside_int64_t = 0; bool is_out_of_range = 0; int nhexdigs = p-argi-2; @@ -715,13 +715,13 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, is_outside_int64_t = errno == ERANGE; } - if(nl==0 && ns==0 && nh==0) { // no explicit data size - // ordinary hex numbers have "implicit" size, given by number of hex digits, including leading zeros + if(nl==0 && ns==0 && nh==0) { // No explicit data size + // Ordinary hex numbers have implicit size given by number of hex digits, including leading zeros if(is_hex) { data.size = nhexdigs > 8? 8: nhexdigs > 4? 4: nhexdigs > 2? 2: 1; } else if(is_signed) { - // smallest size that fits signed representation + // Smallest size that fits signed representation data.size = is_outside_int64_t? 8: data.ll < INT32_MIN || data.ll > INT32_MAX? 8: @@ -729,7 +729,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, data.ll < INT8_MIN || data.ll > INT8_MAX? 2: 1; } else { - // smallest size that fits unsigned representation + // Smallest size that fits unsigned representation data.size = data.ull > UINT32_MAX? 8: data.ull > UINT16_MAX? 4: @@ -767,7 +767,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, if(!data.size) { // Try double now that input was rejected as integer data.d = strtod(argi, &end_ptr); - // Do not accept valid doubles that are integer rejects (eg, 078 or ULL overflows) + // Do not accept valid mantissa-only doubles that are integer rejects (eg, 078 or ULL overflows) if (end_ptr != argi && *end_ptr == 0) if (!is_mantissa_only(argi)) data.size = 8; @@ -790,7 +790,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, // Strip start and end quotes, and unescape C string strncpy(s, argi+1, arglen-2); unescape(s, s); - if (*argi == '\'') { // single C-style character + if (*argi == '\'') { // Single C-style character if(*s && s[1]) avrdude_message(MSG_INFO, "%s (write): only using first character of %s\n", progname, argi); From 63fb79accbf867af563f83163410b58f0e7f832d Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 12 Jul 2022 12:24:30 +0100 Subject: [PATCH 41/57] Consolidate more error messages in term.c --- src/term.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/term.c b/src/term.c index 181a3b4a..8dc44233 100644 --- a/src/term.c +++ b/src/term.c @@ -316,11 +316,11 @@ static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p, for (int i = 0; i < len; i++) { int rc = pgm->read_byte(pgm, p, mem, addr + i, &buf[i]); if (rc != 0) { - avrdude_message(MSG_INFO, "error reading %s address 0x%05lx of part %s\n", - mem->desc, (long) addr + i, p->desc); + avrdude_message(MSG_INFO, "%s (dump): error reading %s address 0x%05lx of part %s\n", + progname, mem->desc, (long) addr + i, p->desc); if (rc == -1) - avrdude_message(MSG_INFO, "read operation not supported on memory type %s\n", - mem->desc); + avrdude_message(MSG_INFO, "%*sread operation not supported on memory type %s\n", + (int) strlen(progname)+9, "", mem->desc); return -1; } report_progress(i, len, NULL); @@ -597,8 +597,8 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, char * memtype = argv[1]; // Memory name string AVRMEM * mem = avr_locate_mem(p, memtype); if (mem == NULL) { - avrdude_message(MSG_INFO, "%s memory type not defined for part %s\n", - memtype, p->desc); + avrdude_message(MSG_INFO, "%s (write): %s memory type not defined for part %s\n", + progname, memtype, p->desc); return -1; } int maxsize = mem->size; @@ -853,10 +853,10 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, if(data.str_ptr) free(data.str_ptr); - avrdude_message(MSG_NOTICE, "\nInfo: Writing %d bytes starting from address 0x%02lx", + avrdude_message(MSG_NOTICE, "Info: writing %d bytes starting from address 0x%02lx", len + data.bytes_grown, (long) addr); if (write_mode == WRITE_MODE_FILL) - avrdude_message(MSG_NOTICE, ". Remaining space filled with %s", argv[argc - 2]); + avrdude_message(MSG_NOTICE, "; remaining space filled with %s", argv[argc - 2]); avrdude_message(MSG_NOTICE, "\n"); pgm->err_led(pgm, OFF); @@ -868,8 +868,8 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, avrdude_message(MSG_INFO, "%s (write): error writing 0x%02x at 0x%05lx, rc=%d\n", progname, buf[i], (long) addr+i, (int) rc); if (rc == -1) - avrdude_message(MSG_INFO, "write operation not supported on memory type %s\n", - mem->desc); + avrdude_message(MSG_INFO, "%*swrite operation not supported on memory type %s\n", + (int) strlen(progname)+10, "", mem->desc); werror = true; } From d9cb9772d7bfd1569d85fb6eef98cf7bc8c7111f Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 12 Jul 2022 12:30:29 +0100 Subject: [PATCH 42/57] Fix verbosity level parsing in term.c --- src/term.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/term.c b/src/term.c index 8dc44233..41b172ec 100644 --- a/src/term.c +++ b/src/term.c @@ -1241,13 +1241,13 @@ static int cmd_verbose(PROGRAMMER * pgm, struct avrpart * p, return 0; } nverb = strtol(argv[1], &endp, 0); - if (endp == argv[2]) { - avrdude_message(MSG_INFO, "%s: can't parse verbosity level %s\n", - progname, argv[2]); + if (endp == argv[1] || *endp) { + avrdude_message(MSG_INFO, "%s (verbose): can't parse verbosity level %s\n", + progname, argv[1]); return -1; } if (nverb < 0) { - avrdude_message(MSG_INFO, "%s: verbosity level must be positive: %d\n", + avrdude_message(MSG_INFO, "%s: verbosity level must not be negative: %d\n", progname, nverb); return -1; } From 1e8b56751e4368db5abbf09337610916965df0cc Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 12 Jul 2022 13:11:10 +0100 Subject: [PATCH 43/57] Add quell command in terminal Sets the quell_progress global variable that can be, and is, consulted by programmers. Setting quell_progress to a positive number also switches off progress bars. It is currently not possible to switch on progress bars again: that is enabled in main.c once at the start of AVRDUDE. That code in main should move to avr.c to enable report_update() to consult quell_progress directly. Will do at another time when touching main.c and avr.c. smr --- src/term.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/term.c b/src/term.c index 41b172ec..5050938b 100644 --- a/src/term.c +++ b/src/term.c @@ -91,6 +91,9 @@ static int cmd_pgm (PROGRAMMER * pgm, struct avrpart * p, static int cmd_verbose (PROGRAMMER * pgm, struct avrpart * p, int argc, char *argv[]); +static int cmd_quell (PROGRAMMER * pgm, struct avrpart * p, + int argc, char *argv[]); + struct command cmd[] = { { "dump", cmd_dump, "%s [ | ... | | ...]" }, { "read", cmd_dump, "alias for dump" }, @@ -107,6 +110,7 @@ struct command cmd[] = { { "spi", cmd_spi, "enter direct SPI mode" }, { "pgm", cmd_pgm, "return to programming mode" }, { "verbose", cmd_verbose, "change verbosity" }, + { "quell", cmd_quell, "set quell level for progress bars" }, { "help", cmd_help, "help" }, { "?", cmd_help, "help" }, { "quit", cmd_quit, "quit" } @@ -1257,6 +1261,40 @@ static int cmd_verbose(PROGRAMMER * pgm, struct avrpart * p, return 0; } +static int cmd_quell(PROGRAMMER * pgm, struct avrpart * p, + int argc, char * argv[]) +{ + int nquell; + char *endp; + + if (argc != 1 && argc != 2) { + avrdude_message(MSG_INFO, "Usage: quell []\n"); + return -1; + } + if (argc == 1) { + avrdude_message(MSG_INFO, "Quell level: %d\n", quell_progress); + return 0; + } + nquell = strtol(argv[1], &endp, 0); + if (endp == argv[1] || *endp) { + avrdude_message(MSG_INFO, "%s (quell): can't parse quell level %s\n", + progname, argv[1]); + return -1; + } + if (nquell < 0) { + avrdude_message(MSG_INFO, "%s: quell level must not be negative: %d\n", + progname, nquell); + return -1; + } + quell_progress = nquell; + avrdude_message(MSG_INFO, "New quell level: %d\n", quell_progress); + + if(quell_progress > 0) + update_progress = NULL; + + return 0; +} + static int tokenize(char * s, char *** argv) { int i, n, l, k, nargs, offset; From b6204b181a3cb5167e2c41abe3dd79ae19f947c6 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 12 Jul 2022 15:22:52 +0100 Subject: [PATCH 44/57] Provide echo of terminal command line prompt under Windows --- src/term.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/term.c b/src/term.c index 5050938b..fe19d2d5 100644 --- a/src/term.c +++ b/src/term.c @@ -1477,7 +1477,7 @@ int terminal_mode(PROGRAMMER * pgm, struct avrpart * p) return argc; } -#if 0 +#if defined(WIN32) fprintf(stdout, ">>> "); for (int i=0; i Date: Tue, 12 Jul 2022 21:53:37 +0100 Subject: [PATCH 45/57] Echo >>> terminal command line for Windows or non-libreadline --- src/term.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/term.c b/src/term.c index fe19d2d5..1f294540 100644 --- a/src/term.c +++ b/src/term.c @@ -1477,7 +1477,7 @@ int terminal_mode(PROGRAMMER * pgm, struct avrpart * p) return argc; } -#if defined(WIN32) +#if !defined(HAVE_LIBREADLINE) || defined(WIN32) fprintf(stdout, ">>> "); for (int i=0; i Date: Wed, 13 Jul 2022 11:19:21 +0100 Subject: [PATCH 46/57] Fix isspace() and other isxxx() calls in term.c --- src/term.c | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/src/term.c b/src/term.c index 1f294540..8cd48b99 100644 --- a/src/term.c +++ b/src/term.c @@ -124,19 +124,19 @@ static int spi_mode = 0; static int nexttok(char * buf, char ** tok, char ** next) { - char * q, * n; + unsigned char *q, *n; - q = buf; - while (isspace((int)*q)) + q = (unsigned char *) buf; + while (isspace(*q)) q++; /* isolate first token */ n = q; uint8_t quotes = 0; - while (*n && (!isspace((int)*n) || quotes)) { + while (*n && (!isspace(*n) || quotes)) { if (*n == '\"') quotes++; - else if (isspace((int)*n) && *(n-1) == '\"') + else if (isspace(*n) && *(n-1) == '\"') break; n++; } @@ -147,11 +147,11 @@ static int nexttok(char * buf, char ** tok, char ** next) } /* find start of next token */ - while (isspace((int)*n)) + while (isspace(*n)) n++; - *tok = q; - *next = n; + *tok = (char *) q; + *next = (char *) n; return 0; } @@ -190,14 +190,17 @@ static int hexdump_line(char * buffer, unsigned char * p, int n, int pad) static int chardump_line(char * buffer, unsigned char * p, int n, int pad) { int i; - char b [ 128 ]; + unsigned char b[128]; + // sanity check + n = n < 1? 1: n > sizeof b? sizeof b: n; + + memcpy(b, p, n); for (int i = 0; i < n; i++) { - memcpy(b, p, n); buffer[i] = '.'; - if (isalpha((int)(b[i])) || isdigit((int)(b[i])) || ispunct((int)(b[i]))) + if (isalpha(b[i]) || isdigit(b[i]) || ispunct(b[i])) buffer[i] = b[i]; - else if (isspace((int)(b[i]))) + else if (isspace(b[i])) buffer[i] = ' '; } @@ -344,7 +347,7 @@ static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p, // Convert the next n hex digits of s to a hex number -static unsigned int tohex(const char *s, unsigned int n) { +static unsigned int tohex(const unsigned char *s, unsigned int n) { int ret, c; ret = 0; @@ -362,7 +365,7 @@ static unsigned int tohex(const char *s, unsigned int n) { * Permissive for some invalid unicode sequences but not for those with * high bit set). Returns numbers of characters written (0-6). */ -static int wc_to_utf8str(unsigned int wc, char *str) { +static int wc_to_utf8str(unsigned int wc, unsigned char *str) { if(!(wc & ~0x7fu)) { *str = (char) wc; return 1; @@ -406,8 +409,8 @@ static int wc_to_utf8str(unsigned int wc, char *str) { } // Unescape C-style strings, destination d must hold enough space (and can be source s) -static char *unescape(char *d, const char *s) { - char *ret = d; +static unsigned char *unescape(unsigned char *d, const unsigned char *s) { + unsigned char *ret = d; int n, k; while(*s) { @@ -650,7 +653,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, // Data info int bytes_grown; uint8_t size; - char * str_ptr; + char *str_ptr; // Data union union { float f; @@ -793,7 +796,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, } // Strip start and end quotes, and unescape C string strncpy(s, argi+1, arglen-2); - unescape(s, s); + unescape((unsigned char *) s, (unsigned char *) s); if (*argi == '\'') { // Single C-style character if(*s && s[1]) avrdude_message(MSG_INFO, "%s (write): only using first character of %s\n", @@ -1463,7 +1466,7 @@ int terminal_mode(PROGRAMMER * pgm, struct avrpart * p) * find the start of the command, skipping any white space */ q = cmdbuf; - while (*q && isspace((int)*q)) + while (*q && isspace((unsigned char) *q)) q++; /* skip blank lines and comments */ From 1efbc64922486a6036cce04fedc34ef514b251c5 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Wed, 13 Jul 2022 11:38:43 +0100 Subject: [PATCH 47/57] Add terminal_setup_update_progress() library interface to term.c This enables the new quell terminal command to switch on and off progress reports to the terminal. The code for this was moved from main.c to term.c. It can be used as library call for other frontends than main.c --- src/main.c | 80 ++------------------------------------------------- src/term.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++++- src/term.h | 1 + 3 files changed, 86 insertions(+), 79 deletions(-) diff --git a/src/main.c b/src/main.c index 1d00ae67..b6fd2926 100644 --- a/src/main.c +++ b/src/main.c @@ -135,72 +135,6 @@ static void usage(void) } -static void update_progress_tty (int percent, double etime, char *hdr) -{ - static char hashes[51]; - static char *header; - static int last = 0; - int i; - - setvbuf(stderr, (char*)NULL, _IONBF, 0); - - hashes[50] = 0; - - memset (hashes, ' ', 50); - for (i=0; i>1)*2; - - setvbuf(stderr, (char*)NULL, _IONBF, 0); - - if (hdr) { - avrdude_message(MSG_INFO, "\n%s | ", hdr); - last = 0; - done = 0; - } - else { - while ((cnt > last) && (done == 0)) { - avrdude_message(MSG_INFO, "#"); - cnt -= 2; - } - } - - if ((percent == 100) && (done == 0)) { - avrdude_message(MSG_INFO, " | 100%% %0.2fs\n\n", etime); - last = 0; - done = 1; - } - else - last = (percent>>1)*2; /* Make last a multiple of 2. */ - - setvbuf(stderr, (char*)NULL, _IOLBF, 0); -} - static void list_programmers_callback(const char *name, const char *desc, const char *cfgname, int cfglineno, void *cookie) @@ -759,18 +693,8 @@ int main(int argc, char * argv []) } #endif - if (quell_progress == 0) { - if (isatty (STDERR_FILENO)) - update_progress = update_progress_tty; - else { - update_progress = update_progress_no_tty; - /* disable all buffering of stderr for compatibility with - software that captures and redirects output to a GUI - i.e. Programmers Notepad */ - setvbuf( stderr, NULL, _IONBF, 0 ); - setvbuf( stdout, NULL, _IONBF, 0 ); - } - } + if (quell_progress == 0) + terminal_setup_update_progress(); /* * Print out an identifying string so folks can tell what version diff --git a/src/term.c b/src/term.c index 8cd48b99..ec95fcec 100644 --- a/src/term.c +++ b/src/term.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #if defined(HAVE_LIBREADLINE) @@ -345,7 +346,6 @@ static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p, } - // Convert the next n hex digits of s to a hex number static unsigned int tohex(const unsigned char *s, unsigned int n) { int ret, c; @@ -1294,6 +1294,8 @@ static int cmd_quell(PROGRAMMER * pgm, struct avrpart * p, if(quell_progress > 0) update_progress = NULL; + else + terminal_setup_update_progress(); return 0; } @@ -1499,3 +1501,83 @@ int terminal_mode(PROGRAMMER * pgm, struct avrpart * p) return rc; } + + +static void update_progress_tty (int percent, double etime, char *hdr) +{ + static char hashes[51]; + static char *header; + static int last = 0; + int i; + + setvbuf(stderr, (char*)NULL, _IONBF, 0); + + hashes[50] = 0; + + memset (hashes, ' ', 50); + for (i=0; i>1)*2; + + setvbuf(stderr, (char*)NULL, _IONBF, 0); + + if (hdr) { + avrdude_message(MSG_INFO, "\n%s | ", hdr); + last = 0; + done = 0; + } + else { + while ((cnt > last) && (done == 0)) { + avrdude_message(MSG_INFO, "#"); + cnt -= 2; + } + } + + if ((percent == 100) && (done == 0)) { + avrdude_message(MSG_INFO, " | 100%% %0.2fs\n\n", etime); + last = 0; + done = 1; + } + else + last = (percent>>1)*2; /* Make last a multiple of 2. */ + + setvbuf(stderr, (char*)NULL, _IOLBF, 0); +} + +void terminal_setup_update_progress() { + if (isatty (STDERR_FILENO)) + update_progress = update_progress_tty; + else { + update_progress = update_progress_no_tty; + /* disable all buffering of stderr for compatibility with + software that captures and redirects output to a GUI + i.e. Programmers Notepad */ + setvbuf( stderr, NULL, _IONBF, 0 ); + setvbuf( stdout, NULL, _IONBF, 0 ); + } +} diff --git a/src/term.h b/src/term.h index f114d4b0..61c4916c 100644 --- a/src/term.h +++ b/src/term.h @@ -34,6 +34,7 @@ typedef enum { int terminal_mode(PROGRAMMER * pgm, struct avrpart * p); char * terminal_get_input(const char *prompt); +void terminal_setup_update_progress(); #ifdef __cplusplus } From 0b3a5781fc46e6193b26560eed8c7a1d062cb511 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Wed, 13 Jul 2022 11:48:29 +0100 Subject: [PATCH 48/57] Flush stderr and stdout with all terminal error messages Error messages are written to stderr whilst normal terminal output is stdout. When redirecting output to pipelines or files these two streams can get separated as they are buffered separately. To avoid this, term.c now provides a function terminal_message() that works just like avrdude_message() but flushes stderr and stdout before printing on stderr, and it flushes stderr afterwards. This commit replaces all avrdude_message() calls except for progress report with terminal_message() to ensure stdout and stderr streams keep together. --- src/term.c | 155 +++++++++++++++++++++++++++++------------------------ src/term.h | 1 + 2 files changed, 87 insertions(+), 69 deletions(-) diff --git a/src/term.c b/src/term.c index ec95fcec..18999b19 100644 --- a/src/term.c +++ b/src/term.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -241,7 +242,7 @@ static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p, int argc, char * argv[]) { if (argc < 2 || argc > 4) { - avrdude_message(MSG_INFO, + terminal_message(MSG_INFO, "Usage: %s \n" " %s ...\n" " %s \n" @@ -256,7 +257,7 @@ static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p, char * memtype = argv[1]; AVRMEM * mem = avr_locate_mem(p, memtype); if (mem == NULL) { - avrdude_message(MSG_INFO, "%s (dump): %s memory type not defined for part %s\n", + terminal_message(MSG_INFO, "%s (dump): %s memory type not defined for part %s\n", progname, memtype, p->desc); return -1; } @@ -269,11 +270,11 @@ static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p, if (argc >= 3 && strcmp(argv[2], "...") != 0) { addr = strtoul(argv[2], &end_ptr, 0); if (*end_ptr || (end_ptr == argv[2])) { - avrdude_message(MSG_INFO, "%s (dump): can't parse address %s\n", + terminal_message(MSG_INFO, "%s (dump): can't parse address %s\n", progname, argv[2]); return -1; } else if (addr >= maxsize) { - avrdude_message(MSG_INFO, "%s (dump): address 0x%05lx is out of range for %s memory\n", + terminal_message(MSG_INFO, "%s (dump): address 0x%05lx is out of range for %s memory\n", progname, (long) addr, mem->desc); return -1; } @@ -290,7 +291,7 @@ static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p, } else if (argc == 4) { len = strtol(argv[3], &end_ptr, 0); if (*end_ptr || (end_ptr == argv[3])) { - avrdude_message(MSG_INFO, "%s (dump): can't parse length %s\n", + terminal_message(MSG_INFO, "%s (dump): can't parse length %s\n", progname, argv[3]); return -1; } @@ -316,7 +317,7 @@ static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p, uint8_t * buf = malloc(len); if (buf == NULL) { - avrdude_message(MSG_INFO, "%s (dump): out of memory\n", progname); + terminal_message(MSG_INFO, "%s (dump): out of memory\n", progname); return -1; } @@ -324,10 +325,10 @@ static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p, for (int i = 0; i < len; i++) { int rc = pgm->read_byte(pgm, p, mem, addr + i, &buf[i]); if (rc != 0) { - avrdude_message(MSG_INFO, "%s (dump): error reading %s address 0x%05lx of part %s\n", + terminal_message(MSG_INFO, "%s (dump): error reading %s address 0x%05lx of part %s\n", progname, mem->desc, (long) addr + i, p->desc); if (rc == -1) - avrdude_message(MSG_INFO, "%*sread operation not supported on memory type %s\n", + terminal_message(MSG_INFO, "%*sread operation not supported on memory type %s\n", (int) strlen(progname)+9, "", mem->desc); return -1; } @@ -566,7 +567,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, int argc, char * argv[]) { if (argc < 4) { - avrdude_message(MSG_INFO, + terminal_message(MSG_INFO, "Usage: write [,] {[,]} \n" " write [,] {[,]} ...\n" "\n" @@ -604,7 +605,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, char * memtype = argv[1]; // Memory name string AVRMEM * mem = avr_locate_mem(p, memtype); if (mem == NULL) { - avrdude_message(MSG_INFO, "%s (write): %s memory type not defined for part %s\n", + terminal_message(MSG_INFO, "%s (write): %s memory type not defined for part %s\n", progname, memtype, p->desc); return -1; } @@ -613,13 +614,13 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, char * end_ptr; int addr = strtoul(argv[2], &end_ptr, 0); if (*end_ptr || (end_ptr == argv[2])) { - avrdude_message(MSG_INFO, "%s (write): can't parse address %s\n", + terminal_message(MSG_INFO, "%s (write): can't parse address %s\n", progname, argv[2]); return -1; } if (addr > maxsize) { - avrdude_message(MSG_INFO, "%s (write): address 0x%05lx is out of range for %s memory\n", + terminal_message(MSG_INFO, "%s (write): address 0x%05lx is out of range for %s memory\n", progname, (long) addr, memtype); return -1; } @@ -627,7 +628,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, // Allocate a buffer guaranteed to be large enough uint8_t * buf = calloc(mem->size + 0x10 + maxstrlen(argc-3, argv+3), sizeof(uint8_t)); if (buf == NULL) { - avrdude_message(MSG_INFO, "%s (write): out of memory\n", progname); + terminal_message(MSG_INFO, "%s (write): out of memory\n", progname); return -1; } @@ -637,7 +638,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, start_offset = 4; len = strtoul(argv[3], &end_ptr, 0); if (*end_ptr || (end_ptr == argv[3])) { - avrdude_message(MSG_INFO, "%s (write ...): can't parse length %s\n", + terminal_message(MSG_INFO, "%s (write ...): can't parse length %s\n", progname, argv[3]); free(buf); return -1; @@ -670,7 +671,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, }; if(sizeof(long long) != sizeof(int64_t) || (data.a[0]^data.a[7]) != 1) - avrdude_message(MSG_INFO, "%s (write): assumption on data types not met? " + terminal_message(MSG_INFO, "%s (write): assumption on data types not met? " "Check source and recompile\n", progname); bool is_big_endian = data.a[7]; @@ -765,7 +766,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, } if(is_outside_int64_t || is_out_of_range) - avrdude_message(MSG_INFO, "%s (write): %s out of int%d_t 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); } @@ -790,7 +791,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, if ((*argi == '\'' && argi[arglen-1] == '\'') || (*argi == '\"' && argi[arglen-1] == '\"')) { char *s = calloc(arglen-1, 1); if (s == NULL) { - avrdude_message(MSG_INFO, "%s (write str): out of memory\n", progname); + terminal_message(MSG_INFO, "%s (write str): out of memory\n", progname); free(buf); return -1; } @@ -799,7 +800,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, unescape((unsigned char *) s, (unsigned char *) s); if (*argi == '\'') { // Single C-style character if(*s && s[1]) - avrdude_message(MSG_INFO, "%s (write): only using first character of %s\n", + terminal_message(MSG_INFO, "%s (write): only using first character of %s\n", progname, argi); data.ll = *s; data.size = 1; @@ -811,7 +812,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, } if(!data.size && !data.str_ptr) { - avrdude_message(MSG_INFO, "%s (write): can't parse data %s\n", + terminal_message(MSG_INFO, "%s (write): can't parse data %s\n", progname, argi); free(buf); return -1; @@ -851,7 +852,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, data.bytes_grown = 0; if ((addr + len + data.bytes_grown) > maxsize) { - avrdude_message(MSG_INFO, "%s (write): selected address and # bytes exceed " + terminal_message(MSG_INFO, "%s (write): selected address and # bytes exceed " "range for %s memory\n", progname, memtype); free(buf); return -1; @@ -860,11 +861,11 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, if(data.str_ptr) free(data.str_ptr); - avrdude_message(MSG_NOTICE, "Info: writing %d bytes starting from address 0x%02lx", + terminal_message(MSG_NOTICE, "Info: writing %d bytes starting from address 0x%02lx", len + data.bytes_grown, (long) addr); if (write_mode == WRITE_MODE_FILL) - avrdude_message(MSG_NOTICE, "; remaining space filled with %s", argv[argc - 2]); - avrdude_message(MSG_NOTICE, "\n"); + terminal_message(MSG_NOTICE, "; remaining space filled with %s", argv[argc - 2]); + terminal_message(MSG_NOTICE, "\n"); pgm->err_led(pgm, OFF); bool werror = false; @@ -872,10 +873,10 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, for (i = 0; i < (len + data.bytes_grown); i++) { int rc = avr_write_byte(pgm, p, mem, addr+i, buf[i]); if (rc) { - avrdude_message(MSG_INFO, "%s (write): error writing 0x%02x at 0x%05lx, rc=%d\n", + terminal_message(MSG_INFO, "%s (write): error writing 0x%02x at 0x%05lx, rc=%d\n", progname, buf[i], (long) addr+i, (int) rc); if (rc == -1) - avrdude_message(MSG_INFO, "%*swrite operation not supported on memory type %s\n", + terminal_message(MSG_INFO, "%*swrite operation not supported on memory type %s\n", (int) strlen(progname)+10, "", mem->desc); werror = true; } @@ -883,7 +884,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, uint8_t b; rc = pgm->read_byte(pgm, p, mem, addr+i, &b); if (b != buf[i]) { - avrdude_message(MSG_INFO, "%s (write): error writing 0x%02x at 0x%05lx cell=0x%02x\n", + terminal_message(MSG_INFO, "%s (write): error writing 0x%02x at 0x%05lx cell=0x%02x\n", progname, buf[i], (long) addr+i, b); werror = true; } @@ -911,20 +912,20 @@ static int cmd_send(PROGRAMMER * pgm, struct avrpart * p, int len; if (pgm->cmd == NULL) { - avrdude_message(MSG_INFO, "%s (send): the %s programmer does not support direct ISP commands\n", + terminal_message(MSG_INFO, "%s (send): the %s programmer does not support direct ISP commands\n", progname, pgm->type); return -1; } if (spi_mode && (pgm->spi == NULL)) { - avrdude_message(MSG_INFO, "%s (send): the %s programmer does not support direct SPI transfers\n", + terminal_message(MSG_INFO, "%s (send): the %s programmer does not support direct SPI transfers\n", progname, pgm->type); return -1; } if ((argc > 5) || ((argc < 5) && (!spi_mode))) { - avrdude_message(MSG_INFO, spi_mode? + terminal_message(MSG_INFO, spi_mode? "Usage: send [ [ []]]\n": "Usage: send \n"); return -1; @@ -937,7 +938,7 @@ static int cmd_send(PROGRAMMER * pgm, struct avrpart * p, for (i=1; ichip_erase(pgm, p); return 0; } @@ -993,13 +994,13 @@ static int cmd_sig(PROGRAMMER * pgm, struct avrpart * p, rc = avr_signature(pgm, p); if (rc != 0) { - avrdude_message(MSG_INFO, "%s (sig): error reading signature data, rc=%d\n", + terminal_message(MSG_INFO, "%s (sig): error reading signature data, rc=%d\n", progname, rc); } m = avr_locate_mem(p, "signature"); if (m == NULL) { - avrdude_message(MSG_INFO, "%s (sig): signature data not defined for device %s\n", + terminal_message(MSG_INFO, "%s (sig): signature data not defined for device %s\n", progname, p->desc); } else { @@ -1028,7 +1029,7 @@ static int cmd_parms(PROGRAMMER * pgm, struct avrpart * p, int argc, char * argv[]) { if (pgm->print_parms == NULL) { - avrdude_message(MSG_INFO, "%s (parms): the %s programmer does not support " + terminal_message(MSG_INFO, "%s (parms): the %s programmer does not support " "adjustable parameters\n", progname, pgm->type); return -1; } @@ -1046,22 +1047,22 @@ static int cmd_vtarg(PROGRAMMER * pgm, struct avrpart * p, char *endp; if (argc != 2) { - avrdude_message(MSG_INFO, "Usage: vtarg \n"); + terminal_message(MSG_INFO, "Usage: vtarg \n"); return -1; } v = strtod(argv[1], &endp); if (endp == argv[1]) { - avrdude_message(MSG_INFO, "%s (vtarg): can't parse voltage %s\n", + terminal_message(MSG_INFO, "%s (vtarg): can't parse voltage %s\n", progname, argv[1]); return -1; } if (pgm->set_vtarget == NULL) { - avrdude_message(MSG_INFO, "%s (vtarg): the %s programmer cannot set V[target]\n", + terminal_message(MSG_INFO, "%s (vtarg): the %s programmer cannot set V[target]\n", progname, pgm->type); return -2; } if ((rc = pgm->set_vtarget(pgm, v)) != 0) { - avrdude_message(MSG_INFO, "%s (vtarg): failed to set V[target] (rc = %d)\n", + terminal_message(MSG_INFO, "%s (vtarg): failed to set V[target] (rc = %d)\n", progname, rc); return -3; } @@ -1077,7 +1078,7 @@ static int cmd_fosc(PROGRAMMER * pgm, struct avrpart * p, char *endp; if (argc != 2) { - avrdude_message(MSG_INFO, "Usage: fosc [M|k] | off\n"); + terminal_message(MSG_INFO, "Usage: fosc [M|k] | off\n"); return -1; } v = strtod(argv[1], &endp); @@ -1085,7 +1086,7 @@ static int cmd_fosc(PROGRAMMER * pgm, struct avrpart * p, if (strcmp(argv[1], "off") == 0) v = 0.0; else { - avrdude_message(MSG_INFO, "%s (fosc): can't parse frequency %s\n", + terminal_message(MSG_INFO, "%s (fosc): can't parse frequency %s\n", progname, argv[1]); return -1; } @@ -1095,12 +1096,12 @@ static int cmd_fosc(PROGRAMMER * pgm, struct avrpart * p, else if (*endp == 'k' || *endp == 'K') v *= 1e3; if (pgm->set_fosc == NULL) { - avrdude_message(MSG_INFO, "%s (fosc): the %s programmer cannot set oscillator frequency\n", + terminal_message(MSG_INFO, "%s (fosc): the %s programmer cannot set oscillator frequency\n", progname, pgm->type); return -2; } if ((rc = pgm->set_fosc(pgm, v)) != 0) { - avrdude_message(MSG_INFO, "%s (fosc): failed to set oscillator frequency (rc = %d)\n", + terminal_message(MSG_INFO, "%s (fosc): failed to set oscillator frequency (rc = %d)\n", progname, rc); return -3; } @@ -1116,23 +1117,23 @@ static int cmd_sck(PROGRAMMER * pgm, struct avrpart * p, char *endp; if (argc != 2) { - avrdude_message(MSG_INFO, "Usage: sck \n"); + terminal_message(MSG_INFO, "Usage: sck \n"); return -1; } v = strtod(argv[1], &endp); if (endp == argv[1]) { - avrdude_message(MSG_INFO, "%s (sck): can't parse period %s\n", + terminal_message(MSG_INFO, "%s (sck): can't parse period %s\n", progname, argv[1]); return -1; } v *= 1e-6; /* Convert from microseconds to seconds. */ if (pgm->set_sck_period == NULL) { - avrdude_message(MSG_INFO, "%s (sck): the %s programmer cannot set SCK period\n", + terminal_message(MSG_INFO, "%s (sck): the %s programmer cannot set SCK period\n", progname, pgm->type); return -2; } if ((rc = pgm->set_sck_period(pgm, v)) != 0) { - avrdude_message(MSG_INFO, "%s (sck): failed to set SCK period (rc = %d)\n", + terminal_message(MSG_INFO, "%s (sck): failed to set SCK period (rc = %d)\n", progname, rc); return -3; } @@ -1149,38 +1150,38 @@ static int cmd_varef(PROGRAMMER * pgm, struct avrpart * p, char *endp; if (argc != 2 && argc != 3) { - avrdude_message(MSG_INFO, "Usage: varef [channel] \n"); + terminal_message(MSG_INFO, "Usage: varef [channel] \n"); return -1; } if (argc == 2) { chan = 0; v = strtod(argv[1], &endp); if (endp == argv[1]) { - avrdude_message(MSG_INFO, "%s (varef): can't parse voltage %s\n", + terminal_message(MSG_INFO, "%s (varef): can't parse voltage %s\n", progname, argv[1]); return -1; } } else { chan = strtoul(argv[1], &endp, 10); if (endp == argv[1]) { - avrdude_message(MSG_INFO, "%s (varef): can't parse channel %s\n", + terminal_message(MSG_INFO, "%s (varef): can't parse channel %s\n", progname, argv[1]); return -1; } v = strtod(argv[2], &endp); if (endp == argv[2]) { - avrdude_message(MSG_INFO, "%s (varef): can't parse voltage %s\n", + terminal_message(MSG_INFO, "%s (varef): can't parse voltage %s\n", progname, argv[2]); return -1; } } if (pgm->set_varef == NULL) { - avrdude_message(MSG_INFO, "%s (varef): the %s programmer cannot set V[aref]\n", + terminal_message(MSG_INFO, "%s (varef): the %s programmer cannot set V[aref]\n", progname, pgm->type); return -2; } if ((rc = pgm->set_varef(pgm, chan, v)) != 0) { - avrdude_message(MSG_INFO, "%s (varef): failed to set V[aref] (rc = %d)\n", + terminal_message(MSG_INFO, "%s (varef): failed to set V[aref] (rc = %d)\n", progname, rc); return -3; } @@ -1214,7 +1215,7 @@ static int cmd_spi(PROGRAMMER * pgm, struct avrpart * p, spi_mode = 1; return 0; } - avrdude_message(MSG_INFO, "%s: spi command unavailable for this programmer type\n", + terminal_message(MSG_INFO, "%s: spi command unavailable for this programmer type\n", progname); return -1; } @@ -1228,7 +1229,7 @@ static int cmd_pgm(PROGRAMMER * pgm, struct avrpart * p, pgm->initialize(pgm, p); return 0; } - avrdude_message(MSG_INFO, "%s: pgm command unavailable for this programmer type\n", + terminal_message(MSG_INFO, "%s: pgm command unavailable for this programmer type\n", progname); return -1; } @@ -1240,26 +1241,26 @@ static int cmd_verbose(PROGRAMMER * pgm, struct avrpart * p, char *endp; if (argc != 1 && argc != 2) { - avrdude_message(MSG_INFO, "Usage: verbose []\n"); + terminal_message(MSG_INFO, "Usage: verbose []\n"); return -1; } if (argc == 1) { - avrdude_message(MSG_INFO, "Verbosity level: %d\n", verbose); + terminal_message(MSG_INFO, "Verbosity level: %d\n", verbose); return 0; } nverb = strtol(argv[1], &endp, 0); if (endp == argv[1] || *endp) { - avrdude_message(MSG_INFO, "%s (verbose): can't parse verbosity level %s\n", + terminal_message(MSG_INFO, "%s (verbose): can't parse verbosity level %s\n", progname, argv[1]); return -1; } if (nverb < 0) { - avrdude_message(MSG_INFO, "%s: verbosity level must not be negative: %d\n", + terminal_message(MSG_INFO, "%s: verbosity level must not be negative: %d\n", progname, nverb); return -1; } verbose = nverb; - avrdude_message(MSG_INFO, "New verbosity level: %d\n", verbose); + terminal_message(MSG_INFO, "New verbosity level: %d\n", verbose); return 0; } @@ -1271,26 +1272,26 @@ static int cmd_quell(PROGRAMMER * pgm, struct avrpart * p, char *endp; if (argc != 1 && argc != 2) { - avrdude_message(MSG_INFO, "Usage: quell []\n"); + terminal_message(MSG_INFO, "Usage: quell []\n"); return -1; } if (argc == 1) { - avrdude_message(MSG_INFO, "Quell level: %d\n", quell_progress); + terminal_message(MSG_INFO, "Quell level: %d\n", quell_progress); return 0; } nquell = strtol(argv[1], &endp, 0); if (endp == argv[1] || *endp) { - avrdude_message(MSG_INFO, "%s (quell): can't parse quell level %s\n", + terminal_message(MSG_INFO, "%s (quell): can't parse quell level %s\n", progname, argv[1]); return -1; } if (nquell < 0) { - avrdude_message(MSG_INFO, "%s: quell level must not be negative: %d\n", + terminal_message(MSG_INFO, "%s: quell level must not be negative: %d\n", progname, nquell); return -1; } quell_progress = nquell; - avrdude_message(MSG_INFO, "New quell level: %d\n", quell_progress); + terminal_message(MSG_INFO, "New quell level: %d\n", quell_progress); if(quell_progress > 0) update_progress = NULL; @@ -1413,7 +1414,7 @@ static int do_cmd(PROGRAMMER * pgm, struct avrpart * p, } else if (strncasecmp(argv[0], cmd[i].name, len)==0) { if (hold != -1) { - avrdude_message(MSG_INFO, "%s (cmd): command %s is ambiguous\n", + terminal_message(MSG_INFO, "%s (cmd): command %s is ambiguous\n", progname, argv[0]); return -1; } @@ -1424,7 +1425,7 @@ static int do_cmd(PROGRAMMER * pgm, struct avrpart * p, if (hold != -1) return cmd[hold].func(pgm, p, argc, argv); - avrdude_message(MSG_INFO, "%s (cmd): invalid command %s\n", + terminal_message(MSG_INFO, "%s (cmd): invalid command %s\n", progname, argv[0]); return -1; @@ -1503,6 +1504,22 @@ int terminal_mode(PROGRAMMER * pgm, struct avrpart * p) } +int terminal_message(const int msglvl, const char *format, ...) { + 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); + } + fflush(stderr); + + return rc; +} + + static void update_progress_tty (int percent, double etime, char *hdr) { static char hashes[51]; diff --git a/src/term.h b/src/term.h index 61c4916c..a89927ea 100644 --- a/src/term.h +++ b/src/term.h @@ -35,6 +35,7 @@ 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 } From b02cce38d76346a4dcef69717fbe77e530bea261 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Wed, 13 Jul 2022 12:25:09 +0100 Subject: [PATCH 49/57] Added long double data type for terminal write --- src/term.c | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/src/term.c b/src/term.c index 18999b19..96abbf7c 100644 --- a/src/term.c +++ b/src/term.c @@ -626,7 +626,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, } // Allocate a buffer guaranteed to be large enough - uint8_t * buf = calloc(mem->size + 0x10 + maxstrlen(argc-3, argv+3), sizeof(uint8_t)); + uint8_t * buf = calloc(mem->size + sizeof(long double) + 8 + maxstrlen(argc-3, argv+3)+1, sizeof(uint8_t)); if (buf == NULL) { terminal_message(MSG_INFO, "%s (write): out of memory\n", progname); return -1; @@ -659,9 +659,10 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, union { float f; double d; + long double ld; int64_t ll; uint64_t ull; - uint8_t a[8]; + uint8_t a[sizeof(long double) > 8? sizeof(long double): 8]; }; } data = { .bytes_grown = 0, @@ -773,7 +774,13 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, } } - if(!data.size) { // Try double now that input was rejected as integer + if(!data.size) { // Try long double now that input was rejected as integer + data.ld = strtold(argi, &end_ptr); + if (end_ptr != argi && toupper(*end_ptr) == 'L' && end_ptr[1] == 0) + data.size = sizeof(data.ld); + } + + if(!data.size) { // Try double data.d = strtod(argi, &end_ptr); // Do not accept valid mantissa-only doubles that are integer rejects (eg, 078 or ULL overflows) if (end_ptr != argi && *end_ptr == 0) @@ -826,20 +833,10 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, if(data.str_ptr) { for(size_t j = 0; j < strlen(data.str_ptr); j++) buf[i - start_offset + data.bytes_grown++] = (uint8_t)data.str_ptr[j]; - } else { - buf[i - start_offset + data.bytes_grown] = data.a[0]; - if (llabs(data.ll) > 0x000000FF || data.size >= 2) - buf[i - start_offset + ++data.bytes_grown] = data.a[1]; - if (llabs(data.ll) > 0x0000FFFF || data.size >= 4) { - buf[i - start_offset + ++data.bytes_grown] = data.a[2]; - buf[i - start_offset + ++data.bytes_grown] = data.a[3]; - } - if (llabs(data.ll) > 0xFFFFFFFF || data.size == 8) { - buf[i - start_offset + ++data.bytes_grown] = data.a[4]; - buf[i - start_offset + ++data.bytes_grown] = data.a[5]; - buf[i - start_offset + ++data.bytes_grown] = data.a[6]; - buf[i - start_offset + ++data.bytes_grown] = data.a[7]; - } + } else if(data.size > 0) { + for(int k=0; k Date: Wed, 13 Jul 2022 12:35:49 +0100 Subject: [PATCH 50/57] Change terminal write usage message to accommodate long double --- src/term.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/term.c b/src/term.c index 96abbf7c..ea34d5ee 100644 --- a/src/term.c +++ b/src/term.c @@ -574,11 +574,12 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, "Ellipsis ... writes bytes padded by repeating the last item.\n" "\n" " can be hexadecimal, octal or decimal integers, double, float or\n" - "C-style strings and chars. For numbers, an optional case-insensitive suffix\n" - "specifies the data size: HH: 8 bit, H/S: 16 bit, L: 32 bit, LL: 64 bit, F:\n" - "32-bit float. Hexadecimal floating point notation is supported. The\n" - "ambiguous trailing F in 0x1.8F makes the number be interpreted as double;\n" - "use a zero exponent as in 0x1.8p0F to denote a hexadecimal float.\n" + "C-style strings and chars. For integers, an optional case-insensitive suffix\n" + "specifies the data size: HH: 8 bit, H/S: 16 bit, L: 32 bit or LL: 64 bit.\n" + "Floating point types follow the C convention (add F for 32-bit float or L for\n" + "long double). Hexadecimal floating point notation is supported. The ambiguous\n" + "trailing F in 0x1.8F makes the number be interpreted as double; use a zero\n" + "exponent as in 0x1.8p0F to denote a hexadecimal float.\n" "\n" "An optional U suffix makes a number unsigned. Ordinary 0x hex numbers are\n" "always treated as unsigned. +0x or -0x hex numbers are treated as signed\n" From dde35018eb7a3bf26af3f64d5549cb8ceb66583d Mon Sep 17 00:00:00 2001 From: MCUdude Date: Wed, 13 Jul 2022 23:49:14 +0200 Subject: [PATCH 51/57] Exit if programmer can't send HV pulse to target --- src/jtag3.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/jtag3.c b/src/jtag3.c index becfd8a1..5ce6769c 100644 --- a/src/jtag3.c +++ b/src/jtag3.c @@ -1266,9 +1266,11 @@ static int jtag3_initialize(PROGRAMMER * pgm, AVRPART * p) parm[0] = PARM3_UPDI_HV_SIMPLE_PULSE; break; } - if (parm[0] == PARM3_UPDI_HV_NONE) + if (parm[0] == PARM3_UPDI_HV_NONE) { avrdude_message(MSG_INFO, "%s: %s does not support sending HV pulse to target %s\n", progname, pgm->desc, p->desc); + return -1; + } } if (jtag3_setparm(pgm, SCOPE_AVR, 3, PARM3_OPT_12V_UPDI_ENABLE, parm, 1) < 0) return -1; From 5721908e63a16ce44b326738c91ec4c46078b47e Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Thu, 14 Jul 2022 17:13:13 +0100 Subject: [PATCH 52/57] Revert to double/float only in terminal write and clarify usage --- src/term.c | 52 ++++++++++++++++++++++++---------------------------- 1 file changed, 24 insertions(+), 28 deletions(-) diff --git a/src/term.c b/src/term.c index ea34d5ee..52906f29 100644 --- a/src/term.c +++ b/src/term.c @@ -573,15 +573,16 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, "\n" "Ellipsis ... writes bytes padded by repeating the last item.\n" "\n" - " can be hexadecimal, octal or decimal integers, double, float or\n" - "C-style strings and chars. For integers, an optional case-insensitive suffix\n" - "specifies the data size: HH: 8 bit, H/S: 16 bit, L: 32 bit or LL: 64 bit.\n" - "Floating point types follow the C convention (add F for 32-bit float or L for\n" - "long double). Hexadecimal floating point notation is supported. The ambiguous\n" - "trailing F in 0x1.8F makes the number be interpreted as double; use a zero\n" - "exponent as in 0x1.8p0F to denote a hexadecimal float.\n" + " can be hexadecimal, octal or decimal integers, floating point numbers\n" + "or C-style strings and characters. For integers, an optional case-insensitive\n" + "suffix specifies the data size: HH 8 bit, H/S 16 bit, L 32 bit, LL 64 bit.\n" + "Suffix D indicates a 64-bit double, F a 32-bit float, whilst a floating point\n" + "number without suffix defaults to 32-bit float. Hexadecimal floating point\n" + "notation is supported. An ambiguous trailing suffix, eg, 0x1.8D, is read as\n" + "no-suffix float where D is part of the mantissa; use a zero exponent 0x1.8p0D\n" + "to clarify.\n" "\n" - "An optional U suffix makes a number unsigned. Ordinary 0x hex numbers are\n" + "An optional U suffix makes integers unsigned. Ordinary 0x hex integers are\n" "always treated as unsigned. +0x or -0x hex numbers are treated as signed\n" "unless they have a U suffix. Unsigned integers cannot be larger than 2^64-1.\n" "If n is an unsigned integer then -n is also a valid unsigned integer as in C.\n" @@ -589,12 +590,12 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, "smaller range when a suffix specifies a smaller type. Out of range signed\n" "numbers trigger a warning.\n" "\n" - "Ordinary 0x hex numbers with n hex digits (counting leading zeros) use\n" - "the smallest size of 1, 2, 4 and 8 bytes that can accommodate any n-digit hex\n" - "number. If a suffix specifies a size explicitly the corresponding number of\n" - "least significant bytes are written. Otherwise, signed and unsigned integers\n" - "alike occupy the smallest of 1, 2, 4, or 8 bytes needed to accommodate them\n" - "in their respective representation.\n" + "Ordinary 0x hex integers with n hex digits (counting leading zeros) use the\n" + "smallest size of 1, 2, 4 and 8 bytes that can accommodate any n-digit hex\n" + "integer. If an integer suffix specifies a size explicitly the corresponding\n" + "number of least significant bytes are written. Otherwise, signed and unsigned\n" + "integers alike occupy the smallest of 1, 2, 4, or 8 bytes needed to\n" + "accommodate them in their respective representation.\n" ); return -1; } @@ -627,7 +628,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, } // Allocate a buffer guaranteed to be large enough - uint8_t * buf = calloc(mem->size + sizeof(long double) + 8 + maxstrlen(argc-3, argv+3)+1, sizeof(uint8_t)); + uint8_t * buf = calloc(mem->size + 8 + maxstrlen(argc-3, argv+3)+1, sizeof(uint8_t)); if (buf == NULL) { terminal_message(MSG_INFO, "%s (write): out of memory\n", progname); return -1; @@ -660,10 +661,9 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, union { float f; double d; - long double ld; int64_t ll; uint64_t ull; - uint8_t a[sizeof(long double) > 8? sizeof(long double): 8]; + uint8_t a[8]; }; } data = { .bytes_grown = 0, @@ -775,24 +775,20 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, } } - if(!data.size) { // Try long double now that input was rejected as integer - data.ld = strtold(argi, &end_ptr); - if (end_ptr != argi && toupper(*end_ptr) == 'L' && end_ptr[1] == 0) - data.size = sizeof(data.ld); - } - - if(!data.size) { // Try double + if(!data.size) { // Try double now that input was rejected as integer data.d = strtod(argi, &end_ptr); - // Do not accept valid mantissa-only doubles that are integer rejects (eg, 078 or ULL overflows) - if (end_ptr != argi && *end_ptr == 0) - if (!is_mantissa_only(argi)) - data.size = 8; + if (end_ptr != argi && toupper(*end_ptr) == 'D' && end_ptr[1] == 0) + data.size = 8; } if(!data.size) { // Try float 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 (!is_mantissa_only(argi)) + data.size = 4; } if(!data.size) { // Try C-style string or single character From 14b27726d4fa05d7d18dcc8711d50f63e67571f3 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Thu, 14 Jul 2022 17:16:30 +0100 Subject: [PATCH 53/57] Protect terminal dump from vagaries of C libray implementation of isalpha() etc Some C libraries assign true to isalpha(0xff), isdigit(0xff) or ispunct(0xff), which means that the Operating System terminal sees a character 0xff which it may not have a useful display character for. This commit only outputs printable ASCII characters for an AVRDUDE terminal dump reducing the risk of the OS terminal not being able to print the character properly. --- src/term.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/term.c b/src/term.c index 52906f29..7fe6246c 100644 --- a/src/term.c +++ b/src/term.c @@ -198,13 +198,9 @@ static int chardump_line(char * buffer, unsigned char * p, int n, int pad) n = n < 1? 1: n > sizeof b? sizeof b: n; memcpy(b, p, n); - for (int i = 0; i < n; i++) { - buffer[i] = '.'; - if (isalpha(b[i]) || isdigit(b[i]) || ispunct(b[i])) - buffer[i] = b[i]; - else if (isspace(b[i])) - buffer[i] = ' '; - } + for (int i = 0; i < n; i++) + buffer[i] = isascii(b[i]) && isspace(b[i])? ' ': + isascii(b[i]) && isgraph(b[i])? b[i]: '.'; for (i = n; i < pad; i++) buffer[i] = ' '; From 7ceb163cbabda069462fcd4e7770ece0f5d09494 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Thu, 14 Jul 2022 18:31:44 +0100 Subject: [PATCH 54/57] Echo terminal command line on Apple --- src/term.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/term.c b/src/term.c index 7fe6246c..e779f84a 100644 --- a/src/term.c +++ b/src/term.c @@ -1473,7 +1473,7 @@ int terminal_mode(PROGRAMMER * pgm, struct avrpart * p) return argc; } -#if !defined(HAVE_LIBREADLINE) || defined(WIN32) +#if !defined(HAVE_LIBREADLINE) || defined(WIN32) || defined(__APPLE__) fprintf(stdout, ">>> "); for (int i=0; i Date: Fri, 15 Jul 2022 18:50:20 +0100 Subject: [PATCH 55/57] Fix terminal line parsing for strings (to some extent) --- src/term.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/term.c b/src/term.c index e779f84a..f02f95c5 100644 --- a/src/term.c +++ b/src/term.c @@ -136,9 +136,12 @@ static int nexttok(char * buf, char ** tok, char ** next) n = q; uint8_t quotes = 0; while (*n && (!isspace(*n) || quotes)) { - if (*n == '\"') + // poor man's quote and escape processing + if (*n == '"' || *n == '\'') quotes++; - else if (isspace(*n) && *(n-1) == '\"') + else if(*n == '\\' && n[1]) + n++; + else if (isspace(*n) && (n > q+1) && (n[-1] == '"' || n[-1] == '\'')) break; n++; } @@ -787,7 +790,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, data.size = 4; } - if(!data.size) { // Try C-style string or single character + if(!data.size && arglen > 1) { // Try C-style string or single character if ((*argi == '\'' && argi[arglen-1] == '\'') || (*argi == '\"' && argi[arglen-1] == '\"')) { char *s = calloc(arglen-1, 1); if (s == NULL) { From d05ddd188d10aa43398c6f33d9e6515c00b7cd2c Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Sat, 16 Jul 2022 11:06:18 +0100 Subject: [PATCH 56/57] Fix usbtiny read/verify for parts with more than 64 kB flash Usbtiny has a protocol or firmware problem that prevents it from reading flash above 64 kB in page mode (used by -U flash:r:... and -U flash:v:...). This commit fixes that problem by falling back on byte access for flash paged reads above 64k. It also issues the correct load extended address command for parts with more than 128 kB flash thus extending support to ATmega2560 et al. --- src/usbtiny.c | 38 +++++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/src/usbtiny.c b/src/usbtiny.c index 4bbaca7c..75c88be6 100644 --- a/src/usbtiny.c +++ b/src/usbtiny.c @@ -657,15 +657,39 @@ static int usbtiny_paged_load (PROGRAMMER * pgm, AVRPART * p, AVRMEM* m, unsigned int addr, unsigned int n_bytes) { unsigned int maxaddr = addr + n_bytes; - int chunk; - int function; - + int chunk, function; + OPCODE *lext, *readop; + unsigned char cmd[8]; // First determine what we're doing - if (strcmp( m->desc, "flash" ) == 0) { - function = USBTINY_FLASH_READ; - } else { - function = USBTINY_EEPROM_READ; + function = strcmp(m->desc, "eeprom")==0? + USBTINY_EEPROM_READ: USBTINY_FLASH_READ; + + // paged_load() only called for pages, so OK to set ext addr once at start + if((lext = m->op[AVR_OP_LOAD_EXT_ADDR])) { + memset(cmd, 0, sizeof(cmd)); + avr_set_bits(lext, cmd); + avr_set_addr(lext, cmd, addr/2); + if(pgm->cmd(pgm, cmd, cmd+4) < 0) + return -1; + } + + // Byte acces as work around to correctly read flash above 64 kiB + if(function == USBTINY_FLASH_READ && addr >= 0x10000) { + for(unsigned int i=0; iop[addr&1? AVR_OP_READ_HI: AVR_OP_READ_LO])) + return -1; + + memset(cmd, 0, sizeof(cmd)); + avr_set_bits(readop, cmd); + avr_set_addr(readop, cmd, addr/2); + if(pgm->cmd(pgm, cmd, cmd+4) < 0) + return -1; + m->buf[addr] = 0; + avr_get_output(readop, cmd+4, m->buf + addr); + } + + return n_bytes; } for (; addr < maxaddr; addr += chunk) { From a5552f64cf0bea2a4f72e3a0dc90672d1bc2a18a Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Mon, 18 Jul 2022 14:38:37 +0100 Subject: [PATCH 57/57] Update NEWS --- NEWS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/NEWS b/NEWS index 7bea2bcb..84852dbf 100644 --- a/NEWS +++ b/NEWS @@ -38,6 +38,12 @@ Changes since version 7.0: - Fix ft245r paged read for ATmega2560 et al #1018 - Add option -A that supresses trailing 0xff optimisation and automatically do so for -c arduino #936 + - Fix linuxspi default port #933 + - Add support for high-voltage UPDI im jtag3.c #1015 + - Fix terminal write edge cases; + add one read mode; + add quell command #1025 + - Fix usbtiny read for parts with more than 64 kB flash #1029 * Internals: