Skip to content

I2C FIFO Target

The PxI2CFifoTarget class emulates an I2C target with host-accessible RX and TX FIFOs. A controller writes data on the bus into the RX FIFO (delivered to Python as events); Python enqueues data into the TX FIFO for the controller to read on the bus.

FIFO depth is fixed at 4 KB and is not configurable from Python. A single enqueue call may transfer up to the available TX FIFO capacity. Each receive event delivers up to 4 KB of data; each sent event reports the byte count drained in a bus read.

Data flow

Controller WRITE  →  RX FIFO  →  fifo_target_recv events  →  Python
Python enqueue    →  TX FIFO  →  Controller READ
Controller READ   →  (drains TX FIFO)  →  fifo_target_sent events  →  Python

Quick start

Attach a target to an I2C bus and enqueue TX data:

from aqpxlib import AqProtocolExerciser
from aqpxlib.i2c import PxI2CBus, PxI2CFifoTarget

with AqProtocolExerciser.connect(port=60600) as px:
    i2c_bus = PxI2CBus(px, scl=0, sda=1)
    target = PxI2CFifoTarget(px, address=0x50)
    target.attach_to_bus(i2c_bus)

    target.enqueue([0x01, 0x02, 0x03])

    state = target.state
    print(f"TX fill: {state.tx_fill}")
    print(f"Total read: {state.total_read}")
    print(f"Total written: {state.total_written}")

    target.detach_from_bus()

Enqueue (host → bus)

Use enqueue to load the TX FIFO. This does not perform an I2C transaction itself. Use a PxI2CController on the same bus to read the enqueued bytes.

target.enqueue(b"\xde\xad\xbe\xef")

Bus receive events

When a controller writes to the target, the exerciser emits fifo_target_recv events. Each event carries a data field with the bytes received in that event packet, and a last flag that marks the final event for the current bus write transaction (STOP or repeated-START).

Field Type Description
data bytes Bytes received in this event
last bool True when this is the last event for the current bus write
from aqpxlib.event import PxEventMsg

@target.on_event("fifo_target_recv")
def on_recv(event: PxEventMsg):
    recv_event = event.device_event.fifo_target_recv
    print(f"Recv {recv_event.data.hex()} last={recv_event.last}")

Bus sent events

When a controller reads from the target, the exerciser emits fifo_target_sent events. Each event reports how many bytes were drained from the TX FIFO in the completed bus read, with last marking the end of that read transaction.

Field Type Description
count int Bytes sent on the bus in this read transaction
last bool True when this is the last event for the current bus read
@target.on_event("fifo_target_sent")
def on_sent(event: PxEventMsg):
    sent_event = event.device_event.fifo_target_sent
    print(f"Sent {sent_event.count} bytes last={sent_event.last}")

enqueue and state queries do not emit recv or sent events.

See also: Event Registration and Handler Setup.

State

Query the current FIFO state via target.state:

Property Description
tx_fill Bytes currently queued in the TX FIFO
total_read Cumulative bytes read by the controller since configure
total_written Cumulative bytes written by the controller since configure
state = target.state
assert state.tx_fill >= 0
assert state.total_read >= 0
assert state.total_written >= 0

Controller access

Use a PxI2CController to exercise the target over the bus:

from aqpxlib import AqProtocolExerciser
from aqpxlib.event import PxEventMsg
from aqpxlib.i2c import PxI2CBus, PxI2CController, PxI2CFifoTarget

with AqProtocolExerciser.connect(port=60600) as px:
    i2c_bus = PxI2CBus(px, scl=0, sda=1)
    target = PxI2CFifoTarget(px, address=0x50)
    target.attach_to_bus(i2c_bus)

    controller = PxI2CController(px)
    controller.attach_to_bus(i2c_bus)

    received: list[int] = []

    @target.on_event("fifo_target_recv")
    def on_recv(event: PxEventMsg) -> None:
        recv_event = event.device_event.fifo_target_recv
        received.extend(recv_event.data)

    target.enqueue([0xAA, 0xBB, 0xCC])
    read_back = controller.i2c_read(target.address, 3)
    assert read_back == [0xAA, 0xBB, 0xCC]

    controller.i2c_write(target.address, [0x11, 0x22])
    assert received == [0x11, 0x22]

    controller.detach_from_bus()
    target.detach_from_bus()

I3C bus support

PxI2CFifoTarget may be attached to an I3C bus (valid_buses includes "i3c" and "i2c"). The device behaves as an I2C-style target on the I3C SDA line.

