Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue #973: Differentiate multiple USB programmers of the same VID/PI… #1588

Merged
merged 4 commits into from
Dec 18, 2023

Conversation

MikeRaffa
Copy link
Contributor

…D (libusb or hidapi or libftdi)

Added code for USBasp to check for bus:device match using the -P option. Syntax is -P usb:: (same as current USBTiny implementation).

This also supports serial number check with the alternative -P usb:<serial_number> format (no ':').

In verbose mode, prints out bus/device/serial number for any found USBasps.

Only tested on Linux, but it works with HAVE_LIBUSB_1_0 on or off (there's some slightly different code in the two versions of usbOpenDevice()).

…e VID/PID (libusb or hidapi or libftdi)

Added code for USBasp to check for bus:device match using the -P option. Syntax is -P usb:<bus>:<device> (same as current USBTiny implementation).

This also supports serial number check with the alternative -P usb:<serial_number> format (no ':').

In verbose mode, prints out bus/device/serial number for any found USBasps.

Only tested on Linux, but it works with HAVE_LIBUSB_1_0 on or off (there's some slightly different code in the two versions of usbOpenDevice()).
@mcuee mcuee added the enhancement New feature or request label Dec 4, 2023
@mcuee
Copy link
Collaborator

mcuee commented Dec 4, 2023

@stefanrueger
Copy link
Collaborator

Thanks for submitting a PR!

I'll add a few tips on how to make the code easier to maintain (and read) and harden it against failure. Once that's been addressed it will need testing.

@@ -399,6 +399,37 @@ static int usbasp_transmit(const PROGRAMMER *pgm,
return nbytes;
}

static int check_for_port_argument_match(const char *port, char *bus, char *device, char *serial_num) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function returns a 1 if the port arguments are not matched and 0 if they do. So I suggest renaming the function to port_argument_not_matched().

src/usbasp.c Outdated
return 1;
}
return 0;
} else {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not wrong, but I am not in favour of elsing a return. It feels wrong.

src/usbasp.c Outdated
return 0;
} else {
// serial number case
if (!str_eq(serial_num, port)) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These five lines can be replaced by return !str_eq(serial_num, port);

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... and actually, taking Jörg's comment about matching trailing SNs into account, it would be better to simply use

  return !str_ends(serial_num, port);

or if you don't want an empty serial number by the user to match everything

  return !(*port && str_ends(serial_num, port));

src/usbasp.c Outdated
char *colon_pointer = strchr(port, ':');
if (colon_pointer) {
// Value contains ':' character. Compare with bus/device.
if (strncmp(port, bus, colon_pointer - port)) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is not wrong to use braces here, but it's unnecessary and costs an extra line. I generally prefer code to be crisp, to lessen the need for scrolling for maintenance. Those unnecessary braces appear a few times.

src/usbasp.c Outdated
return 1;
}
port = colon_pointer + 1;
if (strcmp(port, device)) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These 4 lines can be replaced by return !str_eq(port, device);

src/usbasp.c Outdated
if(!str_eq(port, "usb")) {
// -P option given
libusb_get_string_descriptor_ascii(handle, descriptor.iSerialNumber, (unsigned char*)string, sizeof(string));
char bus_num[4];
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uhhm, bus_num needs to have space to hold the ASCII representation of any integer as we don't control what number range libusb_get_bus_number() returns. Worst case could mean 21 characters are needed.

src/usbasp.c Outdated
libusb_get_string_descriptor_ascii(handle, descriptor.iSerialNumber, (unsigned char*)string, sizeof(string));
char bus_num[4];
sprintf(bus_num, "%d", libusb_get_bus_number(dev));
char dev_addr[4];
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here: I suggest char dev_addr[21];

@stefanrueger
Copy link
Collaborator

Apart from a few niggles, the code looks good. Thank you @MikeRaffa. Don't forget to document the new superpower.

@MikeRaffa
Copy link
Contributor Author

Thanks for the feedback! I'll try to look into all those items within the next couple of days.

@dl8dtl
Copy link
Contributor

dl8dtl commented Dec 4, 2023

Question from me: has it been tested on at least two different OSes? It'd be interesting in particular to name some examples in the documentation.
(I'd appreciate if USBasps came with a kind of semi-random serial number to distinguish them, but I accept we won't be able to change the world. Alas.)

@MikeRaffa
Copy link
Contributor Author

I've just tested this on Windows using MYSY2 Mingw64. Seems to work correctly. I am getting this error: "avrdude warning: cannot open USB device: Function not implemented", but avrdude is in fact communicating with the USBasp, so I'm not sure what's up with that.

Change sense of check_for_port_argument_match() to return nonzero when there is a match.

Increase size of 'bus_num' and 'dev_addr' from 4 to 21.

Various cleanup, formatting changes, and simplifications.

Match trailing end of serial numbers.
@mcuee
Copy link
Collaborator

mcuee commented Dec 5, 2023

Working fine under Windows.

USBASP unit 1, snL 6666, connected to ATmega32A
USBASP unit 2, snL 8888, connected to ATmega328PB

PS C:\work\avr\avrdude_test\avrdude_bin> function prompt {$null}
PS>.\avrdude_pr1588 -C .\avrdude_pr1588.conf -c usbasp -p m328pb -P usb:8888
avrdude_pr1588: AVR device initialized and ready to accept instructions
avrdude_pr1588: device signature = 0x1e9516 (probably m328pb)

avrdude_pr1588 done.  Thank you.

PS>.\avrdude_pr1588 -C .\avrdude_pr1588.conf -c usbasp -p m32a -P usb:6666
avrdude_pr1588: AVR device initialized and ready to accept instructions
avrdude_pr1588: device signature = 0x1e9502 (probably m32a)

avrdude_pr1588 done.  Thank you.

@mcuee
Copy link
Collaborator

mcuee commented Dec 5, 2023

The PR is also good for Linux.

USBASP unit 1, snL 6666, connected to ATmega32A
USBASP unit 2, snL 8888, connected to ATmega328PB

mcuee@UbuntuSwift3 $ ./avrdude_pr1588 -C ./avrdude_pr1588.conf -c usbasp -p m328pb -P usb:8888
avrdude_pr1588: AVR device initialized and ready to accept instructions
avrdude_pr1588: device signature = 0x1e9516 (probably m328pb)

avrdude_pr1588 done.  Thank you.

mcuee@UbuntuSwift3 $ ./avrdude_pr1588 -C ./avrdude_pr1588.conf -c usbasp -p m32a -P usb:8888
avrdude_pr1588: AVR device initialized and ready to accept instructions
avrdude_pr1588: device signature = 0x1e9516 (probably m328pb)
avrdude_pr1588 error: expected signature for ATmega32A is 1E 95 02
               double check chip or use -F to override this check

avrdude_pr1588 done.  Thank you.

mcuee@UbuntuSwift3 $ ./avrdude_pr1588 -C ./avrdude_pr1588.conf -c usbasp -p m32a -P usb:6666
avrdude_pr1588: AVR device initialized and ready to accept instructions
avrdude_pr1588: device signature = 0x1e9502 (probably m32a)

avrdude_pr1588 done.  Thank you.

mcuee@UbuntuSwift3 $ ./avrdude_pr1588 -C ./avrdude_pr1588.conf -c usbasp -p m328pb -P usb:6666
avrdude_pr1588: AVR device initialized and ready to accept instructions
avrdude_pr1588: device signature = 0x1e9502 (probably m32)
avrdude_pr1588 error: expected signature for ATmega328PB is 1E 95 16
               double check chip or use -F to override this check

avrdude_pr1588 done.  Thank you.

@stefanrueger
Copy link
Collaborator

I've just tested this on Windows using MYSY2 Mingw64. Seems to work correctly. I am getting this error: "avrdude warning: cannot open USB device: Function not implemented", but avrdude is in fact communicating with the USBasp, so I'm not sure what's up with that.

@MikeRaffa Try running avrdude with -vvv so that the warning tells you the source file and line number of the message. Then you have a sporting chance to see why that warning might come about.

src/usbasp.c Outdated
return str_eq(port, device);
}
// serial number case
return (*port && str_ends(serial_num, port));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Outer parentheses not needed

src/usbasp.c Outdated
sprintf(bus_num, "%d", libusb_get_bus_number(dev));
char dev_addr[21];
sprintf(dev_addr, "%d", libusb_get_device_address(dev));
if (!check_for_port_argument_match(port, bus_num, dev_addr, string)) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unnecessary braces

src/usbasp.c Outdated
// -P option given
usb_get_string_simple(handle, dev->descriptor.iSerialNumber,
string, sizeof(string));
if (!check_for_port_argument_match(port, bus->dirname, dev->filename, string)) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unnecessary braces

src/usbasp.c Outdated
@@ -399,6 +399,28 @@ static int usbasp_transmit(const PROGRAMMER *pgm,
return nbytes;
}

static int check_for_port_argument_match(const char *port, char *bus, char *device, char *serial_num) {

if (verbose) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pmsg_notice() only outputs sth if verbose is one or greater. Hence, the if test is unnecessary

Remove some unnecessary braces and parens.
@MikeRaffa
Copy link
Contributor Author

MikeRaffa commented Dec 7, 2023

This is the output I got with -vvv on Windows. It is correctly reading the signature from the MCU so I'm not sure what to make of that. Maybe something to do with Windows libusb setup? I was getting the same behavior without my changes. Note: this was run with the latest pushed version so the line number (457) reflects that.

$ ./build_mingw64_nt-10.0-22631/src/avrdude.exe -p m128 -c USBasp -vvv -P usb:3

avrdude: Version 7.2-20231201 (5501c63a)
         Copyright the AVRDUDE authors;
         see https://github.com/avrdudes/avrdude/blob/main/AUTHORS

         System wide configuration file is I:\stuff\msys64\home\raffa\avrdude\build_mingw64_nt-10.0-22631\src\avrdude.conf

         Using port            : usb:3
         Using programmer      : usbasp
avrdude: usbasp_open("usb:3")
avrdude usbOpenDevice() [usbasp.c:457] warning: cannot open USB device: Function not implemented
avrdude usbOpenDevice() [usbasp.c:457] warning: cannot open USB device: Function not implemented
avrdude: seen device from vendor >www.fischl.de<
avrdude: seen product >USBasp<
avrdude: usbOpenDevice(): found USBasp, bus:device: 2:32, serial_number: 3
         AVR Part              : ATmega128
         Programming modes     : ISP, HVPP, JTAG, JTAGmkI, SPM

         Memory         Size  Pg size
         ----------------------------
         eeprom         4096        8
         flash        131072      256
         efuse             1        1
         hfuse             1        1
         lfuse             1        1
         lock              1        1
         calibration       4        1
         signature         3        1
         io              224        1
         sram           4096        1

         Variants         Package  F max   T range         V range
         ----------------------------------------------------------------
         ATmega128-16AN   TQFP64   16 MHz  [-40 C, 105 C]  [4.5 V, 5.5 V]
         ATmega128-16ANR  TQFP64   16 MHz  [-40 C, 105 C]  [4.5 V, 5.5 V]
         ATmega128-16AU   TQFP64   16 MHz  [-40 C,  85 C]  [4.5 V, 5.5 V]
         ATmega128-16AUR  TQFP64   16 MHz  [-40 C,  85 C]  [4.5 V, 5.5 V]
         ATmega128-16MN   MLF64    16 MHz  [-40 C, 105 C]  [4.5 V, 5.5 V]
         ATmega128-16MNR  MLF64    16 MHz  [N/A,     N/A]  [4.5 V, 5.5 V]
         ATmega128-16MU   MLF64    16 MHz  [-40 C,  85 C]  [4.5 V, 5.5 V]
         ATmega128-16MUR  MLF64    16 MHz  [-40 C,  85 C]  [4.5 V, 5.5 V]
         ATmega128L-8AN   TQFP64   8 MHz   [-40 C, 105 C]  [3 V,   5.5 V]
         ATmega128L-8ANR  TQFP64   8 MHz   [-40 C, 105 C]  [3 V,   5.5 V]
         ATmega128L-8AU   TQFP64   8 MHz   [-40 C,  85 C]  [2.7 V, 5.5 V]
         ATmega128L-8AUR  TQFP64   8 MHz   [-40 C,  85 C]  [2.7 V, 5.5 V]
         ATmega128L-8MN   MLF64    8 MHz   [-40 C, 105 C]  [3 V,   5.5 V]
         ATmega128L-8MNR  MLF64    8 MHz   [N/A,     N/A]  [2.7 V, 5.5 V]
         ATmega128L-8MU   MLF64    8 MHz   [-40 C,  85 C]  [2.7 V, 5.5 V]
         ATmega128L-8MUR  MLF64    8 MHz   [-40 C,  85 C]  [2.7 V, 5.5 V]

         Programmer Type       : usbasp
         Description           : USBasp ISP and TPI programmer
avrdude: usbasp_initialize()
avrdude: usbasp_spi_set_sck_period(0)
avrdude: auto set sck period (because given equals null)
avrdude: usbasp_program_enable()
avrdude: AVR device initialized and ready to accept instructions
Reading |                                                    | 0% 0.00 s
avrdude: usbasp_spi_cmd(0x30, 0x00, 0x00, 0x00) => 0x00, 0x30, 0x00, 0x1e
avrdude: usbasp_spi_cmd(0x30, 0x00, 0x01, 0x00) => 0x00, 0x30, 0x00, 0x97
Reading | #################                                  | 33% 0.01 s
avrdude: usbasp_spi_cmd(0x30, 0x00, 0x02, 0x00) => 0x00, 0x30, 0x00, 0x02
Reading | ################################################## | 100% 0.02 s
avrdude: device signature = 0x1e9702 (probably m128)
avrdude: usbasp_close()

avrdude done.  Thank you.

@stefanrueger
Copy link
Collaborator

avrdude: usbasp_open("usb:3")
avrdude usbOpenDevice() [usbasp.c:457] warning: cannot open USB device: Function not implemented
avrdude usbOpenDevice() [usbasp.c:457] warning: cannot open USB device: Function not implemented

Interesting. The key seems to be why line 457 of usbasp.c is visited twice... Any idea?

@MikeRaffa
Copy link
Contributor Author

MikeRaffa commented Dec 11, 2023

I was able to get it run cleanly (without that error) by changing the driver to libusbK with the "Zadig" tool.

$ ./avrdude.exe -p m128 -c USBasp -P usb:2 -vvv

avrdude: Version 7.2-20231201 (5501c63a)
         Copyright the AVRDUDE authors;
         see https://github.com/avrdudes/avrdude/blob/main/AUTHORS

         System wide configuration file is I:\stuff\msys64\home\raffa\avrdude\build_mingw64_nt-10.0-22631\src\avrdude.conf

         Using port            : usb:2
         Using programmer      : usbasp
avrdude: usbasp_open("usb:2")
avrdude: seen device from vendor >www.fischl.de<
avrdude: seen product >USBasp<
avrdude: usbOpenDevice(): found USBasp, bus:device: 2:37, serial_number: 2
         AVR Part              : ATmega128
         Programming modes     : ISP, HVPP, JTAG, JTAGmkI, SPM

         Memory         Size  Pg size
         ----------------------------
         eeprom         4096        8
         flash        131072      256
         efuse             1        1
         hfuse             1        1
         lfuse             1        1
         lock              1        1
         calibration       4        1
         signature         3        1
         io              224        1
         sram           4096        1

         Variants         Package  F max   T range         V range
         ----------------------------------------------------------------
         ATmega128-16AN   TQFP64   16 MHz  [-40 C, 105 C]  [4.5 V, 5.5 V]
         ATmega128-16ANR  TQFP64   16 MHz  [-40 C, 105 C]  [4.5 V, 5.5 V]
         ATmega128-16AU   TQFP64   16 MHz  [-40 C,  85 C]  [4.5 V, 5.5 V]
         ATmega128-16AUR  TQFP64   16 MHz  [-40 C,  85 C]  [4.5 V, 5.5 V]
         ATmega128-16MN   MLF64    16 MHz  [-40 C, 105 C]  [4.5 V, 5.5 V]
         ATmega128-16MNR  MLF64    16 MHz  [N/A,     N/A]  [4.5 V, 5.5 V]
         ATmega128-16MU   MLF64    16 MHz  [-40 C,  85 C]  [4.5 V, 5.5 V]
         ATmega128-16MUR  MLF64    16 MHz  [-40 C,  85 C]  [4.5 V, 5.5 V]
         ATmega128L-8AN   TQFP64   8 MHz   [-40 C, 105 C]  [3 V,   5.5 V]
         ATmega128L-8ANR  TQFP64   8 MHz   [-40 C, 105 C]  [3 V,   5.5 V]
         ATmega128L-8AU   TQFP64   8 MHz   [-40 C,  85 C]  [2.7 V, 5.5 V]
         ATmega128L-8AUR  TQFP64   8 MHz   [-40 C,  85 C]  [2.7 V, 5.5 V]
         ATmega128L-8MN   MLF64    8 MHz   [-40 C, 105 C]  [3 V,   5.5 V]
         ATmega128L-8MNR  MLF64    8 MHz   [N/A,     N/A]  [2.7 V, 5.5 V]
         ATmega128L-8MU   MLF64    8 MHz   [-40 C,  85 C]  [2.7 V, 5.5 V]
         ATmega128L-8MUR  MLF64    8 MHz   [-40 C,  85 C]  [2.7 V, 5.5 V]

         Programmer Type       : usbasp
         Description           : USBasp ISP and TPI programmer
avrdude: usbasp_initialize()
avrdude: usbasp_spi_set_sck_period(0)
avrdude: auto set sck period (because given equals null)
avrdude: usbasp_program_enable()
avrdude: AVR device initialized and ready to accept instructions
Reading |                                                    | 0% 0.00 s
avrdude: usbasp_spi_cmd(0x30, 0x00, 0x00, 0x00) => 0x00, 0x30, 0x00, 0x1e
avrdude: usbasp_spi_cmd(0x30, 0x00, 0x01, 0x00) => 0x00, 0x30, 0x00, 0x97
Reading | #################                                  | 33% 0.02 s
avrdude: usbasp_spi_cmd(0x30, 0x00, 0x02, 0x00) => 0x00, 0x30, 0x00, 0x02
Reading | ################################################## | 100% 0.03 s
avrdude: device signature = 0x1e9702 (probably m128)
avrdude: usbasp_close()

avrdude done.  Thank you.

@mcuee
Copy link
Collaborator

mcuee commented Dec 15, 2023

I was able to get it run cleanly (without that error) by changing the driver to libusbK with the "Zadig" tool.

Interesting.

Zadig 2.8 comes with libusb0.sys 1.2.7.3 version, can you try that as well? I suspect that you were using libusb0.sys 1.0.26 version.
https://github.com/pbatard/libwdi/releases/tag/v1.5.0

You can also try WinUSB and I believe it should work as well.

Or you can use the MSVC build which use avrdude's own avrdude-libusb implementation. MinGW build uses libusb-1.0 (eg: USBASP) or libusb-1.0+libusb-compat-0.1 (other programmers).

BTW, latest libusb-win32 version is 1.3.0.1 and you need to use a customized version of Zadig to install it.
https://github.com/mcuee/libusb-win32/releases/tag/snapshot_1.3.0.1

@MikeRaffa
Copy link
Contributor Author

It also ran cleanly with the WinUSB from Zadig 2.8.

@mcuee
Copy link
Collaborator

mcuee commented Dec 17, 2023

It also ran cleanly with the WinUSB from Zadig 2.8.

@MikeRaffa
Thanks. Have you tried to use libusb0.sys 1.2.7.3 from Zadig 2.8?

@MikeRaffa
Copy link
Contributor Author

Worked with that one as well.

@mcuee
Copy link
Collaborator

mcuee commented Dec 17, 2023

Worked with that one as well.

Thanks. Then it should be fine. There are some issues with the older libusb0.sys 1.2.6.0 version with some avrdude programmers. It is great that you can get libusb0.sys 1.2.7.3, libusbK.sys and WinUSB working fine.

@mcuee
Copy link
Collaborator

mcuee commented Dec 17, 2023

This PR looks good to me based on my test results.

@stefanrueger stefanrueger merged commit 79f7035 into avrdudes:main Dec 18, 2023
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Differentiate multiple USB programmers of the same VID/PID (libusb or hidapi or libftdi)
4 participants