@@ -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+
3849class 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 \x03 T\x00 e\x00 s\x00 t\x00 \x00 C\x00 o\x00 m\x00 p\x00 a\x00 n\x00 y\x00 ' ), results )
564604 self .assertIn ((3 , 2 , b'\x1a \x03 T\x00 e\x00 s\x00 t\x00 \x00 P\x00 r\x00 o\x00 d\x00 u\x00 c\x00 t\x00 ' ), results )
565605
606+ # IAD function string
607+ self .assertIn ((3 , 3 , b'\x12 \x03 T\x00 e\x00 s\x00 t\x00 \x00 I\x00 A\x00 D\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 ):
0 commit comments