-
Notifications
You must be signed in to change notification settings - Fork 68
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
libusb_set_option support #75
Comments
Ref: FYI. I have not been able to get usbdk to work under pyusb yet. |
Something like this on the low level, but I am not so sure how to add the higher level changes.
|
Some updates: I figured out a potential workaround for usbdk. But I do not have the proper fix. The issue may or may not be applicable to python-libusb1. |
It is very unfortunate that libusb chose to add a variadic in their API, as these are basically impossible to wrap with ctypes (I was trying to find a positive mention of this in either the documentation or python code, but fail to - the closest I have is a not-merged, possibly-abandoned merge request to add python's What I did on a previous project was to have a C file with glue functions with fixed arguments (because I knew which forms my ctypes wrapper needed) calling into the variadic. In the case of that module, getting these functions was so essential that I saw no other way. Which means such module now requires a compilation step... There are two reasons why I chose ctypes (as opposed to a C module):
Reading pyusb/pyusb#200 , I kind of agree that this is a ctypes "bug" (I would rather call it an entirely missing feature which gives the illusion of working on some common archs), but IMHO it is also a very poor design decision from libusb1 to use a variadic in their API. Back when |
So it seems libusb_set_option does pose some challenges to python bindings. I am not a programmer myself and I only know a little bit of C and Python. Just wondering if it is possible to split the python binding into different functions.
|
This is definitely possible, but I can understand libusb maintainers not wanting to multiply such functions. Alternatives which would be ABI-call-friendly (but definitely not as good-looking as a sweep-complexity-under-compiler's-rug variadic) and which I can think of (I'm not a seasoned C dev) are:
|
The simplest for now and foreseeable future would be if libusb could keep libusb_set_debug() and not deprecate it. Other than that, libusb has only two other options and they are simple flags without option argument: It is nice for a library to be future-proof and get everything right from the beginning, and the new libusb_set_option() is enormously scalable and elegant with variadic macros, however it is wonderful over-engineering for a problem that libusb doesn't have, and rather should try to avoid (lots of options with various arguments). |
@tormodvolden This seems to be a good suggestion. Therefore I create libusb issue libusb/libusb#990. |
One option is to improve libusb using Env variables. |
I briefly glanced at this as I have an open pull request to libusb that adds options that take a parameter. I was unaware of the python concern. I believe the failure concern may be resolvable for the current implementations, if the maximum number of parameters is always passed. Extra ones will simply be ignored, and I expect libusb could likely document that to make it clear. Some legacy code passes NULL pointers to denote that there are no further parameters. |
I read some more about variadic, and now I wonder why I was under the impression that variadics could cause crashes:
So... was I mistaken entirely and variadic are actually fine, and the python patches are just adding some syntactic sugar ? Or am I still not re-identifying the real issue ? One thing I saw but do not yet understand is that on (at least) x86-64 registers are used in an order which depend on argument type (integer and float, at least), but if variadic follows the same convention as regular calls (and the argument types are correct to begin with, but it is not the kind of issue I am worried about - at least I think) then the order should be consistent with the one expected by the callee. I'll search some more, but another day: I wanted to post an update here quickly. EDIT: fix a few sentence structures and recover a few dropped words |
it looks like small types are promoted to int and double in variadics. so this seems mostly an issue for machines where sizeof(int) != sizeof(void*). I see the maintenance issue. I believe right now my android branch might be the only code that uses the variadic arguments, and it takes a pointer to the java vm for old android apis where it can't reasonably be enumerated. somebody may improve on that code at some point, which then could use an auxiliary function instead of set_option. |
I checked python's ctype code, and while there is code checking the Python 3.10.0 (tags/v3.10.0:b494f59, Oct 4 2021, 18:46:30) [MSC v.1929 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import ctypes
>>> libusb = ctypes.WinDLL(r'libusb-1.0.24\VS2019\MS32\dll\libusb-1.0.dll')
>>> bin(libusb.libusb_set_option._flags_)
'0b0'
>>> bin(libusb.libusb_init._flags_)
'0b0'
>>> c_libusb = ctypes.CDLL(r'libusb-1.0.24\VS2019\MS32\dll\libusb-1.0.dll')
>>> bin(c_libusb.libusb_set_option._flags_)
'0b1'
>>> bin(c_libusb.libusb_init._flags_)
'0b1' Looking at
Getting back from my own off-topic Windows concerns and towards a more concrete solution: I have the option to only fetch
Would they also be promoted on non-variadic |
Thanks for the work you're putting in looking into this.
No, it sounds like this happens only when the types for function parameters are not specified. Here is a link: https://azrael.digipen.edu/~mmead/www/Courses/CS120/VariadicFunctions.html Others here may be more experienced with C than I am. |
So, my current understanding is that
...so maybe it can reliably work ? But my confidence in myself is low. |
all the issues look unlikely to crop up, but it does seem kind of like an advanced call where it's best to understand c variadic functions if using it with new parameters. |
Following the recent libusb 1.0.27 release, I checked the API this module is not wrapping yet, and am happy about the new I do not think I have an android setup to test usb on (I'm not actually sure what is needed... maybe I have ?). Testing and reviews very welcome. |
I do not know how to test libusb for Anrdoid either. But @xloem or @CraigHutchinson should be able to help. Ref: |
I think somebody would need to port this library into android using an android python development framework such as kivy or beeware. This may have already been done in which case the maintainer would have the most experience. EDIT: Mistake, the below information only relates to the above linked non-root PR which is still unmerged. |
I could have a first try, by following https://wiki.termux.com/wiki/Termux-usb , replacing the C code with: #!/usr/bin/env python3
import sys
import usb1
usb_fd = int(sys.argv[1], 10)
with usb1.USBContext(
with_device_discovery=False, # Note: I'll probably rename this parameter
log_level=usb1.LOG_LEVEL_DEBUG,
) as ctx:
handle = ctx.wrapSysDevice(usb_fd)
dev = handle.getDevice()
import pdb; pdb.set_trace() and ran with:
I could not get a device behing an OTG-to-A hub to appear, but I could plug one of the few OTG devices I have (a SeekThermal camera) and could open it and trigger a bit of IO (retrieving the manufacturer string descriptor, list of languages...). So at least the basics are working, and I identified a few things which should be improved. As I have no idea what the camera's protocol is, I will not be able to test much more of the API with it. On the side of Linux devices with gadget support (which would allow much more testing), both of my devices currently do not boot, and I've been procrastinating on figuring out what makes them sad. |
From, what I gather, a variadic is a function that has a dynamic amount of arguments? |
Correct, and while ctypes is able to reliably know what to do for a call with a fixed number of arguments, it cannot (or at least, it does not implement it) when it is variable. IIRC it is then always up to the caller to unwind the stack (while in some ABI this is up to the callee), and some argument types are promoted to larger registers (? not sure). This makes this fall into the arch- and possibly also OS-dependent bucket, where many "works for me" bugs strive. |
out of curiosity can you not dynamically allocate the argtypes? Since the first option will always be ctx if I remember correctly # assume imported libusb-1.0.dll as libusb
import ctypes
libusb_set_option = libusb.libusb_set_option
libusb_set_option.argtypes = [libusb_context_p,c_int,c_int] #if I understand correctly, ctx will always be there and the only variable part is onwards with log level and so on
def variadic_func(*args):
if len(args) == 2: # only 2 args so ctx and log level
libusb_set_option.argtypes = [libusb_context_p,c_int]
if len(args) == 3:
libusb_set_option.argtypes = [libusb_context_p,c_int,c_int]
# or if the rest are all type ints (for x no. of args)
argtypes = [libusb_context_p]
ctx = args[0]
args = args[1:]
for i in args:
argtypes.append(c_int)
libusb_set_option.argtypes = [ctx,*argtypes]
args = [ctx,*args]
libusb_set_option(*args)
I'm not sure if I understood correctly and I'll quickly run it to see if I haven't forgotten to add anything |
As of cpython 3.10 to 3.12, ctypes documentation mentions variadic. Checking the source, it seems the intended way is:
|
It seems to me libusb_set_option() is missing here.
https://libusb.sourceforge.io/api-1.0/group__libusb__lib.html#gaf6ce5db28dac96b1680877a123da4fa8
https://libusb.sourceforge.io/api-1.0/group__libusb__lib.html#ga07d4ec54cf575d672ba94c72b3c0de7c
For the enum libusb_option, probably LIBUSB_OPTION_USE_USBDK is a bit special.
Use the UsbDk backend for a specific context, if available.
This option should be set immediately after calling libusb_init(), otherwise unspecified behavior may occur.
Only valid on Windows.
The text was updated successfully, but these errors were encountered: