Enums

Configuration values are typed enums, never bare integers or strings — the signature tells you the whole legal set, so a mistake fails at the call site rather than as a firmware rejection later. Note what it fails as: passing a bare 0 or "330" where a member is expected raises AttributeError (the SDK reads .name or .value off the argument), and a mistyped member name raises AttributeError too. A TypeError here means a mistyped keyword, which is a different mistake.

Three flavours live side by side, and the difference is not cosmetic.

Bound from C++, plain enum.Enum. Most of them — every configuration ladder (SpiMode, UartBaudRate, I3cPushPullRate, I2cPullUp, I2cBus, DeviceModel, StatusCode, …). These are not int subclasses: SpiMode.MODE_0 == 0 is False. Pass the member, never a literal.

Bound from C++, arithmetic. The eight enum.IntEnums (GpioPinNumber, GpioFunctionality, GpioLogicLevel, I3cConnectorPort, I3cConnectorEvent, I3cConnectorType, I3cTargetBusEventKind, I3cTargetDcr) plus the three enum.IntFlags (GpioTriggerType, I3cEvent, I3cTransferFlags). Nearly all of them are arithmetic because their values turn up as raw int fields on notifications or are bitwise-combinable flags, and being arithmetic is load-bearing there: n.pin_number == GpioPinNumber.PIN_3 holds only because of it. See the warning on the GPIO guide. GpioFunctionality is the one member of this group that is neither — it is only ever a configure_pin argument — and it is arithmetic for consistency with the other GPIO enums rather than because anything compares it against an int.

Python-only. Nine enums have no native counterpart. Seven are StrEnums: DeviceState, ResetTarget, ProtocolInterface, SpiTransport, I3cTransport, I2cTransport and BulkOperation. The three transport enums are the ones easiest to mistake for bound enums, because they are documented in their protocols’ sections below alongside the C++-bound ladders — but a transport value never crosses into the extension at all: AUTO is resolved in Python and the result selects which call to make, so there is no firmware number for a member to mirror and nothing to compare it against. BulkOperation is Python-only for the same reason: support is decided in Python from the integer triples the device’s capability query returns.

I2cTargetBusEventKind and SpiTargetBusEventKind are the eighth and ninth, and they are the exceptions to that rule: both are enum.IntEnum rather than StrEnum, because their values do arrive from the device — as plain int fields on I2cTargetBusEventNotification and SpiTargetBusEventNotification — so a comparison against a raw notification value has to succeed. That is the same rule the bound device-ward enums follow; these two are Python-side only because firmware puts no event-kind enum in its headers for I2C or SPI. Each notification’s field is a bare byte, and these name the values it currently takes: WRITE_TRANSFER and READ_TRANSFER for I2C, and for SPI a single TRANSACTION_COMPLETE.

SpiTargetBusEventKind having exactly one member makes the raw-int arm of SpiTargetBusEvent.kind matter more there than anywhere else: it is the only thing that will make a future second kind visible instead of dropping the event.

The C++-bound enums carry no per-member prose — CosmicSDK’s own enums have none to bind — so their members below are listed as bare name/value pairs.

StrEnum itself is re-exported for Python 3.10, where enum.StrEnum does not exist yet; on 3.11+ it is enum.StrEnum.

Note

A notification field that carries a raw firmware value stays an int rather than being coerced into an enum, so a value this release does not name still arrives instead of raising. Compare against the members you care about; do not assume the set is closed, and do not call SomeEnum(raw_value) inside a where= predicate.

class pycosmicsdk.StrEnum(new_class_name, /, names, *, module=None, qualname=None, type=None, start=1, boundary=None)

Bases: str, ReprEnum

Enum where members are also (and must be) strings

Device

class pycosmicsdk.DeviceModel(*values)

Bases: Enum

UNKNOWN = 0
SUPERNOVA = 1
PULSAR = 2
class pycosmicsdk.DeviceState(*values)

Bases: StrEnum

Lifecycle state of a Device instance.

Exposed as Device.state so callers can detect TERMINAL (entered after reboot()) without having to issue a call that raises.

NEW = 'new'
OPEN = 'open'
TERMINAL = 'terminal'
CLOSED = 'closed'
class pycosmicsdk.ResetTarget(*values)

Bases: StrEnum

Target mode for Device.reboot(into=...).

Replaces the legacy reset() / enter_boot_mode() / enter_isp_mode() triad with a single call parameterised by a member of this enum.

RUNTIME = 'runtime'
BOOT = 'boot'
ISP = 'isp'
class pycosmicsdk.ProtocolInterface(*values)

Bases: StrEnum

Protocol interface a Binho device can expose.

Used in DeviceCapabilities.protocols to declare which protocols a given firmware build supports. The full set is enumerated here even when a particular release ships bindings for only a subset, so callers can write forward-compatible code.

I2C = 'i2c'
I3C = 'i3c'
I3C_TARGET = 'i3c_target'
SPI = 'spi'
UART = 'uart'
GPIO = 'gpio'

I2C

class pycosmicsdk.I2cBus(*values)

Bases: Enum

A = 0
B = 1
class pycosmicsdk.I2cPullUp(*values)

Bases: Enum

OHM_150 = 0
OHM_220 = 1
OHM_330 = 2
OHM_470 = 3
OHM_680 = 4
KOHM_1_0 = 5
KOHM_1_5 = 6
KOHM_2_2 = 7
KOHM_3_3 = 8
KOHM_4_0 = 9
KOHM_4_7 = 10
KOHM_10_0 = 11
DISABLE = 12
class pycosmicsdk.I2cOpenDrainRate(*values)

Bases: Enum

STANDARD_MODE = 0
FAST_MODE = 1
FAST_MODE_PLUS = 2
HIGH_SPEED_MODE = 3
ULTRA_FAST_MODE = 4
class pycosmicsdk.I2cTransport(*values)

Bases: StrEnum

Which host transport carries an I2C controller payload.

The I2C counterpart of SpiTransport, passed as transport= to I2cController.write and I2cController.read. Like SpiTransport it names a host-side transport and not a bus mode: all three members clock the same frames on the same pins at the same rate, and the only observable difference is the payload ceiling one call accepts.

``AUTO`` means something narrower here than it does for SPI, and the difference is deliberate. SpiTransport.AUTO prefers the bulk plane whenever it is available. I2cTransport.AUTO takes the ordinary HID route for every request that fits its 1024-byte ceiling and reaches for bulk only above it. Two reasons, and both are specific to I2C:

  • There is nothing to win below the ceiling. Upstream says so in i2cWriteBulk’s own note: “I2C is bus-limited long before the transport is, so the gain here is smaller than for SPI – what it removes is the per-1024-byte command round trip, not the bus time.” A 4-byte register write is bus-bound either way.

  • There is something to lose. I2cController.write and I2cController.read are shipped methods with existing callers, unlike SpiController.write which was new when its AUTO was designed. The bulk route acquires the device’s shared bulk-staging pool – the same pool an armed I2C or SPI target draws its arena from – so routing every small write through it would expose existing callers to a contention failure they cannot have today, for no throughput gain.

So AUTO is the transport that never changes the wire for a call that already worked, and lifts the ceiling for one that could not. I2cController.max_transfer_bytes reports how far it reaches on a given connection.

AUTO

Ordinary HID route up to its 1024-byte ceiling, bulk above it when this host and device can. The default, and the portable choice.

BULK

Require the bulk plane, at every size. Raises CapabilityError before any request is sent when it is unavailable – including on a build whose device facade carries no i2c_write_bulk, which the refusal names as the missing piece rather than blaming the host or the device. For benchmarks that must not silently measure the wrong transport.

HID

Never use the bulk plane. Skips the capability negotiation entirely, so it sends nothing extra, and keeps the 1024-byte ceiling whatever the device offers.

I2C — target mode

class pycosmicsdk.I2cTargetModel(*values)

Bases: Enum

MEMORY = 0
EEPROM = 1
REGISTER_MAP = 2
class pycosmicsdk.I2cTargetAddressMode(*values)

Bases: Enum

BIT_7 = 0
BIT_10 = 1
class pycosmicsdk.I2cTargetMemoryLayout(*values)

Bases: Enum

BIT_8 = 0
BIT_16 = 1
class pycosmicsdk.I2cTargetRegisterAccess(*values)

Bases: Enum

