From 6e4c0052cf6c33d457b57e75e4ada502db32cb10 Mon Sep 17 00:00:00 2001 From: MCUdude Date: Sun, 1 Oct 2023 23:39:45 +0200 Subject: [PATCH 01/19] Initial support for "1200bps touch" functionality This makes it possible to upload to boards like the Arduino Leonardo and Arduino Nano Every wwithout using an external tool to enter bootloader mode --- src/libavrdude.h | 1 + src/main.c | 10 +++++++++- src/serialadapter.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/src/libavrdude.h b/src/libavrdude.h index 0f9d59380..e932b9593 100644 --- a/src/libavrdude.h +++ b/src/libavrdude.h @@ -1252,6 +1252,7 @@ extern "C" { int setport_from_serialadapter(char **portp, const SERIALADAPTER *ser, const char *sernum); int setport_from_vid_pid(char **portp, int vid, int pid, const char *sernum); int list_available_serialports(LISTID programmers); +int touch_serialport(char **portp, int baudrate); int str_starts(const char *str, const char *starts); int str_eq(const char *str1, const char *str2); diff --git a/src/main.c b/src/main.c index 5b5eb6995..2dec03362 100644 --- a/src/main.c +++ b/src/main.c @@ -526,6 +526,7 @@ int main(int argc, char * argv []) char * e; /* for strtod() error checking */ const char *errstr; /* for str_int() error checking */ int baudrate; /* override default programmer baud rate */ + int touch_baudrate; /* baudrate to use when "touching" a serial port */ double bitclock; /* Specify programmer bit clock (JTAG ICE) */ int ispdelay; /* Specify the delay for ISP clock */ int init_ok; /* Device initialization worked well */ @@ -635,7 +636,7 @@ int main(int argc, char * argv []) /* * process command line arguments */ - while ((ch = getopt(argc,argv,"?Ab:B:c:C:DeE:Fi:l:np:OP:qstT:U:uvVx:yY:")) != -1) { + while ((ch = getopt(argc,argv,"?Ab:B:c:C:DeE:Fi:l:np:OP:qr:stT:U:uvVx:yY:")) != -1) { switch (ch) { case 'b': /* override default programmer baud rate */ @@ -766,6 +767,10 @@ int main(int argc, char * argv []) quell_progress++ ; break; + case 'r' : + touch_baudrate = str_int(optarg, STR_INT32, &errstr); + break; + case 't': /* enter terminal mode */ ladd(updates, cmd_update("interactive terminal")); break; @@ -1231,6 +1236,9 @@ int main(int argc, char * argv []) free(port_tok[i]); } + if(touch_baudrate) + touch_serialport(&port, touch_baudrate); + /* * open the programmer */ diff --git a/src/serialadapter.c b/src/serialadapter.c index b57f679ec..4cd6b3ad2 100644 --- a/src/serialadapter.c +++ b/src/serialadapter.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "avrdude.h" #include "libavrdude.h" @@ -302,6 +303,48 @@ int setport_from_vid_pid(char **portp, int vid, int pid, const char *sernum) { return rv; } +int touch_serialport(char **portp, int baudrate) { + int n1, n2; + SERPORT *sp1, *sp2, **diff; + sp1 = get_libserialport_data(&n1); + if(!sp1 || n1 <= 0) + return -1; + + pmsg_info("touching serial port %s at %d baud\n", *portp, baudrate); + struct sp_port *prt; + struct sp_port_config *cfg; + sp_get_port_by_name(*portp, &prt); + sp_open(prt, SP_MODE_READ); + sp_set_baudrate(prt, baudrate); + sp_set_bits(prt, 8); + sp_set_parity(prt, SP_PARITY_NONE); + sp_set_stopbits(prt, 1); + sp_set_flowcontrol(prt, SP_FLOWCONTROL_NONE); + sp_new_config(&cfg); + sp_get_config(prt, cfg); + sp_set_config_dtr(cfg, SP_DTR_OFF); + sp_close(prt); + sp_free_port(prt); + usleep(1000000); + + for(int i = 0; i < 5; i++) { + sp2 = get_libserialport_data(&n2); + diff = sa_spa_not_spb(sp2, n2, sp1, n1); + if(*diff && (*diff)->port) { + pmsg_notice("new port %s discovered\n", (*diff)->port); + if(portp) { + if(*portp) + free(*portp); + *portp = cfg_strdup(__func__, (*diff)->port); + } + break; + } + usleep(500000); + } + + return 0; +} + // List available serial ports int list_available_serialports(LISTID programmers) { // Get serial port information from libserialport From 51d0b5b2bdf0b6134447596d5393f97ffdc2b254 Mon Sep 17 00:00:00 2001 From: MCUdude Date: Mon, 2 Oct 2023 08:06:09 +0200 Subject: [PATCH 02/19] Print error message if "touch" functionality is used without libserialport --- src/serialadapter.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/serialadapter.c b/src/serialadapter.c index 4cd6b3ad2..cae006e49 100644 --- a/src/serialadapter.c +++ b/src/serialadapter.c @@ -387,6 +387,11 @@ int list_available_serialports(LISTID programmers) { return -1; } +int touch_serialport(char **portp, int baudrate) { + pmsg_error("avrdude built without libserialport support; please compile again with libserialport installed\n"); + return -1; +} + #endif void list_serialadapters(FILE *fp, const char *prefix, LISTID programmers) { From 4ce53cbd8efe36a60255aa00d184dad937ce085c Mon Sep 17 00:00:00 2001 From: MCUdude Date: Mon, 2 Oct 2023 08:12:09 +0200 Subject: [PATCH 03/19] Make sure touch_baudrate is initialized --- src/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.c b/src/main.c index 2dec03362..29a6809f7 100644 --- a/src/main.c +++ b/src/main.c @@ -526,7 +526,7 @@ int main(int argc, char * argv []) char * e; /* for strtod() error checking */ const char *errstr; /* for str_int() error checking */ int baudrate; /* override default programmer baud rate */ - int touch_baudrate; /* baudrate to use when "touching" a serial port */ + int touch_baudrate = 0; /* baudrate to use when "touching" a serial port */ double bitclock; /* Specify programmer bit clock (JTAG ICE) */ int ispdelay; /* Specify the delay for ISP clock */ int init_ok; /* Device initialization worked well */ From 57e235644abfe08cb9ef18af9cb2b3b413d3d442 Mon Sep 17 00:00:00 2001 From: MCUdude Date: Mon, 2 Oct 2023 08:40:45 +0200 Subject: [PATCH 04/19] Add help text --- src/main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main.c b/src/main.c index 29a6809f7..9caf71f08 100644 --- a/src/main.c +++ b/src/main.c @@ -228,6 +228,8 @@ static void usage(void) " -p / Run developer options for matched AVR devices,\n" " e.g., -p ATmega328P/s or /S for part definition\n" " -b Override RS-232 baud rate\n" + " -r Open and close (\"touch\") the serial port before\n" + " establishing connection with the programmer." " -B Specify bit clock period (us)\n" " -C Specify location of configuration file\n" " -c Specify programmer; -c ? and -c ?type list all\n" From ae00c8abc743477fd489020a30cafc76334184e2 Mon Sep 17 00:00:00 2001 From: MCUdude Date: Mon, 2 Oct 2023 08:55:10 +0200 Subject: [PATCH 05/19] Only touch serial port if the programmer is connected via a serial port --- src/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.c b/src/main.c index 9caf71f08..01a0ec6ad 100644 --- a/src/main.c +++ b/src/main.c @@ -1238,7 +1238,7 @@ int main(int argc, char * argv []) free(port_tok[i]); } - if(touch_baudrate) + if(touch_baudrate && pgm->conntype == CONNTYPE_SERIAL) touch_serialport(&port, touch_baudrate); /* From d1c8e640b866bb0d1de378552d27b1c273c06162 Mon Sep 17 00:00:00 2001 From: MCUdude Date: Mon, 2 Oct 2023 10:11:33 +0200 Subject: [PATCH 06/19] Fix memory leak --- src/serialadapter.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/serialadapter.c b/src/serialadapter.c index cae006e49..7c2f49ef4 100644 --- a/src/serialadapter.c +++ b/src/serialadapter.c @@ -337,8 +337,10 @@ int touch_serialport(char **portp, int baudrate) { free(*portp); *portp = cfg_strdup(__func__, (*diff)->port); } + free(diff); break; } + free(diff); usleep(500000); } From f7a9b37c6b58d32f8f751273b59ea645a3edc960 Mon Sep 17 00:00:00 2001 From: MCUdude Date: Mon, 2 Oct 2023 20:53:47 +0200 Subject: [PATCH 07/19] Update docs --- src/avrdude.1 | 7 +++++++ src/doc/avrdude.texi | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/src/avrdude.1 b/src/avrdude.1 index f1e352913..38a2f8b0e 100644 --- a/src/avrdude.1 +++ b/src/avrdude.1 @@ -29,6 +29,7 @@ .Nm .Fl p Ar partno .Op Fl b Ar baudrate +.Op Fl r Ar baudrate .Op Fl B Ar bitclock .Op Fl c Ar programmer-id .Op Fl C Ar config-file @@ -365,6 +366,12 @@ for more information run avrdude -p x/h. .It Fl b Ar baudrate Override the RS-232 connection baud rate specified in the respective programmer's entry of the configuration file. +.It Fl r Ar baudrate +Sets the baudrate used to open and close a serial port prior to establishing +communication with the programmer, often referred to a "port touch". +The most common speed used for this is 1200 baud. Common hardware that +requires this in order to enter programming mode is the Arduino Leonardo, +Arduino Micro/Pro Micro and the Arduino Nano Every. .It Fl B Ar bitclock Specify the bit clock period for the JTAG, PDI, TPI, UPDI, or ISP interface. The value is a floating-point number in microseconds. diff --git a/src/doc/avrdude.texi b/src/doc/avrdude.texi index f71598ba2..502a7389c 100644 --- a/src/doc/avrdude.texi +++ b/src/doc/avrdude.texi @@ -469,6 +469,13 @@ ATmega328P MCU properties; for more information run @code{avrdude -p x/h}. Override the RS-232 connection baud rate specified in the respective programmer's entry of the configuration file. +@item -r @var{baudrate} +Sets the baudrate used to open and close a serial port prior to establishing +communication with the programmer, often referred to a "port touch". +The most common speed used for this is 1200 baud. Common hardware that +requires this in order to enter programming mode is the Arduino Leonardo, +Arduino Micro/Pro Micro and the Arduino Nano Every. + @item -B @var{bitclock} Specify the bit clock period for the JTAG, PDI, TPI, UPDI, or ISP interface. The value is a floating-point number in microseconds. From efe0649056f9544cd970f3b345425154da119237 Mon Sep 17 00:00:00 2001 From: MCUdude Date: Mon, 2 Oct 2023 22:25:30 +0200 Subject: [PATCH 08/19] Don't provide a user specifiable touch baudrate AFAIK, all boards/bootloaders that are using this approach to enter programming mode are using 1200 baud 8N1 anyways --- src/avrdude.1 | 13 ++++++------- src/doc/avrdude.texi | 9 ++++----- src/main.c | 14 +++++++------- 3 files changed, 17 insertions(+), 19 deletions(-) diff --git a/src/avrdude.1 b/src/avrdude.1 index 38a2f8b0e..6869cd895 100644 --- a/src/avrdude.1 +++ b/src/avrdude.1 @@ -29,7 +29,7 @@ .Nm .Fl p Ar partno .Op Fl b Ar baudrate -.Op Fl r Ar baudrate +.Op Fl r .Op Fl B Ar bitclock .Op Fl c Ar programmer-id .Op Fl C Ar config-file @@ -366,12 +366,11 @@ for more information run avrdude -p x/h. .It Fl b Ar baudrate Override the RS-232 connection baud rate specified in the respective programmer's entry of the configuration file. -.It Fl r Ar baudrate -Sets the baudrate used to open and close a serial port prior to establishing -communication with the programmer, often referred to a "port touch". -The most common speed used for this is 1200 baud. Common hardware that -requires this in order to enter programming mode is the Arduino Leonardo, -Arduino Micro/Pro Micro and the Arduino Nano Every. +.It Fl r +Opens the serial port at 1200 baud and immedeatly closes it, prior to +establishing communication with the programmer. This is commonly knows as A +"1200bps touch", and is used to trigger programming mode for certain boards +like Arduino Leonardo, Arduino Micro/Pro Micro and the Arduino Nano Every. .It Fl B Ar bitclock Specify the bit clock period for the JTAG, PDI, TPI, UPDI, or ISP interface. The value is a floating-point number in microseconds. diff --git a/src/doc/avrdude.texi b/src/doc/avrdude.texi index 502a7389c..4f426d190 100644 --- a/src/doc/avrdude.texi +++ b/src/doc/avrdude.texi @@ -470,11 +470,10 @@ Override the RS-232 connection baud rate specified in the respective programmer's entry of the configuration file. @item -r @var{baudrate} -Sets the baudrate used to open and close a serial port prior to establishing -communication with the programmer, often referred to a "port touch". -The most common speed used for this is 1200 baud. Common hardware that -requires this in order to enter programming mode is the Arduino Leonardo, -Arduino Micro/Pro Micro and the Arduino Nano Every. +Opens the serial port at 1200 baud and immedeatly closes it, prior to +establishing communication with the programmer. This is commonly knows as A +"1200bps touch", and is used to trigger programming mode for certain boards +like Arduino Leonardo, Arduino Micro/Pro Micro and the Arduino Nano Every. @item -B @var{bitclock} Specify the bit clock period for the JTAG, PDI, TPI, UPDI, or ISP diff --git a/src/main.c b/src/main.c index 01a0ec6ad..a498f40fe 100644 --- a/src/main.c +++ b/src/main.c @@ -228,8 +228,8 @@ static void usage(void) " -p / Run developer options for matched AVR devices,\n" " e.g., -p ATmega328P/s or /S for part definition\n" " -b Override RS-232 baud rate\n" - " -r Open and close (\"touch\") the serial port before\n" - " establishing connection with the programmer." + " -r Open and close (\"touch\") the serial port at\n" + " 1200 baud before establishing connection\n" " -B Specify bit clock period (us)\n" " -C Specify location of configuration file\n" " -c Specify programmer; -c ? and -c ?type list all\n" @@ -528,7 +528,7 @@ int main(int argc, char * argv []) char * e; /* for strtod() error checking */ const char *errstr; /* for str_int() error checking */ int baudrate; /* override default programmer baud rate */ - int touch_baudrate = 0; /* baudrate to use when "touching" a serial port */ + bool touch_1200bps = false; /* "touch" serial port prior to programming */ double bitclock; /* Specify programmer bit clock (JTAG ICE) */ int ispdelay; /* Specify the delay for ISP clock */ int init_ok; /* Device initialization worked well */ @@ -638,7 +638,7 @@ int main(int argc, char * argv []) /* * process command line arguments */ - while ((ch = getopt(argc,argv,"?Ab:B:c:C:DeE:Fi:l:np:OP:qr:stT:U:uvVx:yY:")) != -1) { + while ((ch = getopt(argc,argv,"?Ab:B:c:C:DeE:Fi:l:np:OP:qrstT:U:uvVx:yY:")) != -1) { switch (ch) { case 'b': /* override default programmer baud rate */ @@ -770,7 +770,7 @@ int main(int argc, char * argv []) break; case 'r' : - touch_baudrate = str_int(optarg, STR_INT32, &errstr); + touch_1200bps = true; break; case 't': /* enter terminal mode */ @@ -1238,8 +1238,8 @@ int main(int argc, char * argv []) free(port_tok[i]); } - if(touch_baudrate && pgm->conntype == CONNTYPE_SERIAL) - touch_serialport(&port, touch_baudrate); + if(touch_1200bps && pgm->conntype == CONNTYPE_SERIAL) + touch_serialport(&port, 1200); /* * open the programmer From a99137e1155792be0862bbabaded0694fda34dee Mon Sep 17 00:00:00 2001 From: MCUdude Date: Tue, 3 Oct 2023 20:48:00 +0200 Subject: [PATCH 09/19] Apply @stefanruegers patch --- src/serialadapter.c | 85 +++++++++++++++++++++++++++------------------ 1 file changed, 52 insertions(+), 33 deletions(-) diff --git a/src/serialadapter.c b/src/serialadapter.c index 7c2f49ef4..fee29b831 100644 --- a/src/serialadapter.c +++ b/src/serialadapter.c @@ -131,6 +131,13 @@ static SERPORT *get_libserialport_data(int *np) { return sp; } +// Free memory allocated from get_libserialport_data() +static void free_libserialport_data(SERPORT *sp, int n) { + for(int k = 0; sp && k < n; k++) + free(sp[k].sernum), free(sp[k].port); + free(sp); +} + // Returns a NULL-terminated malloc'd list of items in SERPORT list spa that are not in spb SERPORT **sa_spa_not_spb(SERPORT *spa, int na, SERPORT *spb, int nb) { SERPORT **ret = cfg_malloc(__func__, (na+1)*sizeof*ret); @@ -267,10 +274,7 @@ int setport_from_serialadapter(char **portp, const SERIALADAPTER *sea, const cha if(m == 0 || sa_num_matches_by_sea(sea, sernum, sp+i, 1) == 1) sa_print_specs(sp, n, i); } - - for(int k = 0; k < n; k++) - free(sp[k].sernum), free(sp[k].port); - free(sp); + free_libserialport_data(sp, n); return rv; } @@ -295,54 +299,69 @@ int setport_from_vid_pid(char **portp, int vid, int pid, const char *sernum) { if(m == 0 || sa_num_matches_by_ids(vid, pid, sernum, sp+i, 1) == 1) sa_print_specs(sp, n, i); } - - for(int k = 0; k < n; k++) - free(sp[k].sernum), free(sp[k].port); - free(sp); + free_libserialport_data(sp, n); return rv; } +// Potentially change port *portp after opening & closing it with baudrate int touch_serialport(char **portp, int baudrate) { - int n1, n2; + int n1, n2, rc, touched; SERPORT *sp1, *sp2, **diff; sp1 = get_libserialport_data(&n1); - if(!sp1 || n1 <= 0) + if(!sp1 || n1 <= 0 || !portp) return -1; pmsg_info("touching serial port %s at %d baud\n", *portp, baudrate); struct sp_port *prt; struct sp_port_config *cfg; - sp_get_port_by_name(*portp, &prt); - sp_open(prt, SP_MODE_READ); - sp_set_baudrate(prt, baudrate); - sp_set_bits(prt, 8); - sp_set_parity(prt, SP_PARITY_NONE); - sp_set_stopbits(prt, 1); - sp_set_flowcontrol(prt, SP_FLOWCONTROL_NONE); - sp_new_config(&cfg); - sp_get_config(prt, cfg); - sp_set_config_dtr(cfg, SP_DTR_OFF); - sp_close(prt); - sp_free_port(prt); - usleep(1000000); - - for(int i = 0; i < 5; i++) { - sp2 = get_libserialport_data(&n2); - diff = sa_spa_not_spb(sp2, n2, sp1, n1); - if(*diff && (*diff)->port) { - pmsg_notice("new port %s discovered\n", (*diff)->port); - if(portp) { + char *errs[] = { + "getting info for", "opening", "setting the baud rate for", "setting the character size for", + "setting parity to none for", "setting 1 stopbit for", "unsetting flow of control", + "allocating a new condiguration for", "getting configuration for", "setting DTR off for", + "closing", "all OK (one should never see this printed)", + }; + + touched = 0; + if((rc = sp_get_port_by_name(*portp, &prt)) == SP_OK && ++touched) { + if((rc = sp_open(prt, SP_MODE_READ)) == SP_OK && ++touched) { + if((rc = sp_set_baudrate(prt, baudrate)) == SP_OK && ++touched) + if((rc = sp_set_bits(prt, 8)) == SP_OK && ++touched) + if((rc = sp_set_parity(prt, SP_PARITY_NONE)) == SP_OK && ++touched) + if((rc = sp_set_stopbits(prt, 1)) == SP_OK && ++touched) + if((rc = sp_set_flowcontrol(prt, SP_FLOWCONTROL_NONE)) == SP_OK && ++touched) + if((rc = sp_new_config(&cfg)) == SP_OK && ++touched) + if((rc = sp_get_config(prt, cfg)) == SP_OK && ++touched) + if((rc = sp_set_config_dtr(cfg, SP_DTR_OFF)) == SP_OK) + ++touched; + if((rc = sp_close(prt)) == SP_OK) + ++touched; + } + sp_free_port(prt); + } + + if(touched < 11) { + pmsg_error("%s() failed %s port %s: %s\n", __func__, errs[touched], *portp, + rc==SP_ERR_FAIL? sp_last_error_message(): "unknown reason"); + return -1; + } + + for(int i = 5; i > 0; i--) { + usleep(200*1000); + if((sp2 = get_libserialport_data(&n2))) { + diff = sa_spa_not_spb(sp2, n2, sp1, n1); + if(*diff && diff[0]->port && !diff[1]) { // Exactly one new port sprung up + pmsg_notice("new port %s discovered\n", (*diff)->port); if(*portp) free(*portp); *portp = cfg_strdup(__func__, (*diff)->port); + i = 1; // Leave loop } free(diff); - break; + free_libserialport_data(sp2, n2); } - free(diff); - usleep(500000); } + free_libserialport_data(sp1, n1); return 0; } From 354a5bb93e6439f717af205bc1492a688798b603 Mon Sep 17 00:00:00 2001 From: MCUdude Date: Tue, 3 Oct 2023 21:59:07 +0200 Subject: [PATCH 10/19] Replace libserialport port open/close with the built-in avrdude one --- src/serialadapter.c | 50 ++++++++++++++------------------------------- 1 file changed, 15 insertions(+), 35 deletions(-) diff --git a/src/serialadapter.c b/src/serialadapter.c index fee29b831..ac1d9fd41 100644 --- a/src/serialadapter.c +++ b/src/serialadapter.c @@ -306,48 +306,27 @@ int setport_from_vid_pid(char **portp, int vid, int pid, const char *sernum) { // Potentially change port *portp after opening & closing it with baudrate int touch_serialport(char **portp, int baudrate) { - int n1, n2, rc, touched; + int i, n1, n2; SERPORT *sp1, *sp2, **diff; sp1 = get_libserialport_data(&n1); if(!sp1 || n1 <= 0 || !portp) return -1; pmsg_info("touching serial port %s at %d baud\n", *portp, baudrate); - struct sp_port *prt; - struct sp_port_config *cfg; - char *errs[] = { - "getting info for", "opening", "setting the baud rate for", "setting the character size for", - "setting parity to none for", "setting 1 stopbit for", "unsetting flow of control", - "allocating a new condiguration for", "getting configuration for", "setting DTR off for", - "closing", "all OK (one should never see this printed)", - }; - - touched = 0; - if((rc = sp_get_port_by_name(*portp, &prt)) == SP_OK && ++touched) { - if((rc = sp_open(prt, SP_MODE_READ)) == SP_OK && ++touched) { - if((rc = sp_set_baudrate(prt, baudrate)) == SP_OK && ++touched) - if((rc = sp_set_bits(prt, 8)) == SP_OK && ++touched) - if((rc = sp_set_parity(prt, SP_PARITY_NONE)) == SP_OK && ++touched) - if((rc = sp_set_stopbits(prt, 1)) == SP_OK && ++touched) - if((rc = sp_set_flowcontrol(prt, SP_FLOWCONTROL_NONE)) == SP_OK && ++touched) - if((rc = sp_new_config(&cfg)) == SP_OK && ++touched) - if((rc = sp_get_config(prt, cfg)) == SP_OK && ++touched) - if((rc = sp_set_config_dtr(cfg, SP_DTR_OFF)) == SP_OK) - ++touched; - if((rc = sp_close(prt)) == SP_OK) - ++touched; - } - sp_free_port(prt); - } - - if(touched < 11) { - pmsg_error("%s() failed %s port %s: %s\n", __func__, errs[touched], *portp, - rc==SP_ERR_FAIL? sp_last_error_message(): "unknown reason"); + union pinfo pinfo; + union filedescriptor fd; + pinfo.serialinfo.baud = baudrate; + pinfo.serialinfo.cflags = SERIAL_8N1; + if(serial_open(*portp, pinfo, &fd) == -1) { + pmsg_error("%s() failed to open port %s at %d baud\n", __func__, *portp, baudrate); return -1; } + serial_set_dtr_rts(&fd, 0); + serial_close(&fd); - for(int i = 5; i > 0; i--) { - usleep(200*1000); + pmsg_info("waiting for new port..."); + for(i = 10; i > 0; i--) { + usleep(80*1000); if((sp2 = get_libserialport_data(&n2))) { diff = sa_spa_not_spb(sp2, n2, sp1, n1); if(*diff && diff[0]->port && !diff[1]) { // Exactly one new port sprung up @@ -355,13 +334,14 @@ int touch_serialport(char **portp, int baudrate) { if(*portp) free(*portp); *portp = cfg_strdup(__func__, (*diff)->port); - i = 1; // Leave loop + i = -1; // Leave loop } - free(diff); + free(diff); free_libserialport_data(sp2, n2); } } free_libserialport_data(sp1, n1); + msg_info(" using %s port %s\n", i<0? "new": "same", *portp); return 0; } From deb314d627880e5e8a30d94e397d32cbb48067c1 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Fri, 6 Oct 2023 19:06:30 +0100 Subject: [PATCH 11/19] Allow repeated -r to lengthen sleep before reconnecting --- src/avrdude.1 | 11 +++++++---- src/doc/avrdude.texi | 13 ++++++++----- src/libavrdude.h | 3 ++- src/main.c | 31 +++++++++++++++---------------- src/serialadapter.c | 13 ++++++++++--- 5 files changed, 42 insertions(+), 29 deletions(-) diff --git a/src/avrdude.1 b/src/avrdude.1 index 6869cd895..cffcdf067 100644 --- a/src/avrdude.1 +++ b/src/avrdude.1 @@ -367,10 +367,13 @@ for more information run avrdude -p x/h. Override the RS-232 connection baud rate specified in the respective programmer's entry of the configuration file. .It Fl r -Opens the serial port at 1200 baud and immedeatly closes it, prior to -establishing communication with the programmer. This is commonly knows as A -"1200bps touch", and is used to trigger programming mode for certain boards -like Arduino Leonardo, Arduino Micro/Pro Micro and the Arduino Nano Every. +Opens the serial port at 1200 baud and immediately closes it, waits 400 ms +for each -r on the command line and then establishes communication with +the programmer. This is commonly known as a "1200bps touch", and is used +to trigger programming mode for certain boards like Arduino Leonardo, +Arduino Micro/Pro Micro and the Arduino Nano Every. Longer waits, and +therefore multiple -r options are sometimes needed for slower, less +powerful hosts. .It Fl B Ar bitclock Specify the bit clock period for the JTAG, PDI, TPI, UPDI, or ISP interface. The value is a floating-point number in microseconds. diff --git a/src/doc/avrdude.texi b/src/doc/avrdude.texi index 4f426d190..2f28b3bb6 100644 --- a/src/doc/avrdude.texi +++ b/src/doc/avrdude.texi @@ -469,11 +469,14 @@ ATmega328P MCU properties; for more information run @code{avrdude -p x/h}. Override the RS-232 connection baud rate specified in the respective programmer's entry of the configuration file. -@item -r @var{baudrate} -Opens the serial port at 1200 baud and immedeatly closes it, prior to -establishing communication with the programmer. This is commonly knows as A -"1200bps touch", and is used to trigger programming mode for certain boards -like Arduino Leonardo, Arduino Micro/Pro Micro and the Arduino Nano Every. +@item -r +Opens the serial port at 1200 baud and immediately closes it, waits 400 ms +for each @code{-r} on the command line and then establishes communication +with the programmer. This is commonly known as a "1200bps touch", and is +used to trigger programming mode for certain boards like Arduino Leonardo, +Arduino Micro/Pro Micro and the Arduino Nano Every. Longer waits, and +therefore multiple @code{-r} options are sometimes needed for slower, less +powerful hosts. @item -B @var{bitclock} Specify the bit clock period for the JTAG, PDI, TPI, UPDI, or ISP diff --git a/src/libavrdude.h b/src/libavrdude.h index e932b9593..16f669faa 100644 --- a/src/libavrdude.h +++ b/src/libavrdude.h @@ -668,6 +668,7 @@ struct serial_device { int (*open)(const char *port, union pinfo pinfo, union filedescriptor *fd); int (*setparams)(const union filedescriptor *fd, long baud, unsigned long cflags); void (*close)(union filedescriptor *fd); + void (*rawclose)(union filedescriptor *fd); // Don't restore terminal attributes int (*send)(const union filedescriptor *fd, const unsigned char * buf, size_t buflen); int (*recv)(const union filedescriptor *fd, unsigned char * buf, size_t buflen); @@ -1252,7 +1253,7 @@ extern "C" { int setport_from_serialadapter(char **portp, const SERIALADAPTER *ser, const char *sernum); int setport_from_vid_pid(char **portp, int vid, int pid, const char *sernum); int list_available_serialports(LISTID programmers); -int touch_serialport(char **portp, int baudrate); +int touch_serialport(char **portp, int baudrate, int nwaits); int str_starts(const char *str, const char *starts); int str_eq(const char *str1, const char *str2); diff --git a/src/main.c b/src/main.c index a498f40fe..0686790ae 100644 --- a/src/main.c +++ b/src/main.c @@ -228,8 +228,6 @@ static void usage(void) " -p / Run developer options for matched AVR devices,\n" " e.g., -p ATmega328P/s or /S for part definition\n" " -b Override RS-232 baud rate\n" - " -r Open and close (\"touch\") the serial port at\n" - " 1200 baud before establishing connection\n" " -B Specify bit clock period (us)\n" " -C Specify location of configuration file\n" " -c Specify programmer; -c ? and -c ?type list all\n" @@ -239,6 +237,8 @@ static void usage(void) " -D Disable auto erase for flash memory; implies -A\n" " -i ISP Clock Delay [in microseconds]\n" " -P Connection; -P ?s or -P ?sa lists serial ones\n" + " -r Reconnect to -P port after \"touching\" it; wait\n" + " 400 ms for each -r; needed for some USB boards\n" " -F Override invalid signature or initial checks\n" " -e Perform a chip erase\n" " -O Perform RC oscillator calibration (see AVR053)\n" @@ -528,7 +528,7 @@ int main(int argc, char * argv []) char * e; /* for strtod() error checking */ const char *errstr; /* for str_int() error checking */ int baudrate; /* override default programmer baud rate */ - bool touch_1200bps = false; /* "touch" serial port prior to programming */ + int touch_1200bps; /* "touch" serial port prior to programming */ double bitclock; /* Specify programmer bit clock (JTAG ICE) */ int ispdelay; /* Specify the delay for ISP clock */ int init_ok; /* Device initialization worked well */ @@ -615,6 +615,7 @@ int main(int argc, char * argv []) explicit_e = 0; verbose = 0; baudrate = 0; + touch_1200bps = 0; bitclock = 0.0; ispdelay = 0; is_open = 0; @@ -770,7 +771,7 @@ int main(int argc, char * argv []) break; case 'r' : - touch_1200bps = true; + touch_1200bps++; break; case 't': /* enter terminal mode */ @@ -1182,6 +1183,13 @@ int main(int argc, char * argv []) } } + if(port[0] == 0 || str_eq(port, "unknown")) { + msg_error("\n"); + pmsg_error("no port has been specified on the command line or in the config file\n"); + imsg_error("specify a port using the -P option and try again\n\n"); + exit(1); + } + /* * Divide a serialadapter port string into tokens separated by colons. * There are two ways such a port string can be presented: @@ -1236,21 +1244,12 @@ int main(int argc, char * argv []) } for (int i = 0; i < 4; i++) free(port_tok[i]); + if(touch_1200bps && touch_serialport(&port, 1200, touch_1200bps) < 0) + exit(1); } - if(touch_1200bps && pgm->conntype == CONNTYPE_SERIAL) - touch_serialport(&port, 1200); - - /* - * open the programmer - */ - if (port[0] == 0) { - msg_error("\n"); - pmsg_error("no port has been specified on the command line or in the config file\n"); - imsg_error("specify a port using the -P option and try again\n\n"); - exit(1); - } + // Open the programmer if (verbose > 0) { imsg_notice("Using Port : %s\n", port); imsg_notice("Using Programmer : %s\n", pgmid); diff --git a/src/serialadapter.c b/src/serialadapter.c index ac1d9fd41..8ea0244d7 100644 --- a/src/serialadapter.c +++ b/src/serialadapter.c @@ -305,7 +305,7 @@ int setport_from_vid_pid(char **portp, int vid, int pid, const char *sernum) { } // Potentially change port *portp after opening & closing it with baudrate -int touch_serialport(char **portp, int baudrate) { +int touch_serialport(char **portp, int baudrate, int nwaits) { int i, n1, n2; SERPORT *sp1, *sp2, **diff; sp1 = get_libserialport_data(&n1); @@ -313,6 +313,7 @@ int touch_serialport(char **portp, int baudrate) { return -1; pmsg_info("touching serial port %s at %d baud\n", *portp, baudrate); + union pinfo pinfo; union filedescriptor fd; pinfo.serialinfo.baud = baudrate; @@ -324,9 +325,14 @@ int touch_serialport(char **portp, int baudrate) { serial_set_dtr_rts(&fd, 0); serial_close(&fd); + int nloops = 32, nap = 50; +#if defined(__arm__) + nwaits += 2; +#endif pmsg_info("waiting for new port..."); - for(i = 10; i > 0; i--) { - usleep(80*1000); + usleep(400*nwaits*1000); + for(i = nloops; i > 0; i--) { + usleep(nap*1000); if((sp2 = get_libserialport_data(&n2))) { diff = sa_spa_not_spb(sp2, n2, sp1, n1); if(*diff && diff[0]->port && !diff[1]) { // Exactly one new port sprung up @@ -334,6 +340,7 @@ int touch_serialport(char **portp, int baudrate) { if(*portp) free(*portp); *portp = cfg_strdup(__func__, (*diff)->port); + msg_info(" %d ms:", (nloops-i+1)*nap + nwaits*400); i = -1; // Leave loop } free(diff); From 6897a3f1ded5d0fee7dfa1cee3c4f80861da6ab2 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Fri, 6 Oct 2023 19:13:51 +0100 Subject: [PATCH 12/19] Add serial_rawclose() to aid -r "touch" for Linux --- src/libavrdude.h | 3 ++- src/ser_avrdoper.c | 1 + src/ser_posix.c | 7 ++++++- src/ser_win32.c | 1 + src/serialadapter.c | 2 +- src/usb_hidapi.c | 1 + src/usb_libusb.c | 2 ++ src/xbee.c | 1 + 8 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/libavrdude.h b/src/libavrdude.h index 16f669faa..85d1e59cd 100644 --- a/src/libavrdude.h +++ b/src/libavrdude.h @@ -668,7 +668,7 @@ struct serial_device { int (*open)(const char *port, union pinfo pinfo, union filedescriptor *fd); int (*setparams)(const union filedescriptor *fd, long baud, unsigned long cflags); void (*close)(union filedescriptor *fd); - void (*rawclose)(union filedescriptor *fd); // Don't restore terminal attributes + void (*rawclose)(union filedescriptor *fd); // Don't restore terminal attributes (Linux) int (*send)(const union filedescriptor *fd, const unsigned char * buf, size_t buflen); int (*recv)(const union filedescriptor *fd, unsigned char * buf, size_t buflen); @@ -692,6 +692,7 @@ extern struct serial_device usbhid_serdev; #define serial_open (serdev->open) #define serial_setparams (serdev->setparams) #define serial_close (serdev->close) +#define serial_rawclose (serdev->rawclose) #define serial_send (serdev->send) #define serial_recv (serdev->recv) #define serial_drain (serdev->drain) diff --git a/src/ser_avrdoper.c b/src/ser_avrdoper.c index ca46ca58e..937909a47 100644 --- a/src/ser_avrdoper.c +++ b/src/ser_avrdoper.c @@ -352,6 +352,7 @@ struct serial_device avrdoper_serdev = { .open = avrdoper_open, .close = avrdoper_close, + .rawclose = avrdoper_close, .send = avrdoper_send, .recv = avrdoper_recv, .drain = avrdoper_drain, diff --git a/src/ser_posix.c b/src/ser_posix.c index b0bab284d..aec8ba5c5 100644 --- a/src/ser_posix.c +++ b/src/ser_posix.c @@ -352,7 +352,6 @@ static int net_open(const char *port, union filedescriptor *fdp) { return ret; } - static int ser_set_dtr_rts(const union filedescriptor *fdp, int is_on) { unsigned int ctl; int r; @@ -431,6 +430,11 @@ static void ser_close(union filedescriptor *fd) { close(fd->ifd); } +// Close but don't restore attributes +static void ser_rawclose(union filedescriptor *fd) { + saved_original_termios = 0; + close(fd->ifd); +} static int ser_send(const union filedescriptor *fd, const unsigned char * buf, size_t buflen) { int rc; @@ -598,6 +602,7 @@ struct serial_device serial_serdev = .open = ser_open, .setparams = ser_setparams, .close = ser_close, + .rawclose = ser_rawclose, .send = ser_send, .recv = ser_recv, .drain = ser_drain, diff --git a/src/ser_win32.c b/src/ser_win32.c index fc59b9caa..b7480ac2f 100644 --- a/src/ser_win32.c +++ b/src/ser_win32.c @@ -756,6 +756,7 @@ struct serial_device serial_serdev = .open = ser_open, .setparams = ser_setparams, .close = ser_close, + .rawclose = ser_close, .send = ser_send, .recv = ser_recv, .drain = ser_drain, diff --git a/src/serialadapter.c b/src/serialadapter.c index 8ea0244d7..0a6360058 100644 --- a/src/serialadapter.c +++ b/src/serialadapter.c @@ -323,7 +323,7 @@ int touch_serialport(char **portp, int baudrate, int nwaits) { return -1; } serial_set_dtr_rts(&fd, 0); - serial_close(&fd); + serial_rawclose(&fd); int nloops = 32, nap = 50; #if defined(__arm__) diff --git a/src/usb_hidapi.c b/src/usb_hidapi.c index 34d768223..c7021608a 100644 --- a/src/usb_hidapi.c +++ b/src/usb_hidapi.c @@ -318,6 +318,7 @@ static int usbhid_drain(const union filedescriptor *fd, int display) { struct serial_device usbhid_serdev = { .open = usbhid_open, .close = usbhid_close, + .rawclose = usbhid_close, .send = usbhid_send, .recv = usbhid_recv, .drain = usbhid_drain, diff --git a/src/usb_libusb.c b/src/usb_libusb.c index a7847b357..20ef605ed 100644 --- a/src/usb_libusb.c +++ b/src/usb_libusb.c @@ -578,6 +578,7 @@ struct serial_device usb_serdev = { .open = usbdev_open, .close = usbdev_close, + .rawclose = usbdev_close, .send = usbdev_send, .recv = usbdev_recv, .drain = usbdev_drain, @@ -591,6 +592,7 @@ struct serial_device usb_serdev_frame = { .open = usbdev_open, .close = usbdev_close, + .rawclose = usbdev_close, .send = usbdev_send, .recv = usbdev_recv_frame, .drain = usbdev_drain, diff --git a/src/xbee.c b/src/xbee.c index 0aaf04693..52b3c5df9 100644 --- a/src/xbee.c +++ b/src/xbee.c @@ -1505,6 +1505,7 @@ static int xbeedev_set_dtr_rts(const union filedescriptor *fdp, int is_on) static struct serial_device xbee_serdev_frame = { .open = xbeedev_open, .close = xbeedev_close, + .rawclose = xbeedev_close, .send = xbeedev_send, .recv = xbeedev_recv, .drain = xbeedev_drain, From 7a3de482d6b15d25449683c2fd4842017c00bd6b Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Fri, 6 Oct 2023 19:21:05 +0100 Subject: [PATCH 13/19] Fix touch_serialport() in absence of libserialport --- src/serialadapter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/serialadapter.c b/src/serialadapter.c index 0a6360058..21a350a9d 100644 --- a/src/serialadapter.c +++ b/src/serialadapter.c @@ -395,7 +395,7 @@ int list_available_serialports(LISTID programmers) { return -1; } -int touch_serialport(char **portp, int baudrate) { +int touch_serialport(char **portp, int baudrate, int nwaits) { pmsg_error("avrdude built without libserialport support; please compile again with libserialport installed\n"); return -1; } From c72cc7b10c4936e4bb8d5cc243fb6c3e56dd530b Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Fri, 6 Oct 2023 19:30:02 +0100 Subject: [PATCH 14/19] Fix comma in documentation --- src/avrdude.1 | 2 +- src/doc/avrdude.texi | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/avrdude.1 b/src/avrdude.1 index cffcdf067..0be3994df 100644 --- a/src/avrdude.1 +++ b/src/avrdude.1 @@ -372,7 +372,7 @@ for each -r on the command line and then establishes communication with the programmer. This is commonly known as a "1200bps touch", and is used to trigger programming mode for certain boards like Arduino Leonardo, Arduino Micro/Pro Micro and the Arduino Nano Every. Longer waits, and -therefore multiple -r options are sometimes needed for slower, less +therefore multiple -r options, are sometimes needed for slower, less powerful hosts. .It Fl B Ar bitclock Specify the bit clock period for the JTAG, PDI, TPI, UPDI, or ISP diff --git a/src/doc/avrdude.texi b/src/doc/avrdude.texi index 2f28b3bb6..60d5c6e42 100644 --- a/src/doc/avrdude.texi +++ b/src/doc/avrdude.texi @@ -475,7 +475,7 @@ for each @code{-r} on the command line and then establishes communication with the programmer. This is commonly known as a "1200bps touch", and is used to trigger programming mode for certain boards like Arduino Leonardo, Arduino Micro/Pro Micro and the Arduino Nano Every. Longer waits, and -therefore multiple @code{-r} options are sometimes needed for slower, less +therefore multiple @code{-r} options, are sometimes needed for slower, less powerful hosts. @item -B @var{bitclock} From e7e1e0e256a7c8dee1fbb35444e66040af70a3c9 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Fri, 6 Oct 2023 19:37:27 +0100 Subject: [PATCH 15/19] Hint -rr and -rrr is available if open fails on -r --- src/main.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main.c b/src/main.c index 0686790ae..02cd67c45 100644 --- a/src/main.c +++ b/src/main.c @@ -1276,8 +1276,11 @@ int main(int argc, char * argv []) rc = pgm->open(pgm, port); if (rc < 0) { pmsg_error("unable to open programmer %s on port %s\n", pgmid, port); - if (print_ports && pgm->conntype == CONNTYPE_SERIAL) + if (print_ports && pgm->conntype == CONNTYPE_SERIAL) { list_available_serialports(programmers); + if(touch_1200bps == 1) + pmsg_info("alternatively, try -rr or -rrr for longer delays\n"); + } exitrc = 1; pgm->ppidata = 0; /* clear all bits at exit */ goto main_exit; From 6c4f6ba0c39e99db94953a68881f8511c95a0733 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Fri, 6 Oct 2023 19:40:16 +0100 Subject: [PATCH 16/19] Clarify error message when failing to open a port --- src/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.c b/src/main.c index 02cd67c45..7dde5f8b6 100644 --- a/src/main.c +++ b/src/main.c @@ -1275,7 +1275,7 @@ int main(int argc, char * argv []) rc = pgm->open(pgm, port); if (rc < 0) { - pmsg_error("unable to open programmer %s on port %s\n", pgmid, port); + pmsg_error("unable to open port %s for programmer %s\n", port, pgmid); if (print_ports && pgm->conntype == CONNTYPE_SERIAL) { list_available_serialports(programmers); if(touch_1200bps == 1) From 27654c2cbf82284e9524f5f2726670d6bcf7b92d Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Sun, 8 Oct 2023 20:22:57 +0100 Subject: [PATCH 17/19] Modify default nwaits compile-time condition --- src/serialadapter.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/serialadapter.c b/src/serialadapter.c index 21a350a9d..6a5f9d2e7 100644 --- a/src/serialadapter.c +++ b/src/serialadapter.c @@ -325,12 +325,12 @@ int touch_serialport(char **portp, int baudrate, int nwaits) { serial_set_dtr_rts(&fd, 0); serial_rawclose(&fd); - int nloops = 32, nap = 50; -#if defined(__arm__) + const int nloops = 32, nap = 50; +#if (defined(__arm__) || defined(__aarch64__)) && !defined(__APPLE__) nwaits += 2; #endif pmsg_info("waiting for new port..."); - usleep(400*nwaits*1000); + usleep(400*1000*nwaits); for(i = nloops; i > 0; i--) { usleep(nap*1000); if((sp2 = get_libserialport_data(&n2))) { From 43a5c2b89c10e298a1d86bba1e15273ff374fbc7 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Fri, 13 Oct 2023 09:57:08 +0100 Subject: [PATCH 18/19] Pluck DTR/RTS for serial touch --- src/serialadapter.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/serialadapter.c b/src/serialadapter.c index 6a5f9d2e7..9f785458e 100644 --- a/src/serialadapter.c +++ b/src/serialadapter.c @@ -322,6 +322,8 @@ int touch_serialport(char **portp, int baudrate, int nwaits) { pmsg_error("%s() failed to open port %s at %d baud\n", __func__, *portp, baudrate); return -1; } + serial_set_dtr_rts(&fd, 1); + usleep(100); serial_set_dtr_rts(&fd, 0); serial_rawclose(&fd); From 39f094e6894f4ec632f532f84ff38ac6261f91e4 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Fri, 13 Oct 2023 18:06:50 +0100 Subject: [PATCH 19/19] Suggest serial ports after "touch port" failure --- src/main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main.c b/src/main.c index 7dde5f8b6..21dccd287 100644 --- a/src/main.c +++ b/src/main.c @@ -1245,7 +1245,7 @@ int main(int argc, char * argv []) for (int i = 0; i < 4; i++) free(port_tok[i]); if(touch_1200bps && touch_serialport(&port, 1200, touch_1200bps) < 0) - exit(1); + goto skipopen; } @@ -1276,6 +1276,7 @@ int main(int argc, char * argv []) rc = pgm->open(pgm, port); if (rc < 0) { pmsg_error("unable to open port %s for programmer %s\n", port, pgmid); +skipopen: if (print_ports && pgm->conntype == CONNTYPE_SERIAL) { list_available_serialports(programmers); if(touch_1200bps == 1)