BodgeUSB.Descriptor (BodgeUSB v0.1.0)

Copy Markdown View Source

USB descriptor parsing.

Parses the raw descriptor bytes that usbfs returns (device descriptor followed by the configuration descriptor sets) into Elixir structs, plus string descriptor decoding.

Parsing is total and defensive: for any input binary, parse/1 returns either {:ok, %Device{}} or {:error, reason} with a typed reason, and never raises. That is what lets the library survive malformed descriptors from a hostile or buggy device (truncated, oversized, zero-length, wrong bLength, ...).

Summary

Functions

Decode a string descriptor's bytes (<<bLength, 0x03, utf16le...>>) to a UTF-8 string. Index 0 is not a string (its payload is the LANGID array).

Parse a full descriptor blob (device descriptor + configuration sets), as returned by reading a usbfs node. Returns {:ok, %Device{}} or {:error, reason}.

Parse a single configuration descriptor set (config + interfaces + endpoints).

Parse just the 18-byte device descriptor (ignores any trailing bytes).

Types

reason()

@type reason() ::
  :short_device_descriptor
  | :not_a_device_descriptor
  | {:invalid_device_length, non_neg_integer()}
  | :zero_length_descriptor
  | {:invalid_descriptor_length, non_neg_integer()}
  | :truncated

Functions

decode_string(arg1)

@spec decode_string(binary()) :: {:ok, String.t()} | {:error, :invalid_string}

Decode a string descriptor's bytes (<<bLength, 0x03, utf16le...>>) to a UTF-8 string. Index 0 is not a string (its payload is the LANGID array).

parse(binary)

@spec parse(binary()) :: {:ok, BodgeUSB.Descriptor.Device.t()} | {:error, reason()}

Parse a full descriptor blob (device descriptor + configuration sets), as returned by reading a usbfs node. Returns {:ok, %Device{}} or {:error, reason}.

parse_configuration(binary)

@spec parse_configuration(binary()) ::
  {:ok, BodgeUSB.Descriptor.Configuration.t()} | {:error, reason()}

Parse a single configuration descriptor set (config + interfaces + endpoints).

parse_device(binary)

@spec parse_device(binary()) ::
  {:ok, BodgeUSB.Descriptor.Device.t()} | {:error, reason()}

Parse just the 18-byte device descriptor (ignores any trailing bytes).

Note: reading a usbfs node returns the device descriptor with its multibyte fields (bcdUSB, idVendor, idProduct, bcdDevice) already byte-swapped to host order by the kernel; we read them little-endian, which is correct on little-endian hosts (the common case). Configuration descriptors are raw little-endian and parse correctly everywhere.