libusb / libusb

A cross-platform library to access USB devices
https://libusb.info
GNU Lesser General Public License v2.1
5.1k stars 1.88k forks source link

Add code sample for hotplug fallback #1498

Open fabiensanglard opened 1 month ago

fabiensanglard commented 1 month ago

This CL illustrates how to fallback on systems without support for hotplug. Implemented using pure libusb (no native dependencies).

fabiensanglard commented 1 month ago

Hello @mcuee & @tormodvolden and libusb reviewers. Please take a look when you get a chance.

I think it would be useful to have an "official" code sample for system not supporting hotplub. At least I wish there would have been one when I started working on the Windows version of our software.

Windows: PR #1406 is being authored. It will add hotplug support for Windows but we don't know yet how long it will take to review. And after that it still have to be released. In the meantime, I feel this could be useful for users to know how to fallback.

Other systems: Some systems may never get it implemented. This code sample could be a starting point.

mcuee commented 1 month ago

@fabiensanglard

Thanks for the contribution. I think you need to modify the following file for auto-tools build as well. https://github.com/libusb/libusb/blob/master/examples/Makefile.am

Just wondering if it is possible to use pure C and not C++. In that case, the modification to the above file will be much more simpler.

fabiensanglard commented 1 month ago

I think you need to modify the following file for auto-tools build as well.

Done. How can I test my change works on this file?

Just wondering if it is possible to use pure C and not C++. In that case, the modification to the above file will be much more simpler.

I tried to write in in plain C but it is much more cleaner and concise to use std::thread and std::unordered_map.

mcuee commented 1 month ago

I think you need to modify the following file for auto-tools build as well.

Done. How can I test my change works on this file?

You can see github action run fails, so you know your fix does not work. The current script only takes care of plain C examples. That was why I mentioned the following.

Just wondering if it is possible to use pure C and not C++. In that case, the modification to the above file will be much more simpler.

I tried to write in in plain C but it is much more cleaner and concise to use std::thread and std::unordered_map.

I understand. Let's see if @tormodvolden likes to have C++ examples in github repo or not. I am fine with having C++ examples but you need to fix the build script.

mcuee commented 1 month ago

First test under Windows 10 using VS2019 x64 debug build.

The output seems to be correct when I remove and insert back the external Ugreen USB 2.0 hub (with built-in USB to Ethernet adapter and an attached USB device).

Hotplug capabilities is NOT supported on this platform. Using fallback!
Device added:25013987836936
Device added:4554129408517
Device added:13032341308166
Device added:13030999130883
Device added:4553323840782
Device added:71728913843463
Device added:141317487857158
Device added:40330822353163
Device added:4553324102152
Device added:13032348910082
Device added:13031006733313
Device added:42981081154307
Device added:13032007533577
Device added:141315755802624
Device added:71726507950860
Device added:11391733991941
Device added:141313382023168
Device added:12736577339655
Device added:141313380646912
Device added:4946734219778
Device added:13033100477444
Device added:71728913909002
Device added:4869426971661
Device added:6472616902913
Device added:13032423754500
Device removed:25013987836936
Device removed:12736577339655
Device removed:6472616902913
Device added:25013987836936
Device added:12736577339655
Device added:6472616902913

Device lists:

