greatscottgadgets / python-usb-protocol

python library providing utilities, data structures, constants, parsers, and tools for working with USB data
BSD 3-Clause "New" or "Revised" License
56 stars 32 forks source link

Setting an interface descriptor string throws an error #15

Closed miek closed 3 years ago

miek commented 3 years ago

(This was originally reported by @mubes on Discord in #luna)

When I add a description string to an interface descriptor like this:

@@ -184,6 +184,7 @@ class Device(Elaboratable):

             with c.InterfaceDescriptor() as i:
                 i.bInterfaceNumber = 0
+                i.iInterface = "xyz"

                 with i.EndpointDescriptor() as e:
                     e.bEndpointAddress = 0x80 | BULK_ENDPOINT_NUMBER

I get this error:

Traceback (most recent call last):
  File "/home/mike/.local/lib/python3.8/site-packages/construct/core.py", line 1027, in _build
    data = self.packer.pack(obj)
struct.error: required argument is not an integer

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/lib/python3.8/runpy.py", line 194, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "/usr/lib/python3.8/runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "/home/mike/projects/amalthea/amalthea/gateware/device.py", line 308, in <module>
    device = top_level_cli(Device)
  File "/home/mike/.local/lib/python3.8/site-packages/luna/__init__.py", line 145, in top_level_cli
    products = platform.build(fragment,
  File "/home/mike/projects/nmigen/nmigen/build/plat.py", line 95, in build
    plan = self.prepare(elaboratable, name, **kwargs)
  File "/home/mike/projects/nmigen/nmigen/build/plat.py", line 135, in prepare
    fragment = Fragment.get(elaboratable, self)
  File "/home/mike/projects/nmigen/nmigen/hdl/ir.py", line 39, in get
    obj = obj.elaborate(platform)
  File "/home/mike/projects/amalthea/amalthea/gateware/device.py", line 208, in elaborate
    descriptors = self.create_descriptors()
  File "/home/mike/projects/amalthea/amalthea/gateware/device.py", line 191, in create_descriptors
    e.wMaxPacketSize   = MAX_BULK_PACKET_SIZE
  File "/usr/lib/python3.8/contextlib.py", line 120, in __exit__
    next(self.gen)
  File "/home/mike/projects/python-usb-protocol/usb_protocol/emitters/descriptors/standard.py", line 127, in InterfaceDescriptor
    self.add_subordinate_descriptor(descriptor)
  File "/home/mike/projects/python-usb-protocol/usb_protocol/emitters/descriptor.py", line 46, in add_subordinate_descriptor
    subordinate = subordinate.emit()
  File "/home/mike/projects/python-usb-protocol/usb_protocol/emitters/descriptor.py", line 77, in emit
    result.extend(super().emit())
  File "/home/mike/projects/python-usb-protocol/usb_protocol/emitters/construct.py", line 63, in emit
    return self.format.build(self.fields)
  File "/home/mike/.local/lib/python3.8/site-packages/construct/core.py", line 336, in build
    self.build_stream(obj, stream, **contextkw)
  File "/home/mike/.local/lib/python3.8/site-packages/construct/core.py", line 348, in build_stream
    self._build(obj, stream, context, "(building)")
  File "/home/mike/.local/lib/python3.8/site-packages/construct/core.py", line 2005, in _build
    buildret = sc._build(subobj, stream, context, path)
  File "/home/mike/.local/lib/python3.8/site-packages/construct/core.py", line 2443, in _build
    return self.subcon._build(obj, stream, context, path)
  File "/home/mike/.local/lib/python3.8/site-packages/construct/core.py", line 2443, in _build
    return self.subcon._build(obj, stream, context, path)
  File "/home/mike/.local/lib/python3.8/site-packages/construct/core.py", line 2711, in _build
    return self.subcon._build(obj, stream, context, path)
  File "/home/mike/.local/lib/python3.8/site-packages/construct/core.py", line 1029, in _build
    raise FormatFieldError("struct %r error during building, given value %r" % (self.fmtstr, obj), path=path)
construct.core.FormatFieldError: Error in path (building) -> iInterface -> iInterface
struct '<B' error during building, given value 'xyz'

The problem is that i._collection is None, so the string -> index mapping code never runs: https://github.com/usb-tools/python-usb-protocol/blob/56831fba4a44dfd5a2ff9ab52d7ddc951d9dc797/usb_protocol/emitters/descriptors/standard.py#L99-L101

and I think that the root cause is that the collection is never passed to the upstream ConfigurationDescriptorEmitter: https://github.com/usb-tools/python-usb-protocol/blob/56831fba4a44dfd5a2ff9ab52d7ddc951d9dc797/usb_protocol/emitters/descriptors/standard.py#L287