Search code examples
cpython-3.xctypeshidapi

How do i get data from recursive structure got from C function?


I'm writing a wrapper for usb hid device and want to use hidapi for that. In process of writing/learning got a pointer on recursive structure. How can i get data from this?

I tried to get data from contents, but there was only _field_ inside.

C-struct and C-function from hidapi:

struct hid_device_info {
            /** Platform-specific device path */
            char *path;
            /** Device Vendor ID */
            unsigned short vendor_id;
            /** Device Product ID */
            unsigned short product_id;
            /** Serial Number */
            wchar_t *serial_number;
            /** Device Release Number in binary-coded decimal,
                also known as Device Version Number */
            unsigned short release_number;
            /** Manufacturer String */
            wchar_t *manufacturer_string;
            /** Product string */
            wchar_t *product_string;
            /** Usage Page for this Device/Interface
                (Windows/Mac only). */
            unsigned short usage_page;
            /** Usage for this Device/Interface
                (Windows/Mac only).*/
            unsigned short usage;
            /** The USB interface which this logical device
                represents. Valid on both Linux implementations
                in all cases, and valid on the Windows implementation
                only if the device contains more than one interface. */
            int interface_number;

            /** Pointer to the next device */
            struct hid_device_info *next;
        };

struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id);

Python code:

import ctypes


class HidDeviceInfo(ctypes.Structure):
    pass

HidDeviceInfo._field_ = [
    ('path', ctypes.c_char_p),
    ('vendor_id', ctypes.c_ushort),
    ('product_id', ctypes.c_ushort),
    ('serial_number', ctypes.c_wchar_p),
    ('release_number', ctypes.c_ushort),
    ('manufacturer_string', ctypes.c_wchar_p),
    ('product_string', ctypes.c_wchar_p),
    ('usage_page', ctypes.c_ushort),
    ('usage', ctypes.c_ushort),
    ('interface_number', ctypes.c_int),
    ('next', ctypes.POINTER(HidDeviceInfo))
]


hid_api_dll = ctypes.CDLL("hidapi.dll")

def get_devs(vid, pid):
    hid_enumerate = hid_api_dll.hid_enumerate

    hid_api_dll.hid_enumerate.argtypes = [
        ctypes.c_ushort,
        ctypes.c_ushort
    ]
    hid_api_dll.hid_enumerate.restype = ctypes.POINTER(HidDeviceInfo)

    vid_t = ctypes.c_ushort(vid)
    pid_t = ctypes.c_ushort(pid)

    res = ctypes.POINTER(HidDeviceInfo)()

    res = hid_enumerate(vid_t, pid_t)
    return res


devs = get_devs(0x0, 0x0)
print(devs.contents)
frameInfo = devs.contents
print(frameInfo.path)

I try to just get path attribute from this and got AttributeError: 'HidDeviceInfo' object has no attribute 'path'.

There must be recursive list of all hid devices. How can i retrieve data? Or maybe i done something wrong?


Solution

  • According to [Python.Docs]: ctypes - Structures and unions (emphasis is mine):

    Structures and unions must derive from the Structure and Union base classes which are defined in the ctypes module. Each subclass must define a _fields_ attribute. _fields_ must be a list of 2-tuples, containing a field name and a field type.

    Replace HidDeviceInfo._field_ to HidDeviceInfo._fields_ (plural, surrounded by one UnderScore ("_")), and things should be fine.