Skip to main content

Python bindings for USB Power Delivery protocol message parsing

Project description

usbpdpy

Python bindings for USB Power Delivery message parsing using the usbpd Rust crate.

Features

  • Parse USB PD messages with full specification compliance
  • Support for Source Capabilities and Request message parsing
  • All PDO types: Fixed Supply, Battery, Variable Supply, PPS, EPR
  • Complete RDO (Request Data Object) parsing with PDO state management
  • Message header parsing with proper control/data message classification
  • Python type hints and error handling

Installation

pip install usbpdpy

Quick Start

Parse Source Capabilities

import usbpdpy

# Parse a Source Capabilities message
source_caps_hex = "a1612c9101082cd102002cc103002cb10400454106003c21dcc0"
source_caps_bytes = bytes.fromhex(source_caps_hex)
message = usbpdpy.parse_pd_message(source_caps_bytes)

print(f"Message: {message.header.message_type}")
print(f"Power role: {message.header.port_power_role}")
print(f"Available PDOs: {len(message.data_objects)}")

for i, pdo in enumerate(message.data_objects):
    print(f"  PDO {i+1}: {pdo}")
    # Output: PDO 1: PowerDataObj(FixedSupply: 5V @ 3A = 15W)
    #         PDO 2: PowerDataObj(FixedSupply: 9V @ 3A = 27W)
    #         ...

Parse Request Messages

# First, parse Source Capabilities to get PDO state
source_msg = usbpdpy.parse_pd_message(source_caps_bytes)

# Parse Request message with PDO context
request_hex = "8210dc700323"
request_bytes = bytes.fromhex(request_hex)
request_msg = usbpdpy.parse_pd_message_with_state(request_bytes, source_msg.data_objects)

print(f"Request type: {request_msg.header.message_type}")
for rdo in request_msg.request_objects:
    print(f"  Requesting PDO #{rdo.object_position}: {rdo.rdo_type}")
    # Output: Requesting PDO #2: FixedVariableSupply

API Reference

Core Functions

  • parse_pd_message(data: bytes) -> PdMessage - Parse a USB PD message
  • parse_pd_message_with_state(data: bytes, pdo_state: List[PowerDataObj]) -> PdMessage - Parse with PDO context for Request messages
  • parse_messages(messages: List[bytes]) -> List[PdMessage] - Parse multiple messages
  • get_message_type_name(msg_type: int, num_objects: int) -> str - Get human-readable message type
  • hex_to_bytes(hex_str: str) -> List[int] - Convert hex string to byte list
  • bytes_to_hex(data: bytes) -> str - Convert bytes to hex string

Message Structure

PdMessage

  • header: PdHeader - Message header information
  • data_objects: List[PowerDataObj] - Power Data Objects (PDOs) for Source/Sink Capabilities
  • request_objects: List[RequestDataObj] - Request Data Objects (RDOs) for Request messages
  • raw_bytes: bytes - Original message bytes
  • is_control_message() -> bool - Check if control message
  • is_data_message() -> bool - Check if data message
  • is_source_capabilities() -> bool - Check if Source Capabilities
  • hex() -> str - Get message as hex string

PdHeader

  • message_type: str - Human-readable type (e.g., "Source_Capabilities", "GoodCRC")
  • message_type_raw: int - Raw type code (0–31)
  • port_data_role: str - "Ufp" or "Dfp"
  • port_power_role: str - "Sink" or "Source"
  • message_id: int - Message ID (0–7)
  • num_data_objects: int - Number of 32-bit data objects (0–7)
  • spec_revision: int - PD spec rev (0=R1.0, 1=R2.0, 2=R3.0)
  • extended: bool - Extended message flag

PowerDataObj

  • pdo_type: str - "FixedSupply", "Battery", "VariableSupply", "PPS", "EPR_AVS", "Unknown"
  • raw: int - Raw 32-bit PDO value
  • voltage_v: Optional[float] - Voltage in volts (fixed supply)
  • max_current_a: Optional[float] - Maximum current in amperes
  • max_power_w: Optional[float] - Maximum power in watts (calculated or battery)
  • min_voltage_v: Optional[float] - Minimum voltage in volts (variable/PPS)
  • max_voltage_v: Optional[float] - Maximum voltage in volts (variable/PPS)
  • dual_role_power: Optional[bool] - Dual role power capability
  • usb_communications_capable: Optional[bool] - USB communications capability
  • unconstrained_power: Optional[bool] - Unconstrained power flag