RW = 0
RO = 1
WO = 2
RC = 3
W1C = 4
RESERVED = 5
class pycosmicsdk.I2cTargetEraseScope(*values)

Bases: Enum

PAGE = 0
CHIP = 1
class pycosmicsdk.I2cTargetEepromBusyBehavior(*values)

Bases: Enum

NACK = 0
CLOCK_STRETCH = 1
class pycosmicsdk.I2cTargetBusEventKind(*values)

Bases: IntEnum

What an external I2C controller did to a target the adapter is acting as.

Carried by I2cTargetBusEvent.kind. The I2C counterpart of the bound I3cTargetBusEventKind, and Python-side rather than bound for the same reason SpiTargetBusEventKind is: definitions.h declares no event-kind enum for the I2C bus event, so the notification’s event field arrives as a bare byte and this names the values firmware puts in it.

An IntEnum, like the SPI twin and unlike this module’s device-ward enums: the value does arrive from the device, as an int field on I2cTargetBusEventNotification, so a comparison against a raw notification value has to succeed.

The two members are I2cTargetBusEvent_t in firmware’s common_types/i2c_definitions.h:478-:481, mirrored by hand; docs_dev/hardware_validation/firmware-notifications-and-status.md section 2.1 carries the citation. The I2C event is emitted once per transfer phase, with every phase flushed at the STOP – so an ordinary write or read is one event, the same count the SPI event gives for one chip-select frame. Measured on silicon 2026-09-04, writes and reads from 0 to 1024 bytes, with no chunking at any size; I2cTarget.wait_for_event carries the model in full, including why a held bus reports nothing at all.

WRITE_TRANSFER

The external controller wrote to this target. The bytes landed in the arena at memory_address; read them back with I2cTarget.read_memory, accepting that the region is live.

READ_TRANSFER

The external controller read from this target, served out of the arena at memory_address.

I3C — controller

class pycosmicsdk.I3cPushPullRate(*values)

Bases: Enum

PUSH_PULL_2_5_MHZ_DC_10 = 0
PUSH_PULL_2_5_MHZ_DC_15 = 1
PUSH_PULL_2_5_MHZ_DC_20 = 2
PUSH_PULL_2_5_MHZ_DC_25 = 3
PUSH_PULL_3_125_MHZ_DC_12_5 = 4
PUSH_PULL_3_125_MHZ_DC_18_75 = 5
PUSH_PULL_3_125_MHZ_DC_25 = 6
PUSH_PULL_3_125_MHZ_DC_31_25 = 7
PUSH_PULL_5_MHZ_DC_20 = 8
PUSH_PULL_5_MHZ_DC_30 = 9
PUSH_PULL_5_MHZ_DC_40 = 10
PUSH_PULL_5_MHZ_DC_50 = 11
PUSH_PULL_6_25_MHZ_DC_25 = 12
PUSH_PULL_6_25_MHZ_DC_37_5 = 13
PUSH_PULL_6_25_MHZ_DC_50 = 14
PUSH_PULL_7_5_MHZ_DC_30 = 15
PUSH_PULL_7_5_MHZ_DC_45 = 16
PUSH_PULL_10_MHZ_DC_40 = 17
PUSH_PULL_12_5_MHZ_DC_50 = 18
PUSH_PULL_1_MHZ_DC_40 = 19
PUSH_PULL_400_KHZ_DC_46 = 20
PUSH_PULL_100_KHZ_DC_34 = 21
class pycosmicsdk.I3cOpenDrainRate(*values)

Bases: Enum

OPEN_DRAIN_100_KHZ = 0
OPEN_DRAIN_400_KHZ = 1
OPEN_DRAIN_1_MHZ = 2
OPEN_DRAIN_2_MHZ = 3
OPEN_DRAIN_4_17_MHZ = 4
class pycosmicsdk.I3cDriveStrength(*values)

Bases: Enum

STANDARD = 0
FAST = 1
class pycosmicsdk.I3cSdaPullUp(*values)

Bases: Enum

AUTO = 0
OFF = 1
ON = 2
class pycosmicsdk.I3cTransferDirection(*values)

Bases: Enum

WRITE = 0
READ = 1
class pycosmicsdk.I3cTransferFlags(*values)

