Skip to content
binho.io (opens in a new tab)Contact Us

PyCosmicSDK

pycosmicsdk is the Python SDK for the Binho Supernova and Binho Pulsar host adapters and the Binho Atira debug probe. One package covers all three and every protocol they offer. The host adapters use a blocking API (Device) and an asyncio API (AsyncDevice); the Atira uses DebugProbe and AsyncDebugProbe.

It replaces the older per-product packages (BinhoSupernova, SupernovaController and BinhoPulsar) and ships drop-in compatibility layers for them, so existing scripts keep working during the move. See Migrating to PyCosmicSDK.

ProtocolWhat it can doSupernovaPulsarAtira
I2CController (write, read, bus scan) and target modeBus ABuses A and BNo
I3CController, Common Command Codes (CCCs), target modeYesNoNo
SPIController and target modeController; target mode not on rev BYesController, with SPI flash programming
UARTSend, query and receiveYesYesBridge port
GPIODigital I/O and interruptsYesYesNo

The Atira is a debug probe. Besides SPI and the UART bridge, DebugProbe covers target power and SWD debug. It needs PyCosmicSDK 1.7.0 or newer. See Binho Atira and the debug probe guide.

Large transfers travel over a second USB pipe instead of the ordinary 1024-byte limit: up to 32,768 bytes on a Supernova (32,767 for I3C) and 16,384 bytes on a Pulsar. The SDK asks the adapter for its limit, so the limit never needs hard-coding. See Large transfers.

  • Python 3.10 to 3.14.
  • One of: Windows (x64), macOS on Apple Silicon, or Linux (x86_64). Other platforms, such as Intel Macs and Linux on ARM, have no package yet.
  • A Binho Supernova or Pulsar running firmware 4.x, or a Binho Atira running Atira firmware 1.0 or newer. Firmware 3.x cannot be reached by this package; see Updating Firmware.
  • On Linux, allow the current user to access the adapter once: Solving USB Connection Issues on Linux. Windows and macOS need no driver install.
pip install pycosmicsdk

The package includes everything it needs, the native USB library included, so there is nothing else to install.

https://pypi.org/project/pycosmicsdk/

list_devices() reads each connected adapter’s model, serial number and firmware version straight from USB, without opening it:

from pycosmicsdk import list_devices
for found in list_devices():
print(found.model.name, found.serial_number, "firmware", found.fw_version)
  • A version like 4.6.1 is ready to use.
  • 3.x.x means firmware 3.x: update the firmware before using this package.
  • bootloader means the adapter is waiting in its bootloader instead of running firmware.

Opening an adapter whose firmware is too old raises an SDK error that says so, instead of timing out.

This example opens the first adapter it finds, brings up I2C bus A at 400 kHz, scans the bus, and writes and reads back three bytes of an I2C EEPROM at address 0x50:

import time
from pycosmicsdk import Device, I2cBus, I2cPullUp, list_devices
# List every connected adapter. This only reads USB information; it opens nothing.
for found in list_devices():
print(found.model.name, found.serial_number, "firmware", found.fw_version)
# Open the first adapter found (or pass serial="..." to pick one).
with Device.open() as dev:
i2c = dev.i2c(bus=I2cBus.A)
i2c.set_voltage(voltage_mv=3300) # target voltage first
i2c.bring_up(frequency_hz=400_000, pull_up=I2cPullUp.KOHM_2_2)
print("Devices on the bus:", [hex(a) for a in i2c.scan().addresses_7bit])
i2c.write(0x50, b"\x01\x02\x03", subaddress=b"\x00\x10") # 3 bytes at 0x0010
time.sleep(0.01) # an EEPROM ignores its address while it finishes the write
print("Read back:", i2c.read(0x50, 3, subaddress=b"\x00\x10").hex())
  • Device.open() also accepts serial="...", model=... or path="..." when more than one adapter is connected.
  • bring_up() can be run again safely: if the bus is already up, it applies the new settings instead of failing.
  • The other protocols follow the same pattern: dev.i3c(), dev.spi(), dev.uart(), dev.gpio(), and dev.i2c_target(), dev.spi_target() and dev.i3c_target() for target mode.

Every class has an asyncio twin with the same methods. Use AsyncDevice in place of Device and await each call:

import asyncio
from pycosmicsdk import AsyncDevice, I2cBus, I2cPullUp
async def main() -> None:
async with AsyncDevice.open() as dev:
i2c = dev.i2c(bus=I2cBus.A)
await i2c.set_voltage(voltage_mv=3300)
await i2c.bring_up(frequency_hz=400_000, pull_up=I2cPullUp.KOHM_2_2)
print([hex(a) for a in (await i2c.scan()).addresses_7bit])
asyncio.run(main())

Every error the SDK raises derives from CosmicError and carries the status_code the adapter or the SDK reported. Catch the subclass that can be acted on:

ErrorMeaning
ValidationErrorThe call was rejected before anything was sent to the adapter.
CapabilityErrorThis adapter model or hardware revision cannot do it. Nothing was sent.
FirmwareError (I2cError, I3cError, SpiError, …)The adapter refused the command. exc.status_code says why, for example FW_I2C_NACK_ADDRESS.
CosmicTimeoutErrorNo answer in time. Also caught by except TimeoutError.

The errors reference lists every error and status code.

The SDK comes with more than 50 runnable example scripts, one folder per protocol, for both the blocking and the asyncio API. PyCosmicSDK Examples has the download link, how to run them, and copy-paste snippets for I2C, SPI, I3C, UART and GPIO.

The full documentation is at binhollc.github.io/pycosmicsdk. Start with the guide for the protocol:

GuideCovers
I2CBring-up, pull-ups, duty cycle, write, read, scan
I3CBus voltage and ports, dynamic addressing, SDR and HDR-DDR transfers, CCCs, legacy I2C on the I3C port
SPIModes, chip selects, full-duplex and half-duplex transfers
UARTBaud rates, request/response, streaming reception
GPIODigital I/O and interrupts
Large transfersThe bulk USB pipe and its size limits
Target modeThe adapter as an I2C, SPI or I3C target
Device lifecycleDiscovery, opening by serial or model, closing, rebooting
TestingTesting code without an adapter, using pycosmicsdk.testing

Also in the documentation:

With firmware 4.7.0 or later (coming soon), set_voltage() on a port that already has an external supply leaves the adapter’s supply off and raises an error with status FW_EXTERNAL_VOLTAGE_DETECTED (0x0102).

If something does not work as described here, contact us or email [email protected]. Include:

  • the version printed by python -c "import pycosmicsdk; print(pycosmicsdk.__version__)",
  • the Python version and operating system,
  • the output of the list_devices() example above (model, serial number, firmware),
  • the full traceback, or the status_code of the error raised.