| @@ -0,0 +1,87 @@ | |||
| import unittest | |||
| from contextlib import contextmanager | |||
| from .. import emitter_for_format | |||
| from ..descriptor import ComplexDescriptorEmitter | |||
| from ...types.descriptors.hid import \ | |||
| HIDDescriptor as HIDDescriptorType | |||
| from ...types.descriptors.hid import * | |||
| ReportDescriptorEmitter = emitter_for_format(ReportDescriptor) | |||
| _hid_item_length = [ 0, 1, 2, 4 ] | |||
| class HIDDescriptor(ComplexDescriptorEmitter): | |||
| DESCRIPTOR_FORMAT = HIDDescriptorType | |||
| def add_report(self, report_enum, *report_data): | |||
| hid_report = ReportDescriptorEmitter() | |||
| report_len = _hid_item_length.index(len(report_data)) | |||
| hid_report.bHeader = { | |||
| "prefix": report_enum, | |||
| "bSize": report_len | |||
| } | |||
| hid_report.data = report_data | |||
| self._reports.append(hid_report) | |||
| def add_input(self, | |||
| data_constant = False, | |||
| array_variable = True, | |||
| absolute_relative = False, | |||
| wrap = False, | |||
| linear = False, | |||
| preferred = True, | |||
| null = False, | |||
| volatile = False): | |||
| item_flags = ItemFlags.build({ | |||
| "data_constant": data_constant, | |||
| "array_variable": array_variable, | |||
| "absolute_relative": absolute_relative, | |||
| "wrap": wrap, | |||
| "linear": linear, | |||
| "nPreferred": ~preferred, | |||
| "null": null, | |||
| "volatile": volatile, | |||
| }) | |||
| self.add_report(HIDPrefixes.INPUT, ord(item_flags)) | |||
| def add_output(self, | |||
| data_constant = False, | |||
| array_variable = True, | |||
| absolute_relative = False, | |||
| wrap = False, | |||
| linear = False, | |||
| preferred = True, | |||
| null = False, | |||
| volatile = False): | |||
| item_flags = ItemFlags.build({ | |||
| "data_constant": data_constant, | |||
| "array_variable": array_variable, | |||
| "absolute_relative": absolute_relative, | |||
| "wrap": wrap, | |||
| "linear": linear, | |||
| "nPreferred": ~preferred, | |||
| "null": null, | |||
| "volatile": volatile, | |||
| }) | |||
| self.add_report(HIDPrefixes.OUTPUT, ord(item_flags)) | |||
| def __init__(self, parent_descriptor): | |||
| super().__init__() | |||
| # The HID Report Descriptor sits under a different USB Descriptor, | |||
| # we need access to the descriptor root to create this. | |||
| self._parent_descriptor = parent_descriptor | |||
| self._reports = [] | |||
| def _pre_emit(self): | |||
| report_descriptor = [] | |||
| for report in self._reports: | |||
| if hasattr(report, "emit"): | |||
| report_descriptor.append(report.emit()) | |||
| else: | |||
| report_descriptor.append(report) | |||
| report_descriptor = b"".join(report_descriptor) | |||
| descriptor_len = len(report_descriptor) | |||
| self.wDescriptorLength = descriptor_len | |||
| self._parent_descriptor.add_descriptor(report_descriptor, 0x22) | |||
| @@ -177,12 +177,14 @@ class DeviceDescriptorCollection: | |||
| return index | |||
| def add_descriptor(self, descriptor, index=0): | |||
| def add_descriptor(self, descriptor, descriptor_type=None, index=0): | |||
| """ Adds a descriptor to our collection. | |||
| Parameters: | |||
| descriptor -- The descriptor to be added. | |||
| index -- The index of the relevant descriptor. Defaults to 0. | |||
| descriptor -- The descriptor to be added. | |||
| descriptor_type -- The type of the descriptor to be added. If `None`, | |||
| this is automatically derived from the descriptor contents. | |||
| index -- The index of the relevant descriptor. Defaults to 0. | |||
| """ | |||
| # If this is an emitter rather than a descriptor itself, convert it. | |||
| @@ -190,7 +192,8 @@ class DeviceDescriptorCollection: | |||
| descriptor = descriptor.emit() | |||
| # Figure out the identifier (type + index) for this descriptor... | |||
| descriptor_type = descriptor[1] | |||
| if(descriptor_type == None): | |||
| descriptor_type = descriptor[1] | |||
| identifier = descriptor_type, index | |||
| # ... and store it. | |||
| @@ -0,0 +1,85 @@ | |||
| # | |||
| # This file is part of usb-protocol. | |||
| # | |||
| """ Structures describing Communications Device Class descriptors. """ | |||
| import unittest | |||
| from enum import IntEnum, unique | |||
| import construct | |||
| from construct import this, Default | |||
| from .. import LanguageIDs | |||
| from ..descriptor import \ | |||
| DescriptorField, DescriptorNumber, DescriptorFormat, \ | |||
| BCDFieldAdapter, DescriptorLength | |||
| @unique | |||
| class HIDPrefixes(IntEnum): | |||
| # Main items | |||
| INPUT = 0b1000_00 | |||
| OUTPUT = 0b1001_00 | |||
| FEATURE = 0b1011_00 | |||
| COLLECTION = 0b1010_00 | |||
| END_COLLECTION = 0b1100_00 | |||
| # Global items | |||
| USAGE_PAGE = 0b0000_01 | |||
| LOGICAL_MIN = 0b0001_01 | |||
| LOGICAL_MAX = 0b0010_01 | |||
| PHYSICAL_MIN = 0b0011_01 | |||
| PHYSICAL_MAX = 0b0100_01 | |||
| UNIT_EXPONENT = 0b0101_01 | |||
| UNIT = 0b0110_01 | |||
| REPORT_SIZE = 0b0111_01 | |||
| REPORT_ID = 0b1000_01 | |||
| REPORT_COUNT = 0b1001_01 | |||
| PUSH = 0b1010_01 | |||
| POP = 0b1011_01 | |||
| # Local Items | |||
| USAGE = 0b0000_10 | |||
| USAGE_MIN = 0b0001_10 | |||
| USAGE_MAX = 0b0010_10 | |||
| DESIGNATOR_IDX = 0b0011_10 | |||
| DESIGNATOR_MIN = 0b0100_10 | |||
| DESIGNATOR_MAX = 0b0101_10 | |||
| STRING_IDX = 0b0111_10 | |||
| STRING_MIN = 0b1000_10 | |||
| STRING_MAX = 0b1001_10 | |||
| DELIMITER = 0b1010_10 | |||
| HIDDescriptor = DescriptorFormat( | |||
| "bLength" / construct.Const(0x09, construct.Int8ul), | |||
| "bDescriptorType" / DescriptorNumber(33), | |||
| "bcdHID" / DescriptorField("HID Protocol Version", default=1.11), | |||
| "bCountryCode" / DescriptorField("HID Device Language", default=0), | |||
| "bNumDescriptors" / DescriptorField("Number of HID Descriptors", default=1), | |||
| "bDescriptorType" / DescriptorField("HID Descriptor Type", default=34), | |||
| "wDescriptorLength" / DescriptorField("HID Descriptor Length") | |||
| # bDescriptorType and wDescriptorLength repeat bNumDescriptors times | |||
| ) | |||
| _hid_item_length = [ 0, 1, 2, 4 ] | |||
| ReportDescriptor = DescriptorFormat( | |||
| "bHeader" / construct.BitStruct( | |||
| # prefix technically consists of a 4 byte tag and a 2 byte type, | |||
| # however, they're all listed together in the HID spec | |||
| "prefix" / construct.Enum(construct.BitsInteger(6), HIDPrefixes), | |||
| "bSize" / construct.BitsInteger(2), | |||
| ), | |||
| "data" / construct.Byte[lambda ctx: _hid_item_length[ctx.bHeader.bSize]] | |||
| ) | |||
| # Flags for INPUT/OUTPUT/FEATURE items. Named under one of the following conventions: | |||
| # valA_valB: valA when 0, valB when 1 | |||
| # flag: Flag disabled when 0, flag enabled when 1 | |||
| # nFlag: Flag enabled when 0, flag disabled when 1 | |||
| ItemFlags = construct.BitStruct( | |||
| "volatile" / construct.Flag, | |||
| "null" / construct.Flag, | |||
| "nPreferred" / construct.Flag, | |||
| "linear" / construct.Flag, | |||
| "wrap" / construct.Flag, | |||
| "absolute_relative" / construct.Flag, | |||
| "array_variable" / construct.Flag, | |||
| "data_constant" / construct.Flag, | |||
| ) | |||