Bases: IntFlag

NONE = 0
NONSTOP = 1
START_WITH_7E = 2
class pycosmicsdk.I3cEvent(*values)

Bases: IntFlag

IBI = 1
CR = 2
HJ = 8
class pycosmicsdk.I3cTransport(*values)

Bases: StrEnum

Which host transport carries an I3C controller private transfer.

The I3C counterpart of SpiTransport, passed as transport= to the six I3cController transfer methods – I3cController.sdr_write, I3cController.sdr_read, I3cController.hdr_ddr_write, I3cController.hdr_ddr_read, I3cController.legacy_i2c_write and I3cController.legacy_i2c_read – and returned by I3cController.transport. Like SpiTransport it names a host-side transport and not a bus mode: all three members clock the same frames on the same pins, and the only thing that changes is where the payload travels and therefore how large it may be.

A separate enum rather than a reuse of SpiTransport, because a call site reading transport=SpiTransport.BULK on an I3C method would be actively misleading about which bus it addresses.

The three modes do not benefit equally, and the enum cannot express that – so read this before assuming a uniform speedup:

  • SDR is the mode with a real gain. The ordinary route carries its bytes inside the request and so cannot exceed 1024; the bulk route reaches whatever the device advertises for GROUP_I3C (32 KB on a Supernova). On a write the register sub-address shares the frame with the payload, so the usable payload is the ceiling minus len(subaddress); a read has no such deduction.

  • HDR-DDR gains nothing today, and asking for the advertised GROUP_I3C ceiling in this mode would be actively dangerous. DDR is capped at 1024 bytes in both firmware and this SDK, and the cap is not a buffer size: above roughly 2048 bytes the target stops answering its dynamic address and stays that way until re-enumeration. So the ordinary route already reaches the cap, the bulk route cannot exceed it, and the bulk entry points exist so the route covers every mode and lifting the cap later is not a new API. See pycosmicsdk._constants.I3C_HDR_DDR_MAX_PAYLOAD_BYTES.

  • Legacy I2C on an I3C bus is bounded by its own bus rate long before the transport matters, so expect a smaller gain than from SDR.

Note

I3cTarget takes no transport argument and never will. Its memory commands are HID-carried at a fixed 1024 bytes out of a private buffer rather than the shared bulk staging pool, and are absent from the I3C command mask – deliberately, in firmware.

AUTO

Use the bulk plane when this host and device can, and the ordinary HID route otherwise. The default, and the portable choice: one code path that works everywhere and gets faster where it can.

BULK

Require the bulk plane. Raises CapabilityError before any request is sent when it is unavailable, and the message names which of the four independent gaps applies – this build’s bindings, this host’s driver, this device’s firmware, or a model with no I3C hardware. For benchmarks that must not silently measure the wrong transport.

HID

Never use the bulk plane. Skips the capability negotiation entirely, so it sends nothing extra, and keeps the 1024-byte ceiling. The way a test forces the fallback, and the only route on a Pulsar, which has no I3C hardware at all.

I3C — target mode

class pycosmicsdk.I3cTargetMemoryLayout(*values)

Bases: Enum

MEMORY_1_BYTE_X_1024_REGS = 0
MEMORY_2_BYTES_X_512_REGS = 1
MEMORY_4_BYTES_X_256_REGS = 2
class pycosmicsdk.I3cTargetDcr(*values)

Bases: IntEnum

SECONDARY_CONTROLLER = 196
MEMORY = 197
MICROCONTROLLER = 198
class pycosmicsdk.I3cTargetResetDefByte(*values)

Bases: Enum

NO_RESET = 0
RESET_I3C_PERIPHERAL = 1
RESET_WHOLE_TARGET = 2
RESET_DEBUG_NETWORK = 3
VIRTUAL_TARGET_DETECT = 4
RETURN_TIME_RESET_PERIPHERAL = 129
RETURN_TIME_RESET_WHOLE_TARGET = 130
RETURN_TIME_DEBUG_NETWORK_RESET = 131
RETURN_VIRTUAL_TARGET_INDICATION = 132
class pycosmicsdk.I3cTargetBusEventKind(*values)

Bases: IntEnum

