Skip to content

Commit d43c1f7

Browse files
authored
Merge pull request #52 from miek/iad-emitter
Add an emitter for interface association descriptors
2 parents 5ee66a2 + db717fe commit d43c1f7

File tree

3 files changed

+55
-11
lines changed

3 files changed

+55
-11
lines changed

usb_protocol/emitters/descriptors/standard.py

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,17 @@ def get_string_descriptor(string):
3535

3636
# ... and complex emitters.
3737

38+
class InterfaceAssociationDescriptorEmitter(ComplexDescriptorEmitter):
39+
""" Emitter that creates an interface association descriptor. """
40+
41+
DESCRIPTOR_FORMAT = InterfaceAssociationDescriptor
42+
43+
def _pre_emit(self):
44+
# Ensure that our function string is an index, if we can.
45+
if self._collection and hasattr(self, 'iFunction'):
46+
self.iFunction = self._collection.ensure_string_field_is_index(self.iFunction)
47+
48+
3849
class EndpointDescriptorEmitter(ComplexDescriptorEmitter):
3950
""" Emitter that creates an InterfaceDescriptor. """
4051

@@ -107,6 +118,26 @@ class ConfigurationDescriptorEmitter(ComplexDescriptorEmitter):
107118

108119
DESCRIPTOR_FORMAT = ConfigurationDescriptor
109120

121+
@contextmanager
122+
def InterfaceAssociationDescriptor(self):
123+
""" Context manager that allows addition of a subordinate interface association descriptor.
124+
125+
It can be used with a `with` statement; and yields an InterfaceAssociationDescriptorEmitter
126+
that can be populated:
127+
128+
with configuration.InterfaceAssociationDescriptor() as d:
129+
d.bFirstInterface = 0
130+
d.bInterfaceCount = 2
131+
[snip]
132+
133+
This adds the relevant descriptor, automatically.
134+
"""
135+
descriptor = InterfaceAssociationDescriptorEmitter(collection=self._collection)
136+
yield descriptor
137+
138+
self.add_subordinate_descriptor(descriptor)
139+
140+
110141
@contextmanager
111142
def InterfaceDescriptor(self):
112143
""" Context manager that allows addition of a subordinate interface descriptor.
@@ -540,6 +571,15 @@ def test_descriptor_collection(self):
540571
with collection.ConfigurationDescriptor() as c:
541572
c.bConfigurationValue = 1
542573

574+
with c.InterfaceAssociationDescriptor() as ia:
575+
ia.bFirstInterface = 1
576+
ia.bInterfaceCount = 1
577+
ia.bFunctionClass = 0xa
578+
ia.bFunctionSubClass = 0xb
579+
ia.bFunctionProtocol = 0xc
580+
ia.iFunction = "Test IAD"
581+
582+
543583
with c.InterfaceDescriptor() as i:
544584
i.bInterfaceNumber = 1
545585

@@ -552,9 +592,9 @@ def test_descriptor_collection(self):
552592

553593
results = list(collection)
554594

555-
# We should wind up with four descriptor entries, as our endpoint/interface descriptors are
595+
# We should wind up with six descriptor entries, as our endpoint/interface descriptors are
556596
# included in our configuration descriptor.
557-
self.assertEqual(len(results), 5)
597+
self.assertEqual(len(results), 6)
558598

559599
# Supported languages string.
560600
self.assertIn((3, 0, b'\x04\x03\x09\x04'), results)
@@ -563,11 +603,14 @@ def test_descriptor_collection(self):
563603
self.assertIn((3, 1, b'\x1a\x03T\x00e\x00s\x00t\x00 \x00C\x00o\x00m\x00p\x00a\x00n\x00y\x00'), results)
564604
self.assertIn((3, 2, b'\x1a\x03T\x00e\x00s\x00t\x00 \x00P\x00r\x00o\x00d\x00u\x00c\x00t\x00'), results)
565605

606+
# IAD function string
607+
self.assertIn((3, 3, b'\x12\x03T\x00e\x00s\x00t\x00 \x00I\x00A\x00D\x00'), results)
608+
566609
# Device descriptor.
567610
self.assertIn((1, 0, b'\x12\x01\x00\x02\x00\x00\x00@\xad\xde\xef\xbe\x00\x00\x01\x02\x00\x01'), results)
568611

569612
# Configuration descriptor, with subordinates.
570-
self.assertIn((2, 0, b'\t\x02 \x00\x01\x01\x00\x80\xfa\t\x04\x01\x00\x02\xff\xff\xff\x00\x07\x05\x81\x02@\x00\xff\x07\x05\x01\x02@\x00\xff'), results)
613+
self.assertIn((2, 0, b'\t\x02\x28\x00\x01\x01\x00\x80\xfa\x08\x0b\x01\x01\x0a\x0b\x0c\x03\t\x04\x01\x00\x02\xff\xff\xff\x00\x07\x05\x81\x02@\x00\xff\x07\x05\x01\x02@\x00\xff'), results)
571614

572615

573616
def test_empty_descriptor_collection(self):

usb_protocol/types/descriptors/partial/standard.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22

33
from .. import standard
44

5-
DeviceDescriptor = standard.DeviceDescriptor.Partial
6-
ConfigurationDescriptor = standard.ConfigurationDescriptor.Partial
7-
StringDescriptor = standard.StringDescriptor.Partial
8-
StringLanguageDescriptor = standard.StringLanguageDescriptor.Partial
9-
InterfaceDescriptor = standard.InterfaceDescriptor.Partial
10-
EndpointDescriptor = standard.EndpointDescriptor.Partial
11-
DeviceQualifierDescriptor = standard.DeviceQualifierDescriptor.Partial
5+
DeviceDescriptor = standard.DeviceDescriptor.Partial
6+
ConfigurationDescriptor = standard.ConfigurationDescriptor.Partial
7+
StringDescriptor = standard.StringDescriptor.Partial
8+
StringLanguageDescriptor = standard.StringLanguageDescriptor.Partial
9+
InterfaceDescriptor = standard.InterfaceDescriptor.Partial
10+
EndpointDescriptor = standard.EndpointDescriptor.Partial
11+
DeviceQualifierDescriptor = standard.DeviceQualifierDescriptor.Partial
12+
InterfaceAssociationDescriptor = standard.InterfaceAssociationDescriptor.Partial

usb_protocol/types/descriptors/standard.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ class DeviceCapabilityTypes(IntEnum):
171171
"bFunctionClass" / DescriptorField("Class code"),
172172
"bFunctionSubClass" / DescriptorField("Subclass code"),
173173
"bFunctionProtocol" / DescriptorField("Protocol code"),
174-
"iFunction" / DescriptorField("Index of string descriptor describing this function."),
174+
"iFunction" / DescriptorField("Index of string descriptor describing this function.", default=0),
175175
)
176176

177177
#

0 commit comments

Comments
 (0)