C:\work\libusb\libusb_pr1498\build\v142\x64\Debug [hotplug_fallback ≡]> .\listdevs.exe
16c0:05dc (bus 2, device 11) path: 1.4
0424:5744 (bus 1, device 5) path: 4.3.2
0bda:5413 (bus 1, device 6) path: 2.3
0bda:0413 (bus 1, device 3) path: 4.3
0424:2740 (bus 1, device 14) path: 2.3.2.5
413c:b06e (bus 1, device 7) path: 2.5
8087:0aaa (bus 2, device 6) path: 14
24ae:4057 (bus 1, device 11) path: 2.3.2.1
0424:2744 (bus 1, device 8) path: 2.3.2
0bda:5487 (bus 1, device 2) path: 2
0bda:0487 (bus 1, device 1) path: 4
2717:5013 (bus 2, device 3) path: 3
0bda:402e (bus 1, device 9) path: 2.3.4
8086:a36d (bus 2, device 0)
413c:2107 (bus 1, device 12) path: 2.3.2.3
0a5c:5842 (bus 2, device 5) path: 10
8086:15f0 (bus 1, device 0)
0b95:772b (bus 2, device 10) path: 1.1
8086:15db (bus 3, device 0)
047f:c056 (bus 2, device 2) path: 2
0bda:8153 (bus 1, device 4) path: 4.4
413c:b06f (bus 1, device 10) path: 2.3.5
046d:c077 (bus 1, device 13) path: 2.3.2.4
05e3:0608 (bus 2, device 9) path: 1
0bda:58fd (bus 2, device 4) path: 11
C:\work\libusb\libusb_pr1498\build\v142\x64\Debug [hotplug_fallback ≡]> .\testlibusb.exe
Dev (bus 2, device 11): 16C0 - 05DC speed: 1.5M
  Manufacturer:              www.fischl.de
  Product:                   USBasp
Dev (bus 1, device 5): 0424 - 5744 speed: 5G
Dev (bus 1, device 6): 0BDA - 5413 speed: 480M
Dev (bus 1, device 3): 0BDA - 0413 speed: 5G
Dev (bus 1, device 14): 0424 - 2740 speed: 480M
  Manufacturer:              Microchip Tech
  Product:                   Hub Controller
Dev (bus 1, device 7): 413C - B06E speed: 480M
Dev (bus 2, device 6): 8087 - 0AAA speed: 12M
Dev (bus 1, device 11): 24AE - 4057 speed: 1.5M
  Manufacturer:              SEMICO
  Product:                   USB Keyboard
Dev (bus 1, device 8): 0424 - 2744 speed: 480M
Dev (bus 1, device 2): 0BDA - 5487 speed: 480M
Dev (bus 1, device 1): 0BDA - 0487 speed: 10G
Dev (bus 2, device 3): 2717 - 5013 speed: 12M
  Manufacturer:              MI
  Product:                   Mi Wireless Mouse
Dev (bus 1, device 9): 0BDA - 402E speed: 480M
Dev (bus 2, device 0): 8086 - A36D speed: 5G
Dev (bus 1, device 12): 413C - 2107 speed: 1.5M
  Manufacturer:              DELL
  Product:                   Dell USB Entry Keyboard
Dev (bus 2, device 5): 0A5C - 5842 speed: 480M
Dev (bus 1, device 0): 8086 - 15F0 speed: 10G
Dev (bus 2, device 10): 0B95 - 772B speed: 480M
Dev (bus 3, device 0): 8086 - 15DB speed: 5G
Dev (bus 2, device 2): 047F - C056 speed: 12M
  Manufacturer:              Plantronics
  Product:                   Plantronics Blackwire 3220 Series
Dev (bus 1, device 4): 0BDA - 8153 speed: 5G
Dev (bus 1, device 10): 413C - B06F speed: 480M
Dev (bus 1, device 13): 046D - C077 speed: 1.5M
  Manufacturer:              Logitech
  Product:                   USB Optical Mouse
Dev (bus 2, device 9): 05E3 - 0608 speed: 480M
Dev (bus 2, device 4): 0BDA - 58FD speed: 480M

Another test -- remove and insert back the Dell Type C dock,

C:\work\libusb\libusb_pr1498\build\v142\x64\Debug [hotplug_fallback ≡]> .\hotplug_fallback.exe
Hotplug capabilities is NOT supported on this platform. Using fallback!
Device added:25013987836939
Device added:4554129408517
Device added:13032341308166
Device added:13030999130883
Device added:4553323840782
Device added:71728913843463
Device added:141317487857158
Device added:40330822353163
Device added:4553324102152
Device added:13032348910082
Device added:13031006733313
Device added:42981081154307
Device added:13032007533577
Device added:141315755802624
Device added:71726507950860
Device added:11391733991941
Device added:141313382023168
Device added:12736577339658
Device added:141313380646912
Device added:4946734219778
Device added:13033100477444
Device added:71728913909002
Device added:4869426971661
Device added:6472616902921
Device added:13032423754500
Device removed:13030999130883
Device removed:4554129408517
Device removed:13032341308166
Device removed:4553323840782
Device removed:71728913843463
Device removed:4869426971661
Device removed:40330822353163
Device removed:4553324102152
Device removed:13032348910082
Device removed:71728913909002
Device removed:13031006733313
Device removed:13032007533577
Device removed:71726507950860
Device removed:13033100477444
Device removed:141313382023168
Device added:4554129408517
Device added:13032341308166
Device added:13030999130883
Device added:71728913843463
Device added:13032348910082
Device added:13031006733313
Device added:141313382023168
Device added:13033100477444
Device added:4553323840782
Device added:40330822353163
Device added:4553324102152
Device added:13032007533577
Device added:71726507950860
Device added:71728913909002
Device added:4869426971661
mcuee commented 1 month ago