WRITE_TRANSFER = 0
READ_TRANSFER = 1
CCC_TRANSFER = 2
DYN_ADDR_CHANGE = 3

I3C — connector

class pycosmicsdk.I3cConnectorPort(*values)

Bases: IntEnum

LV = 0
HV = 1
class pycosmicsdk.I3cConnectorEvent(*values)

Bases: IntEnum

PLUGGED = 0
UNPLUGGED = 1
class pycosmicsdk.I3cConnectorType(*values)

Bases: IntEnum

UNIDENTIFIED = 0
HARNESS = 1
QWIIC_ADAPTER = 2
SENSEPEEK = 3
NONE = 4
ERROR = 5

UART

class pycosmicsdk.UartBaudRate(*values)

Bases: Enum

BAUD_600 = 0
BAUD_1200 = 1
BAUD_2400 = 2
BAUD_4800 = 3
BAUD_9600 = 4
BAUD_14400 = 5
BAUD_19200 = 6
BAUD_38400 = 7
BAUD_56000 = 8
BAUD_57600 = 9
BAUD_115200 = 10
class pycosmicsdk.UartParity(*values)

Bases: Enum

NONE = 0
EVEN = 1
ODD = 2
class pycosmicsdk.UartDataSize(*values)

Bases: Enum

BITS_7 = 0
BITS_8 = 1
class pycosmicsdk.UartStopBit(*values)

Bases: Enum

ONE = 0
TWO = 1
class pycosmicsdk.UartHwHandshake(*values)

Bases: Enum

DISABLED = 0
ENABLED = 1

SPI

class pycosmicsdk.SpiMode(*values)

Bases: Enum

MODE_0 = 0
MODE_1 = 1
MODE_2 = 2
MODE_3 = 3
class pycosmicsdk.SpiBitOrder(*values)

Bases: Enum

MSB = 0
LSB = 1
class pycosmicsdk.SpiDataWidth(*values)

Bases: Enum

BITS_8 = 0
BITS_16 = 1
class pycosmicsdk.SpiChipSelect(*values)

Bases: Enum

CS_0 = 0
CS_1 = 1
CS_2 = 2
CS_3 = 3
class pycosmicsdk.SpiChipSelectPolarity(*values)

Bases: Enum

ACTIVE_LOW = 0
ACTIVE_HIGH = 1
class pycosmicsdk.SpiTransport(*values)

Bases: StrEnum

Which host transport carries a large SPI payload.

Passed as transport= to SpiController.write and SpiController.read, and returned by SpiController.transport. It names a host-side transport, not a bus mode: all three members drive the same SPI pins, and the only observable difference between them is the maximum payload one call accepts.

A StrEnum rather than an IntEnum on purpose. The value never crosses into the C++ extension – AUTO is resolved in Python and the result selects which facade method to call – so there is no firmware number for a member to mirror, and an IntEnum would invite a comparison against a wire value that does not exist. This matches DeviceState, ResetTarget and ProtocolInterface, the package’s other three Python-only enums.

AUTO

Use the bulk plane when it is available on this host and device, and the HID path otherwise. The default, and the portable choice: one code path that works everywhere and gets faster where it can.

BULK

Require the bulk plane. Raises CapabilityError before any request is sent when it is unavailable – which today is always, since no installed build carries the bulk surface. For benchmarks that must not silently measure the wrong transport.

HID

Never use the bulk plane. Skips the capability negotiation entirely, so it sends nothing extra, and is the way a test forces the fallback.

SPI — target mode

class pycosmicsdk.SpiTargetModel(*values)

Bases: Enum

MEMORY = 0
FLASH = 1
REGISTER_MAP = 2
class pycosmicsdk.SpiTargetEngine(*values)

Bases: Enum

DMA = 0
ISR = 1
class pycosmicsdk.SpiTargetBusEventKind(*values)

Bases: IntEnum

What an external SPI controller did to a target the adapter is acting as.

Carried by SpiTargetBusEvent.kind. The SPI counterpart of the bound I3cTargetBusEventKind, and Python-side rather than bound because firmware puts no event-kind enum in definitions.h for SPI: the notification’s field is a bare byte, and this names the one value it currently takes.