API reference

PxI2CFifoTarget

PxI2CFifoTarget(
    exerciser: AqProtocolExerciser,
    address: int = 0,
    config: I2CFifoTargetConfig | None = None,
    *args,
    **kwargs
)

Bases: PxAbstractTarget

I2C FIFO target.

Emulates an I2C target with host-accessible RX and TX FIFOs. Bytes written by a controller on the bus are delivered to Python as packeted fifo_target_recv events. Bytes enqueued from Python are presented on subsequent bus reads; completed bus reads are reported as fifo_target_sent events with the byte count drained in each transaction.

Use enqueue to load the TX FIFO. Use self.state for the current device state snapshot (tx_fill, total_read, total_written).

METHOD DESCRIPTION
add_event_handler

Add an event handler to the current device instance.

remove_event_handler

Remove an event handler.

get_event_handlers

Retreive handlers registerd on this device.

on_event

Add an event handler to the instance by decorator.

set_config

Set the config of the target.

detach_from_bus

Detach the device from the bus.

perform_operation

Send an operation.

attach_to_bus

Attach the target to a bus.

enqueue

Enqueue bytes into the host-side TX FIFO.

ATTRIBUTE DESCRIPTION
available_events_map

A reverse mapping of field_name_by_number, which uses field name as key.

TYPE: dict[str, str]

is_attached

Check if the device is attached to a bus.

TYPE: bool

state

Get the state of the device.

TYPE: Message | None

name

Get the name of the device.

TYPE: str

additional_data

Get the opaque additional data blob associated with this device.

TYPE: bytes

config

Get the config of the device.

TYPE: Message | None

cts_op_name

Get the name of CTS operation. Currently not available now.

TYPE: str | None

address

Static 7-bit I2C address of the target.

TYPE: int

tx_fill

Number of bytes currently in the TX FIFO.

TYPE: int

total_read

Total bytes read by the controller from the target since configuration.

TYPE: int

total_written

Total bytes written by the controller to the target since configuration.

TYPE: int

available_events_map

available_events_map: dict[str, str]

A reverse mapping of field_name_by_number, which uses field name as key.

is_attached

is_attached: bool

Check if the device is attached to a bus.

state

state: Message | None

Get the state of the device.

name

name: str

Get the name of the device.

additional_data

additional_data: bytes

Get the opaque additional data blob associated with this device.

config

config: Message | None

Get the config of the device.

cts_op_name

cts_op_name: str | None

Get the name of CTS operation. Currently not available now.

address

address: int

Static 7-bit I2C address of the target.

tx_fill

tx_fill: int

Number of bytes currently in the TX FIFO.

total_read

total_read: int

Total bytes read by the controller from the target since configuration.

total_written

total_written: int

Total bytes written by the controller to the target since configuration.

add_event_handler

add_event_handler(event: str, handler: Callable[[Any], Any]) -> None

Add an event handler to the current device instance.

remove_event_handler

remove_event_handler(event: str) -> None

Remove an event handler.

get_event_handlers

get_event_handlers() -> dict[str, Callable]

Retreive handlers registerd on this device.

on_event

on_event(event_type: str) -> Callable[[Callable[..., Any]], Callable[..., Any]]

Add an event handler to the instance by decorator.

set_config

set_config(config: Message) -> None

Set the config of the target.

detach_from_bus

detach_from_bus() -> None

Detach the device from the bus.

The opposite of the attach_to_bus method.

perform_operation

perform_operation(operation: PxDeviceOperation) -> PxDeviceOperation

Send an operation.

attach_to_bus

attach_to_bus(bus: PxAbstractBus) -> None

Attach the target to a bus.

This method is used to make the device aware of the bus it is connected to. It is used to set the bus attribute of the device.

Note

This method will not automatically create an actual instance on the Protocol Exerciser until user call the attach_to_bus method.

PARAMETER DESCRIPTION

bus

The bus to attach the device to

TYPE: PxAbstractBus

RAISES DESCRIPTION
ValueError

If the device is already attached to a bus

enqueue

enqueue(data: list[int] | bytes) -> None

Enqueue bytes into the host-side TX FIFO.

This does not perform an I2C bus transaction. Enqueued bytes are returned to a controller on subsequent bus read transfers.

PARAMETER DESCRIPTION

data

Bytes to enqueue (0-255 per byte). May exceed 4 KB in a single call; size is limited only by available TX FIFO space.

TYPE: list[int] | bytes