diff --git a/usb_protocol/emitters/descriptors/hid.py b/usb_protocol/emitters/descriptors/hid.py new file mode 100644 index 0000000..031ec74 --- /dev/null +++ b/usb_protocol/emitters/descriptors/hid.py @@ -0,0 +1,39 @@ +import unittest + +from contextlib import contextmanager + +from .. import emitter_for_format +from ..descriptor import ComplexDescriptorEmitter +from ...types.descriptors.hid import * + +class HIDDescriptorEmitter(ComplexDescriptorEmitter): + + DESCRIPTOR_FORMAT = HIDDescriptor + + @contextmanager + def DescriptorReference(self): + """ Context manager that allows addition of a subordinate report descriptor. + + It can be used with a `with` statement; and yields an HIDDescriptorReferenceEmitter + that can be populated: + + with hiddescriptor.DescriptorReference() as r: + r.wDescriptorLength = 0x10 + + This adds the relevant descriptor, automatically. + """ + + descriptor = HIDDescriptorReferenceEmitter() + yield descriptor + + self.add_subordinate_descriptor(descriptor) + + def _pre_emit(self): + # Figure out the total length of our descriptor, including subordinates. + subordinate_length = sum(len(sub) for sub in self._subordinates) + self.bLength = subordinate_length + self.DESCRIPTOR_FORMAT.sizeof() + self.bNumDescriptors = len(self._subordinates) + pass + + +HIDDescriptorReferenceEmitter = emitter_for_format(HIDDescriptorReference) diff --git a/usb_protocol/types/descriptors/hid.py b/usb_protocol/types/descriptors/hid.py new file mode 100644 index 0000000..1d98933 --- /dev/null +++ b/usb_protocol/types/descriptors/hid.py @@ -0,0 +1,46 @@ +# +# This file is part of usb-protocol. +# +""" Structures describing Human Interface Device Class descriptors. """ + +import unittest +from enum import IntEnum + +from ..descriptor import \ + DescriptorField, DescriptorNumber, DescriptorFormat + +class HidInterfaceClassCodes(IntEnum): + HID = 0x03 + +class HidInterfaceSubclassCodes(IntEnum): + NO_SUBCLASS = 0 + BOOT = 1 + +class HidInterfaceProtocols(IntEnum): + NONE = 0 + KEYBOARD = 1 + MOUSE = 2 + +class HidClassSpecificDescriptorTypes(IntEnum): + CS_UNDEFINED = 0x20 + CS_HID = 0x21 + CS_REPORT = 0x22 + CS_PHYSICAL = 0x23 + + +HIDDescriptor = DescriptorFormat( + "bLength" / DescriptorField("Descriptor Length"), + "bDescriptorType" / DescriptorNumber(HidClassSpecificDescriptorTypes.CS_HID), + "bcdHID" / DescriptorField("HID Protocol Version", default=1.11), + "bCountryCode" / DescriptorField("Hardware target country", default=0), + "bNumDescriptors" / DescriptorField("Number of HID class descriptors to follow", default=0), +) + +# This is not really a stand-alone descriptor, but it it is more a reference to a report +# descriptor that can retrieved seperately. It is part of the HIDDescriptor above. +# That descriptor can contain multiple descriptor references. To support this, a seperate +# descriptor format is used. +HIDDescriptorReference = DescriptorFormat( + "bDescriptorType" / DescriptorField("HID Descriptor Type", default=HidClassSpecificDescriptorTypes.CS_REPORT), + "wDescriptorLength" / DescriptorField("HID Descriptor Length") +)