An IntEnum, unlike this module’s device-ward Python-only enums, for the reason those are deliberately not: the value does arrive from the device, as an int field on SpiTargetBusEventNotification, so a comparison against a raw notification value has to succeed. That is the same rule native/bindings/enums.cpp applies when it binds I3cTargetBusEventKind arithmetic and every device-ward enum plain.

One member today, so the raw-integer arm of `SpiTargetBusEvent.kind` matters more here than it does for I3C: it is the only thing that will make a future second kind visible instead of dropping the event.

TRANSACTION_COMPLETE

A chip-select assertion, transfer and de-assertion completed. The event says that a transaction happened, on which chip select, and how many bytes moved; the bytes are not carried, and where they landed is not carried either – memory_address is hard-coded to 0 in firmware. Read them back with SpiTarget.read_memory at an offset you supply.

GPIO

class pycosmicsdk.GpioPinNumber(*values)

Bases: IntEnum

PIN_1 = 0
PIN_2 = 1
PIN_3 = 2
PIN_4 = 3
PIN_5 = 4
PIN_6 = 5
class pycosmicsdk.GpioFunctionality(*values)

Bases: IntEnum

DIGITAL_INPUT = 0
DIGITAL_OUTPUT = 1
class pycosmicsdk.GpioLogicLevel(*values)

Bases: IntEnum

LOW = 0
HIGH = 1
class pycosmicsdk.GpioTriggerType(*values)

Bases: IntFlag

RISING_EDGE = 1
FALLING_EDGE = 2
BOTH_EDGES = 3

The bulk transfer plane

class pycosmicsdk.BulkOperation(*values)

Bases: StrEnum

One bulk-carried operation the connected device may or may not implement.

The vocabulary of BulkTransportCapability.supports, and the reason that method exists rather than a boolean per protocol: the device advertises bulk support per command, while it advertises a payload ceiling per command group. Those are two different questions with two different answers, and collapsing them was a real defect – a device offering the SPI target memory pair but no SPI controller bulk read as a device with no bulk plane at all, because support was being derived from the group.

Members are named for the operation rather than for upstream’s command code, because one operation can be more than one command (I3C is one command carrying both directions) and because a caller reasons about “can my write go fast”, not about 0x0D07.

I3C_CONTROLLER_TRANSFER is one member covering six SDK methods, and that is not a shortcut. The device implements exactly one bulk I3C command, I3C_CONTROLLER_PRIVATE_TRANSFER_BULK (0x190B) – dispatched at i3c_mgr.c:2869, _Static_assert-ed at :226, advertised at sys_mgr.c:514-:517 inside #ifdef CPU_LPC5536JBD100 – and CosmicSDK’s origin/feat/i2c-i3c-controller-bulk (59fa171) wraps it six times, once per transfer mode and direction: i3cSdrWriteBulk / i3cSdrReadBulk, i3cHdrDdrWriteBulk / i3cHdrDdrReadBulk, and i3cLegacyI2cWriteBulk / i3cLegacyI2cReadBulk. All six ride the one command and therefore share the one mask bit, so there is exactly one question the device can be asked and one member to ask it with. Splitting it into six would invent five answers the wire cannot distinguish.

Supernova only. The capability entry is compiled out on the part with no I3C peripheral, so a Pulsar advertises no I3C group at all and this member is never in operations for one.

What the member does not tell you is how much each mode gains. Support is uniform; benefit is not. SDR is the mode with a real gain – the ordinary route carries its bytes inside the request and cannot exceed 1024. HDR-DDR gains nothing today, because it is capped at 1024 in both firmware and the SDK for bus-safety reasons that have nothing to do with the transport, and the ordinary route already reaches that. Legacy I2C on an I3C bus is bounded by its own bus rate long before the transport matters. See I3cTransport and pycosmicsdk._constants.I3C_HDR_DDR_MAX_PAYLOAD_BYTES.

There is deliberately no I3C target member, and this is the half of “I3C has no bulk path” that survives. I3C target memory is HID-carried at a fixed 1024 bytes out of a private buffer rather than the shared staging pool, and is correspondingly absent from the I3C command mask – while the I2C and SPI target-memory commands were added to theirs. That is a design choice in firmware, not an omission, so a member for it would be a value that can never be True.

