diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c10a77eb..5577d955 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -214,6 +214,7 @@ add_library(libavrdude ser_avrdoper.c ser_posix.c ser_win32.c + serialadapter.c serialupdi.c serialupdi.h solaris_ecpp.h @@ -286,6 +287,7 @@ target_link_libraries(libavrdude ${LIB_LIBFTDI} ${LIB_LIBFTDI1} ${LIB_LIBREADLINE} + ${LIB_LIBSERIALPORT} ${LIB_NCURSES} ${LIB_LIBGPIOD} ${EXTRA_WINDOWS_LIBRARIES} diff --git a/src/Makefile.am b/src/Makefile.am index 9ac585a5..5a994fb4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -163,6 +163,7 @@ libavrdude_a_SOURCES = \ ser_avrdoper.c \ ser_posix.c \ ser_win32.c \ + serialadapter.c \ solaris_ecpp.h \ stk500.c \ stk500.h \ diff --git a/src/avrdude.conf.in b/src/avrdude.conf.in index 3dd99558..675828e4 100644 --- a/src/avrdude.conf.in +++ b/src/avrdude.conf.in @@ -4,11 +4,11 @@ # # This file contains configuration data used by AVRDUDE which describes # the programming hardware pinouts and also provides part definitions. -# AVRDUDE's "-C" command line option specifies the location of the -# configuration file. The "-c" option names the programmer configuration -# which must match one of the entry's "id" parameter. The "-p" option +# AVRDUDE's -C command line option specifies the location of the +# configuration file. The -c option names the programmer configuration +# which must match one of the entry's id parameter. The -p option # identifies which part AVRDUDE is going to be programming and must match -# one of the parts' "id" parameter. +# one of the parts' id parameters. # # DO NOT MODIFY THIS FILE. Modifications will be overwritten the next # time a "make install" is run. For user-specific additions, use the @@ -21,12 +21,13 @@ # id = [, ... ] ; # are quoted strings # desc = ; # quoted string # type = ; # programmer type, quoted string -# # supported types can be listed by "-c ?type" +# # list known types with -c ?type # prog_modes = PM_ {| PM_} # interfaces, eg, PM_SPM|PM_PDI (1) -# extra_features = HAS_ {| HAS_} # extra features, eg, HAS_SUFFER|HAS_VTARG_ADJ (2) +# is_serialadapter = # programmer is also a serialadapter +# extra_features = HAS_ {| HAS_} # extra features, eg, HAS_SUFFER (2) # connection_type = parallel | serial | usb | spi # baudrate = ; # baudrate for avr910-programmer -# vcc = [, ... ] ; # pin number(s) +# vcc = [, ... ] ; # pin number(s) (3) # buff = [, ... ] ; # pin number(s) # reset = ; # pin number # sck = ; # pin number @@ -40,8 +41,8 @@ # rdyled = ; # pin number # pgmled = ; # pin number # vfyled = ; # pin number -# usbvid = ; # USB VID (Vendor ID) -# usbpid = [, ...] ; # USB PID (Product ID) (3) +# usbvid = ; # USB vendor ID +# usbpid = [, ...] ; # USB product ID (4) # usbdev = ; # USB interface or other device info # usbvendor = ; # USB Vendor Name # usbproduct = ; # USB Product Name @@ -49,8 +50,7 @@ # hvupdi_support = [, , ... ] ; # UPDI HV Variants Support # ; # -# # To invert a pin use = ~ -# # To invert a pin list (all pins get inverted) use ~ ( [, ... ] ) +# # Notes # # # # (1) The following program modes are known: # # - PM_SPM: Bootloaders, self-programming with SPM opcodes or NVM Controllers @@ -81,7 +81,20 @@ # # - HAS_VAREF_ADJ: Programmer has an adjustable analog reference voltage that # # can be controlled with Avrdude # # -# # (3) Not all programmer types can process a list of PIDs +# # (3) To invert the polarity of a pin use a tilde: ~ +# # To invert the polarity of all pins in a list use ~( [, ... ]) +# # +# # (4) Not all programmer types can process a list of PIDs +# +# serialadapter # same as programmer albeit only for usb parameters +# parent # optional serialadapter or programmer parent +# id = [, ... ] ; # are quoted strings +# desc = ; # quoted string +# baudrate = ; # optional default baudrate, eg, in .avrduderc +# usbvid = ; # USB vendor ID +# usbpid = [, ...] ; # list of USB product IDs +# usbsn = ; # USB Serial Number in per-user .avrduderc +# ; # # part # desc = ; # quoted string, the long part name, eg, "ATmega328p" @@ -924,7 +937,7 @@ programmer # The drivers will look for a specific device and use the first one # found. If you have mulitple devices, and they give out serial # numbers, a different entry for each of them can be created in a -# persnonal ~/.avrduderc or avrdude.rc entry and the usbsn = "..."; +# per-user ~/.avrduderc or avrdude.rc entry and the usbsn = "..."; # field added to distinguish between them. # # Note that the pin numbers for the main ISP signals (reset, sck, @@ -935,7 +948,7 @@ programmer # See also https://ftdichip.com/wp-content/uploads/2020/07/DS_FT2232H.pdf programmer - id = "ft2232h", "avrftdi", "2232h"; + id = "avrftdi", "2232h"; desc = "FT2232H/D based generic programmer"; type = "avrftdi"; prog_modes = PM_TPI | PM_ISP; @@ -950,6 +963,15 @@ programmer sdi = 2; # AD2 (TDO) ; +#------------------------------------------------------------ +# ft2232h +#------------------------------------------------------------ + +programmer parent "2232h" + id = "ft2232h"; + is_serialadapter = yes; +; + #------------------------------------------------------------ # 2232HIO #------------------------------------------------------------ @@ -957,7 +979,7 @@ programmer # This is an implementation of the above with a buffer IC (74AC244) and # 4 LEDs directly attached, all active low. -programmer parent "ft2232h" +programmer parent "2232h" id = "2232hio"; desc = "2232hio based on FT2232H with buffer and LEDs"; buff = ~4; @@ -975,7 +997,7 @@ programmer parent "ft2232h" # Tigard - FT2232H based multi-protocol tool for hardware hacking # https://github.com/tigard-tools/tigard -programmer parent "ft2232h" +programmer parent "2232h" id = "tigard"; desc = "Tigard interface board"; usbdev = "B"; @@ -991,7 +1013,7 @@ programmer parent "ft2232h" # Adds a buffer and a LED indicating that the programming is in progress. # https://www.kanda.com/products/Kanda/AVRISP-U.html -programmer parent "ft2232h" +programmer parent "2232h" id = "avrisp-u"; desc = "Kanda AVRISP-U"; usbsn = "AVR"; @@ -1028,7 +1050,17 @@ programmer # device ID of 0x6011 programmer parent "ft2232h" - id = "ft4232h", "4232h"; + id = "ft4232h"; + desc = "FT4232H based generic programmer"; + usbpid = 0x6011; +; + +#------------------------------------------------------------ +# 4232h +#------------------------------------------------------------ + +programmer parent "2232h" + id = "4232h"; desc = "FT4232H based generic programmer"; usbpid = 0x6011; ; @@ -1067,6 +1099,7 @@ programmer desc = "FT232H based generic programmer"; type = "avrftdi"; prog_modes = PM_TPI | PM_ISP; + is_serialadapter = yes; connection_type = usb; usbvid = 0x0403; usbpid = 0x6014; @@ -1113,6 +1146,7 @@ programmer programmer parent "ft232h" id = "um232h"; desc = "UM232H module from FTDI"; + is_serialadapter = no; ; #------------------------------------------------------------ @@ -1127,7 +1161,7 @@ programmer parent "ft232h" # Use the -b flag to set the SPI clock rate eg -b 3750000 is the fastest I could get # a 16MHz Atmega1280 to program reliably. The 232H is conveniently 5V tolerant. -programmer parent "ft232h" +programmer parent "um232h" id = "c232hm"; desc = "C232HM cable from FTDI"; ; @@ -1205,7 +1239,7 @@ programmer # First SPI connector # User manual: https://www.tiaowiki.com/w/TIAO_USB_Multi_Protocol_Adapter_User%27s_Manual -programmer parent "ft2232h" +programmer parent "2232h" id = "tumpa"; desc = "TIAO USB Multi-Protocol Adapter"; usbpid = 0x8a98; @@ -1582,7 +1616,10 @@ programmer desc = "FT232R based generic programmer"; type = "ftdi_syncbb"; prog_modes = PM_TPI | PM_ISP; + is_serialadapter = yes; connection_type = usb; + usbvid = 0x0403; # For use as serial adapter + usbpid = 0x6001; # " reset = 4; # DTR sck = 0; # TxD sdo = 2; # RTS @@ -1740,7 +1777,6 @@ programmer usbpid = 0x05dc; # Obdev's free shared PID usbvendor = "www.fischl.de"; usbproduct = "USBasp"; - # Old usbasp from fischl.de: # usbvid = 0x03EB; # ATMEL # usbpid = 0xC7B4; # (unoffical) USBasp @@ -1949,6 +1985,7 @@ programmer desc = "ch341a programmer (AVR must have minimum F_CPU of 6.8 MHz)"; type = "ch341a"; prog_modes = PM_ISP; + is_serialadapter = yes; connection_type = usb; usbvid = 0x1a86; usbpid = 0x5512; @@ -2896,6 +2933,40 @@ programmer hvupdi_support = 1; ; +# +# SERIAL ADAPTER DEFINITIONS +# + +# A serialadapter is a programmer that has only USB parameters defined; it +# can be used for a -P [:] port +# specification instead of the created serial port. Per-user serialadapter +# definitions in ~/.avrduderc or avrdude.rc files can add a serial number +# to assign a particular board a specific id and default upload baud rate: +# +# serialadapter parent "ft232r" +# id = "bike-shed-door"; +# usbsn = "0123456789"; +# baudrate = 250000; +# ; +# +# This is particularly useful for uploading to a bootloader as it allows +# specifying the port as -P bike-shed-door rather than having to figure +# out which serial port name the operating system has assigned to the +# plugged in bike-shed-door board at runtime. Note that each programmer +# that defines usbpid and sets is_serialadapter = yes can also be utilised +# as a serialadapter. + +#------------------------------------------------------------ +# ch340 +#------------------------------------------------------------ + +serialadapter + id = "ch340"; + desc = "WCH CH340 USB to serial adapter"; + usbvid = 0x1a86; + usbpid = 0x7523; +; + # # PART DEFINITIONS # diff --git a/src/config.c b/src/config.c index 9d2c790e..c6ea0cff 100644 --- a/src/config.c +++ b/src/config.c @@ -68,6 +68,7 @@ Component_t avr_comp[] = { // PROGRAMMER pgm_comp_desc(desc, COMP_STRING), pgm_comp_desc(prog_modes, COMP_INT), + pgm_comp_desc(is_serialadapter, COMP_INT), pgm_comp_desc(extra_features, COMP_INT), pgm_comp_desc(baudrate, COMP_INT), pgm_comp_desc(usbvid, COMP_INT), @@ -570,7 +571,7 @@ void capture_lvalue_kw(const char *kw, int lineno) { } } - if(str_eq(kw, "programmer") || str_eq(kw, "part") || str_eq(kw, "memory")) + if(str_eq(kw, "programmer") || str_eq(kw, "serialadapter") || str_eq(kw, "part") || str_eq(kw, "memory")) kw = "*"; // Show comment before programmer/part/memory if(lkw) diff --git a/src/config_gram.y b/src/config_gram.y index 0b62c216..441fa863 100644 --- a/src/config_gram.y +++ b/src/config_gram.y @@ -258,7 +258,7 @@ prog_def : yyerror("required parameter id not specified"); YYABORT; } - if (current_prog->initpgm == NULL) { + if (current_prog->initpgm == NULL && current_prog->prog_modes) { yyerror("programmer type not specified"); YYABORT; } diff --git a/src/developer_opts.c b/src/developer_opts.c index ea067111..12920fb6 100644 --- a/src/developer_opts.c +++ b/src/developer_opts.c @@ -140,76 +140,6 @@ static void printallopcodes(const AVRPART *p, const char *d, OPCODE * const *opa // Programming modes -/* - * p->flags no longer used for programming modes, use p->prog_modes - * - - remove this comment in 2023 - -static char *prog_modes_str_flags(const AVRPART *p) { - static char type[1024]; - - *type = 0; - - if(!(p->flags & AVRPART_HAS_TPI) // TPI devices don't have the SPM opcode - && !str_eq(p->id, "t4") // Nor have these early ones - && !str_eq(p->id, "t5") - && !str_eq(p->id, "t9") - && !str_eq(p->id, "t10") - && !str_eq(p->id, "t11") - && !str_eq(p->id, "t12") - && !str_eq(p->id, "t15") - && !str_eq(p->id, "t20") - && !str_eq(p->id, "t26") - && !str_eq(p->id, "t28") - && !str_eq(p->id, "t40")) - strcpy(type, "PM_SPM"); - - switch(p->flags & (AVRPART_HAS_PDI | AVRPART_AVR32 | AVRPART_HAS_TPI | AVRPART_HAS_UPDI)) { - case AVRPART_HAS_TPI: // AVR8L family - strcat(type, "|PM_TPI"); - break; - case 0: // AVR8 family, "classic" parts - if(p->flags & AVRPART_SERIALOK) // ATmega406 has no ISP - strcat(type, "|PM_ISP"); - break; - case AVRPART_HAS_PDI: // AVR8_XMEGA family - strcat(type, "|PM_PDI"); - break; - case AVRPART_HAS_UPDI: // AVR8X family - strcat(type, "|PM_UPDI"); - break; - case AVRPART_AVR32: // AVR32 family - strcat(type, "|PM_aWire"); - break; - default: - strcat(type, "|PM_UNKNOWN"); - } - - switch(p->ctl_stack_type) { - case CTL_STACK_PP: - strcat(type, "|PM_HVPP"); - break; - case CTL_STACK_HVSP: - strcat(type, "|PM_HVSP"); - break; - default: - break; - } - - if(p->flags & AVRPART_HAS_DW) - strcat(type, "|PM_debugWIRE"); - - if(p->flags & AVRPART_HAS_JTAG) - strcat(type, "|PM_JTAG"); - - return type + (*type == '|'); -} - - * - */ - - static char *prog_modes_str(int pm) { static char type[1024]; @@ -450,6 +380,10 @@ static int intcmp(int a, int b) { return a-b; } +static int boolcmp(int a, int b) { + return !!a-!!b; +} + // Deep copies for comparison and raw output @@ -1359,10 +1293,11 @@ static void dev_pgm_strct(const PROGRAMMER *pgm, bool tsv, const PROGRAMMER *bas if(cp) dev_print_comment(cp->comms); + const char *prog_sea = is_programmer(pgm)? "programmer": is_serialadapter(pgm)? "serialadapter": "programmer"; if(pgm->parent_id && *pgm->parent_id) - dev_info("programmer parent \"%s\"\n", pgm->parent_id); + dev_info("%s parent \"%s\"\n", prog_sea, pgm->parent_id); else - dev_info("programmer\n"); + dev_info("%s\n", prog_sea); } if(tsv) @@ -1390,6 +1325,7 @@ static void dev_pgm_strct(const PROGRAMMER *pgm, bool tsv, const PROGRAMMER *bas if(!base || base->initpgm != pgm->initpgm) _pgmout_fmt("type", "\"%s\"", locate_programmer_type_id(pgm->initpgm)); _if_pgmout_str(intcmp, cfg_strdup("dev_pgm_strct()", prog_modes_str(pgm->prog_modes)), prog_modes); + _if_pgmout_str(boolcmp, cfg_strdup("dev_pgm_strct()", pgm->is_serialadapter? "yes": "no"), is_serialadapter); _if_pgmout_str(intcmp, cfg_strdup("dev_pgm_strct()", extra_features_str(pgm->extra_features)), extra_features); if(!base || base->conntype != pgm->conntype) _pgmout_fmt("connection_type", "%s", connstr(pgm->conntype)); diff --git a/src/doc/avrdude.texi b/src/doc/avrdude.texi index e3e0f48e..9011bbfa 100644 --- a/src/doc/avrdude.texi +++ b/src/doc/avrdude.texi @@ -2736,6 +2736,7 @@ the executable. @menu * AVRDUDE Defaults:: * Programmer Definitions:: +* Serial Adapter Definitions:: * Part Definitions:: * Other Notes:: @end menu @@ -2775,7 +2776,7 @@ Whether or not AVRDUDE's interactive terminal is allowed to use subshell rare case @code{avrdude -t} is set up with attached hardware to provide a web service, remote ssh or a login on a PC instead of a shell, say, for demo or training purposes. In almost all other cases this can be -overridden in the personal @code{avrddude.rc} or @code{.avrduderc} +overridden in the per-user @code{avrddude.rc} or @code{.avrduderc} configuration file with @var{yes}. @end table @@ -2784,7 +2785,8 @@ configuration file with @var{yes}. @c @c Node @c -@node Programmer Definitions, Part Definitions, AVRDUDE Defaults, Configuration File +@node Programmer Definitions, Serial Adapter Definitions, AVRDUDE Defaults, Configuration File +@cindex @code{programmer} @section Programmer Definitions @noindent @@ -2796,22 +2798,27 @@ programmer id = [, ... ] ; # are quoted strings desc = ; # quoted string type = ; # programmer type, quoted string - # supported types can be listed by "-c ?type" - prog_modes = PM_ @{ | PM_ @} # interfaces, e.g., PM_SPM|PM_PDI + # list known types with -c ?type + prog_modes = PM_ @{| PM_@} # interfaces, e.g., PM_SPM|PM_PDI (1) + extra_features = HAS_ @{| HAS_@} # extra features, e.g., HAS_SUFFER (2) connection_type = parallel | serial | usb | spi baudrate = ; # baudrate for avr910-programmer - vcc = [, ... ] ; # pin number(s) + vcc = [, ... ] ; # pin number(s) (3) buff = [, ... ] ; # pin number(s) reset = ; # pin number sck = ; # pin number sdo = ; # pin number sdi = ; # pin number + tck = ; # pin number + tdi = ; # pin number + tdo = ; # pin number + tms = ; # pin number errled = ; # pin number rdyled = ; # pin number pgmled = ; # pin number vfyled = ; # pin number - usbvid = ; # USB VID (Vendor ID) - usbpid = [, ...] ; # USB PID (Product ID) + usbvid = ; # USB vendor ID + usbpid = [, ...] ; # USB product ID (4) usbdev = ; # USB interface or other device info usbvendor = ; # USB Vendor Name usbproduct = ; # USB Product Name @@ -2825,7 +2832,12 @@ If a parent is specified, all settings of it (except its ids) are used for the n programmer. These values can be changed by new setting them for the new programmer. @noindent -Known programming modes are +@strong{Notes} + +@enumerate + +@item Known programming modes are + @itemize @bullet @item @code{PM_SPM}: Bootloaders, self-programming with SPM opcodes or NVM Controllers @item @code{PM_TPI}: Tiny Programming Interface (t4, t5, t9, t10, t20, t40, t102, t104) @@ -2842,12 +2854,29 @@ Known programming modes are @item @code{PM_aWire}: AVR32 parts @end itemize -@noindent -To invert a bit in the pin definitions, use @code{= ~ }. To invert a pin list -(all pins get inverted) use @code{~ ( [, ... ] )}. +@item The following extra programmer features are known -@noindent -Not all programmer types can handle a list of USB PIDs. +@itemize @bullet +@item @code{HAS_SUFFER}: Only present on Xplained Mini/Nano programmers; + the Super User Fantastic Feature Enable Register allows the user to modify + the behavior of the mEDBG programmer/debugger chip, see the Xplained Mini/Nano + documentation for more information +@item @code{HAS_VTARG_SWITCH}: Programer has a programmable target power switch +@item @code{HAS_VTARG_READ}: Programmer can read the target voltage +@item @code{HAS_VTARG_ADJ}: Programmer has an adjustable target power source that can + be controlled with Avrdude +@item @code{HAS_FOSC_ADJ}: Programmer has a programable frequency generator that + can clock an AVR directly through its XTAL1 pin +@item @code{HAS_VAREF_ADJ}: Programmer has an adjustable analog reference voltage that + can be controlled with Avrdude +@end itemize + +@item To invert the polarity of a pin, use a tilde @code{~}; to invert +the polarity of all pins in a list use @code{~( [, ... ])} + +@item Not all programmer types can handle a list of USB PIDs + +@end enumerate @noindent The following programmer types are currently implemented: @@ -2859,7 +2888,53 @@ The following programmer types are currently implemented: @c @c Node @c -@node Part Definitions, Other Notes, Programmer Definitions, Configuration File +@node Serial Adapter Definitions, Part Definitions, Programmer Definitions, Configuration File +@cindex @code{serialadapter} +@section Serial Adapter Definitions + +@noindent +The format of a serial adapter definition is as follows: + +@smallexample +serialadapter + parent # optional serialadapter or programmer parent + id = [, ... ] ; # are quoted strings + desc = ; # quoted string + baudrate = ; # optional default baudrate, eg, in .avrduderc + usbvid = ; # USB vendor ID + usbpid = [, ...] ; # list of USB product IDs + usbsn = ; # USB Serial Number in per-user .avrduderc +; +@end smallexample + +Technically, a @code{serialadapter} is implemented as @code{programmer} +that has only USB parameters defined. It can be used for a @code{-P +[:]} port specification instead of the +created serial port. Per-user serialadapter definitions in +@code{~/.avrduderc} or @code{avrdude.rc} files can add a serial number to +assign a particular board a specific id and default upload baud rate: + +@smallexample +serialadapter parent "ft232r" + id = "bike-shed-door"; + usbsn = "0123456789"; + baudrate = 250000; +; +@end smallexample + +@noindent +This is particularly useful for uploading to a bootloader as it allows +specifying the port as @code{-P bike-shed-door} rather than having to +figure out which serial port name the operating system has assigned to the +plugged in bike-shed-door board at runtime. Note that each programmer that +defines @code{usbpid} and sets @code{is_serialadapter = yes} can also be +utilised as a serialadapter. + +@c +@c Node +@c +@node Part Definitions, Other Notes, Serial Adapter Definitions, Configuration File +@cindex @code{part} @section Part Definitions @smallexample @@ -3003,7 +3078,7 @@ arithemtic and bitwise operators. @noindent Parts can also inherit parameters from previously defined parts using -the following syntax. In this case specified integer and string values +the following syntax. In this case specified integer and string values override parameter values from the parent part. New memory definitions are added to the definitions inherited from the parent. If, however, a new memory definition refers to an existing one of the same name for @@ -3023,7 +3098,7 @@ Example format for part inheritance: part parent # String identifying parent id = ; # Id string for new part - ; + ; @end smallexample @c @@ -3827,17 +3902,10 @@ Problem: I'm not using Linux and my AVR910 programmer is really slow. Solutions: The reasons for this are the same as above. If you know how to work around this on your OS, please let us know. -@item -Problem: Updating the flash ROM from terminal mode does not work with the -JTAG ICEs. - -Solution: None at this time. Currently, the JTAG ICE code cannot -write to the flash ROM one byte at a time. - @item Problem: Page-mode programming the EEPROM (using the -U option) does -not erase EEPROM cells before writing, and thus cannot overwrite any -previous value != 0xff. +not erase EEPROM cells before writing, and thus cannot necessarily overwrite +previous values that are different to 0xff. Solution: None. This is an inherent feature of the way JTAG EEPROM programming works, and is documented that way in the Atmel AVR diff --git a/src/lexer.l b/src/lexer.l index e064e3cd..2daa809e 100644 --- a/src/lexer.l +++ b/src/lexer.l @@ -148,7 +148,7 @@ INF [Ii][Nn][Ff]([Ii][Nn][Ii][Tt][Yy])? } -(?x: desc | prog_modes | extra_features | baudrate | usbvid | usbdev | usbsn | usbvendor | usbproduct | +(?x: desc | prog_modes | is_serialadapter | extra_features | baudrate | usbvid | usbdev | usbsn | usbvendor | usbproduct | family_id | mcuid | n_interrupts | n_page_erase | n_boot_sections | boot_section_size | hvupdi_variant | stk500_devcode | avr910_devcode | chip_erase_delay | pagel | bs2 | timeout | stabdelay | cmdexedelay | synchloops | bytedelay | pollindex | pollvalue | predelay | postdelay | pollmethod | @@ -224,7 +224,7 @@ part { yylval=NULL; ccap(); current_strct = COMP_AVRPART; return K_P pgm_enable { yylval=new_token(K_PGM_ENABLE); ccap(); return K_PGM_ENABLE; } pgmled { yylval=NULL; ccap(); return K_PGMLED; } pp_controlstack { yylval=NULL; ccap(); return K_PP_CONTROLSTACK; } -programmer { yylval=NULL; ccap(); current_strct = COMP_PROGRAMMER; return K_PROGRAMMER; } +(programmer|serialadapter) { yylval=NULL; ccap(); current_strct = COMP_PROGRAMMER; return K_PROGRAMMER; } rdyled { yylval=NULL; ccap(); return K_RDYLED; } read { yylval=new_token(K_READ); ccap(); return K_READ; } read_hi { yylval=new_token(K_READ_HI); ccap(); return K_READ_HI; } diff --git a/src/libavrdude.h b/src/libavrdude.h index cabd276c..f52b7793 100644 --- a/src/libavrdude.h +++ b/src/libavrdude.h @@ -753,6 +753,7 @@ typedef struct programmer_t { LISTID comments; // Used by developer options -c*/[ASsr...] const char *parent_id; // Used by developer options int prog_modes; // Programming interfaces, see #define PM_... + int is_serialadapter; // Programmer is also a serialadapter int extra_features; struct pindef_t pin[N_PINS]; conntype_t conntype; @@ -851,6 +852,12 @@ typedef struct programmer_t { char flag; // For use by pgm->initpgm() } PROGRAMMER; +typedef PROGRAMMER SERIALADAPTER; // Only a subset is needed for serial adapters +int is_programmer(const PROGRAMMER *p); +int is_serialadapter(const SERIALADAPTER *p); +void list_serialadapters(FILE *fp, const char *prefix, LISTID programmers); +void serialadapter_not_found(const char *sea_id); + #define NO_PIN (PIN_MAX + 1U) // Magic pinno[] value for unused pins #ifdef __cplusplus diff --git a/src/main.c b/src/main.c index 06e7b034..98586147 100644 --- a/src/main.c +++ b/src/main.c @@ -298,6 +298,8 @@ static void list_programmers(FILE *f, const char *prefix, LISTID programmers, in // Compute max length of programmer names for(ln1 = lfirst(programmers); ln1; ln1 = lnext(ln1)) { pgm = ldata(ln1); + if(!is_programmer(pgm)) + continue; for(ln2=lfirst(pgm->id); ln2; ln2=lnext(ln2)) if(!pm || !pgm->prog_modes || (pm & pgm->prog_modes)) { const char *id = ldata(ln2); @@ -310,6 +312,8 @@ static void list_programmers(FILE *f, const char *prefix, LISTID programmers, in for(ln1 = lfirst(programmers); ln1; ln1 = lnext(ln1)) { pgm = ldata(ln1); + if(!is_programmer(pgm)) + continue; for(ln2=lfirst(pgm->id); ln2; ln2=lnext(ln2)) { // List programmer if pm or prog_modes uninitialised or if they are compatible otherwise if(!pm || !pgm->prog_modes || (pm & pgm->prog_modes)) { @@ -1018,6 +1022,8 @@ int main(int argc, char * argv []) AVRPART *p = ldata(ln1); for(LNODEID ln2 = lfirst(programmers); ln2; ln2 = lnext(ln2)) { PROGRAMMER *pgm = ldata(ln2); + if(!is_programmer(pgm)) + continue; const char *pnam = pgm->id? ldata(lfirst(pgm->id)): "???"; int pm = pgm->prog_modes & p->prog_modes; if((pm & (pm-1)) && !str_eq(pnam, "dryrun")) @@ -1029,7 +1035,7 @@ int main(int argc, char * argv []) if(str_eq(partdesc, "?")) { if(pgmid && *pgmid && explicit_c) { PROGRAMMER *pgm = locate_programmer_set(programmers, pgmid, &pgmid); - if(!pgm) { + if(!pgm || !is_programmer(pgm)) { programmer_not_found(pgmid); exit(1); } @@ -1078,7 +1084,7 @@ int main(int argc, char * argv []) } pgm = locate_programmer_set(programmers, pgmid, &pgmid); - if (pgm == NULL) { + if (pgm == NULL || !is_programmer(pgm)) { programmer_not_found(pgmid); exit(1); } diff --git a/src/pgm.c b/src/pgm.c index 8e4ab69b..7863906f 100644 --- a/src/pgm.c +++ b/src/pgm.c @@ -364,3 +364,12 @@ void sort_programmers(LISTID programmers) lsort(programmers,(int (*)(void*, void*)) sort_programmer_compare); } + +// Soft assignment: some struct programmer_t entries can be both programmers and serial adapters +int is_programmer(const PROGRAMMER *p) { + return p && p->id && lsize(p->id) && p->prog_modes && p->initpgm; +} + +int is_serialadapter(const SERIALADAPTER *p) { + return p && p->id && lsize(p->id) && p->usbpid && lsize(p->usbpid) && (!p->prog_modes || p->is_serialadapter); +} diff --git a/src/serialadapter.c b/src/serialadapter.c new file mode 100644 index 00000000..ef81cc4f --- /dev/null +++ b/src/serialadapter.c @@ -0,0 +1,75 @@ +/* + * AVRDUDE - A Downloader/Uploader for AVR device programmers + * Copyright (C) 2023 Stefan Rueger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "ac_cfg.h" +#include +#include +#include + +#include "avrdude.h" +#include "libavrdude.h" + +void list_serialadapters(FILE *fp, const char *prefix, LISTID programmers) { + LNODEID ln1, ln2, ln3; + SERIALADAPTER *sea; + int maxlen=0, len; + + sort_programmers(programmers); + + // Compute max length of serial adapter names + for(ln1 = lfirst(programmers); ln1; ln1 = lnext(ln1)) { + sea = ldata(ln1); + if(!is_serialadapter(sea)) + continue; + for(ln2=lfirst(sea->id); ln2; ln2=lnext(ln2)) { + const char *id = ldata(ln2); + if(*id == 0 || *id == '.') + continue; + if((len = strlen(id)) > maxlen) + maxlen = len; + } + } + + for(ln1 = lfirst(programmers); ln1; ln1 = lnext(ln1)) { + sea = ldata(ln1); + if(!is_serialadapter(sea)) + continue; + for(ln2=lfirst(sea->id); ln2; ln2=lnext(ln2)) { + const char *id = ldata(ln2); + if(*id == 0 || *id == '.') + continue; + fprintf(fp, "%s%-*s = [usbvid 0x%04x, usbpid", prefix, maxlen, id, sea->usbvid); + for(ln3=lfirst(sea->usbpid); ln3; ln3=lnext(ln3)) + fprintf(fp, " 0x%04x", *(int *) ldata(ln3)); + if(sea->usbsn && *sea->usbsn) + fprintf(fp, ", usbsn %s", sea->usbsn); + fprintf(fp, "]\n"); + } + } +} + + +void serialadapter_not_found(const char *sea_id) { + msg_error("\v"); + if(sea_id && *sea_id) + pmsg_error("cannot find serial adapter id %s\n", sea_id); + + msg_error("\nValid serial adapters are:\n"); + list_serialadapters(stderr, " ", programmers); + msg_error("\n"); +}