| @@ -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 | 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. | """ Adds a descriptor to our collection. | ||||
| Parameters: | 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. | # If this is an emitter rather than a descriptor itself, convert it. | ||||
| @@ -190,7 +192,8 @@ class DeviceDescriptorCollection: | |||||
| descriptor = descriptor.emit() | descriptor = descriptor.emit() | ||||
| # Figure out the identifier (type + index) for this descriptor... | # 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 | identifier = descriptor_type, index | ||||
| # ... and store it. | # ... 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, | |||||
| ) | |||||