The I2C controller pair is here now, which is the change that note used to anticipate: the device implements I2C_CONTROLLER_WRITE_BULK (0x0907) and I2C_CONTROLLER_READ_BULK (0x0908), and origin/feat/i2c-i3c-controller-bulk (59fa171) wraps them as i2cWriteBulk / i2cReadBulk – one wrapper per command, unlike the I3C member’s six-to-one, so the two members map one-for-one onto two mask bits.

A StrEnum rather than an IntEnum, for the same reason as SpiTransport: the value never crosses into the C++ extension – support is decided in Python from the integer triples the capability query returns – so there is no firmware number for a member to mirror.

SPI_CONTROLLER_WRITE

CMD_SPI_CONTROLLER_WRITE_BULK, the large SPI write whose MISO bytes are discarded.

SPI_CONTROLLER_READ

CMD_SPI_CONTROLLER_READ_BULK, a short command phase followed by a large read under one chip select.

SPI_TARGET_WRITE_MEMORY

CMD_SPI_TARGET_WRITE_MEMORY, preloading the SPI target arena. Bulk-only – there is no HID variant.

SPI_TARGET_READ_MEMORY

CMD_SPI_TARGET_READ_MEMORY, reading the SPI target arena back. Bulk-only.

I2C_TARGET_WRITE_MEMORY

CMD_I2C_TARGET_WRITE_MEMORY, preloading the I2C target arena. Bulk-only.

I2C_TARGET_READ_MEMORY

CMD_I2C_TARGET_READ_MEMORY, reading the I2C target arena back. Bulk-only.

I2C_CONTROLLER_WRITE

I2C_CONTROLLER_WRITE_BULK, the large-payload counterpart of an ordinary I2C write. Addressing still travels in the request; only the payload moves endpoint.

I2C_CONTROLLER_READ

I2C_CONTROLLER_READ_BULK, the read half of the same pair. What either one removes is the per-1024-byte command round trip, not the bus time – I2C is bus-limited long before the transport is.

I3C_CONTROLLER_TRANSFER

I3C_CONTROLLER_PRIVATE_TRANSFER_BULK, a controller private transfer in any of I3C’s three modes and either direction – one firmware command, one mask bit, six SDK methods. Supernova only. Per the note above, a True here says the route exists, not that every mode is faster over it.

Status codes

class pycosmicsdk.StatusCode(*values)

Bases: Enum