The above tests show that it seems to work under Windows.

But as an example, I do not quite like the use of an opaque key, why not just print out the Vendor ID, Product ID, Port and Address?

return vendor << 32 | product << 16 | port << 8 | address;
fabiensanglard commented 1 month ago

why not just print out the Vendor ID, Product ID, Port and Address?

Done. Changed for productID and vendorID instead.

fabiensanglard commented 1 month ago

make[2]: *** No rule to make target 'hotplug_fallback.c', needed by 'hotplug_fallback.o'.

Thanks for pointing it out. I can see the build failure but I am not well versed in the art of Makefile.am. I was hoping adding my new file in the Makefile.am would auto-magically work. Looks like I will have to dig and understand who this works.

Although I won't refuse a few pointers :P !

mcuee commented 1 month ago

Although I won't refuse a few pointers :P !

Unfortunately I know little about auto-tools. That was why I suggested to use a C based example, then your modification would have worked.

tormodvolden commented 1 month ago

Your commit fails git show --check.

Adding hotplug_fallback_SOURCES = hotplug_fallback.cc overcomes above errors but then it bombs out:

  CXX      hotplug_fallback.o
cc1plus: warning: ‘-Werror=’ argument ‘-Werror=implicit-function-declaration’ is not valid for C++
cc1plus: warning: ‘-Werror=’ argument ‘-Werror=implicit-int’ is not valid for C++
cc1plus: warning: ‘-Werror=’ argument ‘-Werror=missing-prototypes’ is not valid for C++
cc1plus: warning: ‘-Werror=’ argument ‘-Werror=strict-prototypes’ is not valid for C++
../../libusb-git/examples/hotplug_fallback.cc:41:10: warning: no previous declaration for ‘uint64_t get_key_for(uint64_t, uint64_t, uint64_t, uint64_t)’ [-Wmissing-declarations]
   41 | uint64_t get_key_for(uint64_t vendor, uint64_t product, uint64_t port, uint64_t address) {
      |          ^~~~~~~~~~~
../../libusb-git/examples/hotplug_fallback.cc: In lambda function:
../../libusb-git/examples/hotplug_fallback.cc:105:46: error: ‘chrono_literals’ is not a namespace-name
  105 |                         using namespace std::chrono_literals;
      |                                              ^~~~~~~~~~~~~~~
../../libusb-git/examples/hotplug_fallback.cc:106:53: error: unable to find numeric literal operator ‘operator""s’
  106 |                         std::this_thread::sleep_for(2s);
      |                                                     ^~
../../libusb-git/examples/hotplug_fallback.cc: In lambda function:
../../libusb-git/examples/hotplug_fallback.cc:115:23: warning: declaration of ‘rc’ shadows a previous local [-Wshadow]
  115 |                   int rc = libusb_handle_events(nullptr);
      |                       ^~
../../libusb-git/examples/hotplug_fallback.cc:46:13: note: shadowed declaration is here
   46 |         int rc = libusb_init_context(nullptr, nullptr, 0);
      |             ^~
make[2]: *** [Makefile:526: hotplug_fallback.o] Error 1

I would prefer pure C for examples, but if it doesn't make sense because the corresponding C program becomes a lot more complex, C++ would be acceptable too.

fabiensanglard commented 1 month ago

Looks like std::chrono_literals is not there. I guess we don't compile against C++14?

tormodvolden commented 1 month ago

Yes, adding AM_CXXFLAGS += -std=c++14 fixes this and it builds completely. There are warnings that should be taken care of:

  CXX      hotplug_fallback.o
cc1plus: warning: ‘-Werror=’ argument ‘-Werror=implicit-function-declaration’ is not valid for C++
cc1plus: warning: ‘-Werror=’ argument ‘-Werror=implicit-int’ is not valid for C++
cc1plus: warning: ‘-Werror=’ argument ‘-Werror=missing-prototypes’ is not valid for C++
cc1plus: warning: ‘-Werror=’ argument ‘-Werror=strict-prototypes’ is not valid for C++
../../libusb-git/examples/hotplug_fallback.cc:41:10: warning: no previous declaration for ‘uint64_t get_key_for(uint64_t, uint64_t, uint64_t, uint64_t)’ [-Wmissing-declarations]
   41 | uint64_t get_key_for(uint64_t vendor, uint64_t product, uint64_t port, uint64_t address) {
      |          ^~~~~~~~~~~
../../libusb-git/examples/hotplug_fallback.cc: In lambda function:
../../libusb-git/examples/hotplug_fallback.cc:115:23: warning: declaration of ‘rc’ shadows a previous local [-Wshadow]
  115 |                   int rc = libusb_handle_events(nullptr);
      |                       ^~
../../libusb-git/examples/hotplug_fallback.cc:46:13: note: shadowed declaration is here
   46 |         int rc = libusb_init_context(nullptr, nullptr, 0);
      |             ^~
  CXXLD    hotplug_fallback

Suffice to say, using C++ adds to the maintainer burden.

fabiensanglard commented 1 month ago

Thanks a lot for your help @tormodvolden!

Should I add AM_CXXFLAGS += -std=c++14 to both libusb/Makefile.am and configure.ac or just one of them?

Also, I am unclear where I should add hotplug_fallback_SOURCES = hotplug_fallback.cc

I understand we may not want to merge this PR, it is indeed a burdain. What about I publish this code sample on my personal website? Or we put it somewhere in the documentation? As long as it is somewhere people can find it, I am good with any solution.

tormodvolden commented 1 month ago

They both go, and are only needed, in examples/Makefile.am

tormodvolden commented 1 month ago

Yes, it is always great to have more example libusb code, but I am reluctant to add more build dependencies to our build, and the C++ code demands more from the maintainers too. As you may have noticed we have some C++ code already, but it is limited to some backends for which we have to rely on community contributions.

tormodvolden commented 1 month ago

I just added those Makefile.am fixes to get the CI going. Feel free to drop or squash.

Now on macOS:

../../examples/hotplug_fallback.cc:41:10: error: no previous prototype for function 'get_key_for' [-Werror,-Wmissing-prototypes]
uint64_t get_key_for(uint64_t vendor, uint64_t product, uint64_t port, uint64_t address) {
         ^
../../examples/hotplug_fallback.cc:41:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
uint64_t get_key_for(uint64_t vendor, uint64_t product, uint64_t port, uint64_t address) {
^
static 
  CCLD     testlibusb
1 error generated.
make[2]: *** [hotplug_fallback.o] Error 1
tormodvolden commented 1 month ago

I think that last configure.ac fix is something we should pick in any case, I'll make a separate merge request for that one.

tormodvolden commented 1 month ago

Now it only fails on Linux because the CI container build for umockdev doesn't have a C++ compiler...

An "unreachable code" warning breaks the VS2015 Win32 Release build. VS2013 fails on all build variants.

mcuee commented 1 month ago

Now it only fails on Linux because the CI container build for umockdev doesn't have a C++ compiler...

An "unreachable code" warning breaks the VS2015 Win32 Release build. VS2013 fails on all build variants.

I think we can drop VS2013 build now as Microsoft drops the support on 09 Apr 2024. VS2015 support will end on 14 Oct 2025.

As for the CI container, maybe we can install g++ there.

mcuee commented 1 month ago

As for the CI container, maybe we can install g++ there.

Done and now Linux CI container build is good.