RequestDataObj

  • rdo_type: str - "FixedVariableSupply", "Battery", "PPS", "AVS", "Unknown"
  • raw: int - Raw 32-bit RDO value
  • object_position: int - PDO position being requested (1-7)
  • operating_current_a: Optional[float] - Operating current in amperes
  • max_operating_current_a: Optional[float] - Maximum operating current in amperes
  • operating_voltage_v: Optional[float] - Operating voltage in volts (PPS/AVS)
  • operating_power_w: Optional[float] - Operating power in watts (battery)
  • max_operating_power_w: Optional[float] - Maximum operating power in watts (battery)
  • capability_mismatch: bool - Capability mismatch flag
  • usb_communications_capable: bool - USB communications capability
  • no_usb_suspend: bool - No USB suspend flag
  • giveback_flag: Optional[bool] - GiveBack flag (fixed/variable supply)

Message Types

The library correctly distinguishes between control and data messages:

  • Control Messages (num_data_objects = 0): GoodCRC, Accept, Reject, PS_RDY, etc.
  • Data Messages (num_data_objects > 0): Source_Capabilities, Request, Sink_Capabilities, etc.

Supported Data Messages

  • Source_Capabilities: Parsed into data_objects (PDOs)
  • Request: Parsed into request_objects (RDOs) when PDO state is provided
  • Sink_Capabilities: Header parsed, data objects pending
  • Other data messages: Header parsed, data objects pending

Real-World Usage

This library has been tested with real USB PD captures from KM003C hardware, including complete negotiation sequences:

# Parse a complete USB PD negotiation sequence
messages = [
    "a1612c9101082cd102002cc103002cb10400454106003c21dcc0",  # Source_Capabilities
    "8210dc700323",  # Request (9V)
    "a305",          # Accept
    "a607",          # PS_RDY
]

source_msg = usbpdpy.parse_pd_message(bytes.fromhex(messages[0]))
request_msg = usbpdpy.parse_pd_message_with_state(
    bytes.fromhex(messages[1]), 
    source_msg.data_objects
)

print(f"Sink requested PDO #{request_msg.request_objects[0].object_position}")
# Output: Sink requested PDO #2 (9V from the source capabilities)

Development

# Install development dependencies
uv sync --dev

# Build the extension
uv run maturin develop

# Run tests
uv run pytest

# Lint and format
uv run ruff check .
uv run ruff format .

Requirements

  • Python 3.8+
  • No runtime dependencies

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

usbpdpy-0.2.0.tar.gz (31.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

usbpdpy-0.2.0-cp312-cp312-manylinux_2_34_x86_64.whl (271.4 kB view details)

Uploaded CPython 3.12manylinux: glibc 2.34+ x86-64

File details

Details for the file usbpdpy-0.2.0.tar.gz.

File metadata

  • Download URL: usbpdpy-0.2.0.tar.gz
  • Upload date:
  • Size: 31.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: maturin/1.9.4

File hashes

Hashes for usbpdpy-0.2.0.tar.gz
Algorithm Hash digest
SHA256 3a14a6c5771868dc30b380626c785816c155f3dbaa738fe65b8e87fb885628fe
MD5 a59189487ef74ce4c2d43a9cf56c16db
BLAKE2b-256 86baaf54cfc0b3d4ea5b2a078cce82d1d4da6b8b91f0495fe318836b97166b44

See more details on using hashes here.

File details

Details for the file usbpdpy-0.2.0-cp312-cp312-manylinux_2_34_x86_64.whl.

File metadata

File hashes

Hashes for usbpdpy-0.2.0-cp312-cp312-manylinux_2_34_x86_64.whl
Algorithm Hash digest
SHA256 a2e1980bad8c9a1137538c52ce074c75e604d7a0fcc91a86674ba506cb51757d
MD5 8155cb3652b368bd7aa33cd5fbfa942e
BLAKE2b-256 e000da31b32d76b16bfef828fb4c7a53283d0c05aead78d0c37fb727512d07e1

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page