SUCCESS = 0
FW_UNSUPPORTED_COMMAND = 1
FW_INVALID_COMMAND = 2
FW_FULL_RECEPTION_QUEUE = 3
FW_INVALID_PARAMETER = 4
FW_FEATURE_NOT_SUPPORTED_BY_HARDWARE = 5
FW_INTERFACE_NOT_INITIALIZED = 6
FW_INTERFACE_ALREADY_INITIALIZED = 7
FW_BUS_NOT_SUPPORTED = 8
FW_BUS_TIMEOUT = 9
FW_RX_FIFO_FULL = 10
FW_TX_FIFO_EMPTY = 11
FW_UNHANDLED_ERROR = 12
FW_INTERFACE_UNAVAILABLE_IN_CDC_MODE = 13
FW_RESOURCE_BUSY = 14
FW_VOLTAGE_OUT_OF_RANGE = 257
FW_EXTERNAL_VOLTAGE_DETECTED = 258
FW_VOLTAGE_ADJUSTMENT_FAILURE = 259
FW_I3C_PORTS_NOT_POWERED = 260
FW_BOTH_I3C_PORTS_POWERED = 261
FW_VOLTAGE_OUT_OF_RANGE_ON_I3C_LV = 262
FW_VOLTAGE_OUT_OF_RANGE_ON_I3C_HV = 263
FW_SETTINGS_SAVE_FAILED = 264
FW_SHELL_MODE_ACTIVE = 265
FW_I2C_PULLUP_RESISTOR_SETTING_FAILURE = 513
FW_I2C_ARBITRATION_LOST = 514
FW_I2C_NACK_ADDRESS = 515
FW_I2C_NACK_BYTE = 516
FW_I2C_BIT_ERROR = 517
FW_I2C_START_STOP_ERROR = 518
FW_I2C_BUSY = 519
FW_I2C_TIMEOUT_CONTINUE_TRANSFER = 520
FW_I2C_TIMEOUT_WAITING_BUS_EVENT = 521
FW_I2C_TIMEOUT_SCL_LOW = 522
FW_I2C_DMA_REQUEST_FAIL = 523
FW_I2C_INVALID_PARAMETER = 524
FW_I2C_NO_TRANSFER_IN_PROGRESS = 525
FW_I2C_UNEXPECTED_STATE = 526
FW_I2C_BUS_WITH_NO_TARGETS_CONNECTED = 527
FW_I2C_TARGET_STAGING_UNAVAILABLE = 528
FW_I2C_TARGET_SURPASSED_MEMORY_SIZE = 529
FW_I2C_TARGET_PAYLOAD_TRANSFER_FAILED = 530
FW_I2C_TARGET_WRONG_MODEL = 531
FW_I2C_TARGET_INVALID_CONFIG = 532
FW_I2C_TARGET_REGION_TABLE_FULL = 533
FW_I2C_ROLE_CONFLICT = 534
FW_SPI_TARGET_STAGING_UNAVAILABLE = 784
FW_SPI_TARGET_SURPASSED_MEMORY_SIZE = 785
FW_SPI_TARGET_PAYLOAD_TRANSFER_FAILED = 786
FW_SPI_TARGET_WRONG_MODEL = 787
FW_SPI_TARGET_INVALID_CONFIG = 788
FW_SPI_TARGET_REGION_TABLE_FULL = 789
FW_SPI_ROLE_CONFLICT = 790
FW_UART_IN_VCOM_PORT_MODE = 1025
FW_GPIO_NOT_CONFIGURED = 1281
FW_GPIO_WRONG_CONFIGURATION = 1282
FW_FULL_TARGET_DEVICES_TABLE = 1537
FW_NOT_ENOUGH_SPACE_IN_TARGET_DEVICES_TABLE = 1538
FW_TARGET_DEVICES_TABLE_OVERFLOW = 1539
FW_TARGET_ADDRESS_NOT_FOUND_IN_THE_TABLE = 1540
FW_REPEATED_TARGET_ADDRESS = 1541
FW_INVALID_TARGET_ADDRESS = 1542
FW_I3C_BUS_INIT_NACK_RSTDAA = 1543
FW_I3C_BUS_INIT_NACK_SETDASA = 1544
FW_I3C_BUS_INIT_NACK_SETAASA = 1545
FW_I3C_BUS_INIT_NACK_ENTDAA = 1546
FW_I3C_NACK_ADDRESS = 1547
FW_I3C_I2C_NACK_BYTE = 1548
FW_I3C_TRANSFER_ABORTED_BY_CONTROLLER = 1549
FW_I3C_TRANSFER_MWL_REACHED = 1550
FW_I3C_TRANSFER_MRL_REACHED = 1551
FW_I3C_TRANSFER_PARITY_ERROR = 1552
FW_IBI_REQUEST_ACCEPTED = 1553
FW_IBI_REQUEST_ACCEPTED_WITH_PAYLOAD = 1554
FW_IBI_REQUEST_REJECTED = 1555
FW_HJ_REQUEST_ACCEPTED = 1556
FW_HJ_REQUEST_REJECTED = 1557
FW_REGISTER_ADDRESS_OUT_OF_RANGE = 1558
FW_SURPASSED_MEMORY_SIZE = 1559
FW_I3C_TRANSFER_CRC_ERROR = 1560
FW_I3C_ENGINE_BUSY = 1561
FW_I3C_TRANSFER_INCOMPLETE_READ = 1562
FW_I3C_I2C_CLOCK_STRETCHING_ACTIVE = 1563
FW_SWD_HOST_SESSION_ACTIVE = 7937
FW_TEARDOWN_PENDING = 7938
FW_PIN1_OVERVOLTAGE = 7939
SDK_ERROR_TIMEOUT = 8192
SDK_ERROR_DISCONNECT = 16384
SDK_ERROR_UNEXPECTED_RESPONSE = 24576
SDK_ERROR_WRONG_REQUEST = 32768
SDK_ERROR_WRONG_RESPONSE = 40960
SDK_ERROR_BULK_UNAVAILABLE = 49152