Changelog

This page tracks changes between CosmicSDK releases.

v1.9.0

Adds target flashing to the debug probe: DebugProbe programs a target’s internal flash through the vendor’s CMSIS flash algorithm (.FLM), without pyOCD or Ground Control (#358). The host adapter API does not change. Minimum probe firmware stays fw-atira v1.0.

  • New Features (debug probe)

    • Target flash (8 methods, debugprobe/TargetFlash.hpp): targetFlashLoadAlgorithm takes the .FLM bytes and a RAM window and checks them on the host; targetFlashWrite erases the touched sectors, programs and optionally verifies in one algorithm session; targetFlashEraseRange, targetFlashProgram and targetFlashVerify do one step each; targetFlashGetLastReport, targetFlashGetInfo and targetFlashUnloadAlgorithm. The C API mirrors them as DebugProbe_TargetFlash* (8 functions).

    • targetFlashEraseChip erases the whole flash region: the FLM’s EraseChip when it has one, else every sector (#453). TargetFlashReport gives the erased range, erasedAddr + erasedBytes: sectors are erased whole, so it can reach past the requested range (#452). C: DebugProbe_TargetFlashEraseChip, DebugProbe_TargetFlashGetLastErasedRange, DEBUGPROBE_TFLASH_ROUTINE_ERASE_CHIP; DebugProbe_TargetFlashReport stays 28 bytes.

    • Every operation resets and halts the target before and after, on success and failure, and leaves it halted with the session attached. Verify reads flash back with the core halted. A progress callback in bytes cancels between pages and sectors by returning false.

    • Refused before the target is touched: no algorithm, no debug session, a range outside the flash region, FPB breakpoints set.

    • The FLM is untrusted input: ELF32 little-endian only, 8 MiB cap, offsets bounds-checked, the sector table capped at 512 entries. CI runs the parser and engine unit tests under ASan and UBSan; a libFuzzer target over the parser builds with -DATIRA_FUZZ=ON.

    • New result codes 0x1D01–0x1D0E (DebugProbeTargetFlashCodes.h); 0x1D0A–0x1D0D are the .pack refusals. The debug plane’s codes keep their meaning (DEBUGPROBE_DEBUG_NOT_ATTACHED, _NO_TARGET, _TIMEOUT, _CALL_FAULTED).

    • Examples: examples/debugprobe/target_flash_example.cpp and target_flash_c_example.c.

    • Measured on Linux, Atira Rev B with fw-atira 1.1.0, NUCLEO-H503RB (STM32H503RB): write + verify of 2 KiB, 16 KiB and 128 KiB, 10/10 each, medians 1.0 s, 4.1 s and 29.0 s (2026-10-20). At the release commit (2026-10-28, self-powered target): 128 KiB targetFlashWrite 10/10, 11.44–11.47 s (#444 and #450 cut the flash routine calls’ register traffic in between), read back identical; erase range, erase chip, load by pack name, edge cases and cancel all passed.

  • Self-powered targets (fw-atira >= 1.1, #460)

    • getSignalVoltageCheck (0x6F) compares the signal level with a fresh read of header pin 1: no supply, match, signal higher, signal lower, Atira powered, back-powered, pin 1 overvoltage. signalVoltageUseExternal (0x7D) sets the signal level to the target’s own supply and switches the signal on. C API: DebugProbe_GetSignalVoltageCheck, DebugProbe_SignalVoltageUseExternal.

    • FW_VOLTAGE_OUT_OF_RANGE (0x0101), FW_EXTERNAL_VOLTAGE_DETECTED (0x0102) and the new FW_PIN1_OVERVOLTAGE (0x1F03) come back by name; they used to read as SDK_ERROR_UNEXPECTED_RESPONSE.

    • FW_RESOURCE_BUSY from setTargetPowerEnabled(true) means the target is self-powered: do not retry (the firmware already waits out leftover charge). The ~1 s retry note is gone.

  • Target flash from a .pack (#435, #437)

    • targetFlashListPackDevices lists a .pack’s devices (name, vendor, family, flash block, whether it is flashable, needs connect steps, or is refused and why); targetFlashLoadPackDevice loads one by name in place of targetFlashLoadAlgorithm, with the PDSC’s RAM window. Both run on the host; listing needs no handle. C: DebugProbe_TargetFlashListPackDevices, DebugProbe_TargetFlashLoadPackDevice.

    • A part whose pack declares vendor connect steps (for example DebugPortStart on NXP MCX parts) is listed as needing them. The SDK does not run them; it loads only when the caller passes the device’s steps back as confirmed, and refuses otherwise with DEBUGPROBE_TFLASH_PACK_NEEDS_CONFIRM.

    • TargetFlashPackDevice::variants lists each device’s <variant> part numbers, so a search finds the name printed on the chip; C: DebugProbe_TargetFlashListPackVariants. Load stays by device name (#454).

    • TargetFlashReport::connectStepsSkipped names the vendor connect steps confirmed for the loaded pack part when the operation touched the target (empty on a refusal), so a caller can log the override; C reads them with DebugProbe_TargetFlashGetLastSkippedSteps, and DebugProbe_TargetFlashReport keeps its 28-byte layout (#455).

    • The C pack lists take the caller’s sizeof (entrySize), so later SDKs can append fields to DebugProbe_TargetFlashPackDevice and _PackVariant without breaking older callers. A device’s connect steps have no fixed limit: the struct carries connectStepCount and DebugProbe_TargetFlashGetPackDeviceConnectStep returns step i. reason holds 256 bytes.

    • A multi-core part loads when its merged flash is one contiguous block, with the AP0 core’s copy of the .FLM; there is no core choice (#456).

  • Not in 1.9.0

    Running vendor connect steps or debug sequences; HEX, ELF or S-record images; several flash regions; choosing the core of a multi-core part; option bytes, readout protection; WASM. Python target flash ships in pycosmicsdk 1.9.0 (DebugProbe.target_flash()), not in this package. Parts other than the STM32H503 are not verified.

  • Behaviour Changes for 1.7 Callers

    • debugprobe::DebugProbe gained a private member, so its size changed. Rebuild C++ programs against the 1.9 headers. The C API only gained functions.

v1.7.1

A reliability patch for the host adapters (wedges, resets, lost replies, overruns) and the debug probe (a replug crash). Pairs with fw-hostadapters 4.6.2 and pycosmicsdk 1.7.1. No host adapter API change: the C API has the same functions as in 1.7.0, and CosmicSDK and DebugProbeDriver keep their 1.7.0 layout (sizeof(CosmicSDK) stays 120), so a 1.7.0 program runs against 1.7.1 without a rebuild. BulkTransport and CosmicDriver, which holds it by value, grow by 8 bytes (#426); both are installed headers. The debug probe adds one C function, DebugProbe_ConnectCode().

  • New Features (debug probe)

    • connectCode() (C++, sync and async) and DebugProbe_ConnectCode() (C) say why a connect failed: SDK_ERROR_DISCONNECT (nothing opened), SDK_ERROR_UNEXPECTED_RESPONSE (DEV_INFO unreadable) or the new DEBUGPROBE_FIRMWARE_TOO_OLD (0x1E0C, firmware before fw-atira v1.0). connect() keeps its signature (#378, #415).

  • Bug Fixes

    • A truncated or malformed UART RX notification made the caller read up to 65535 bytes past the buffer. Notification::uartRx() returned the declared payloadLength unchecked, and every binding copies that many bytes. The length is now clamped to the bytes that arrived, and CosmicSDK_notificationAsUartRx uses the C++ decoder. Supernova 4F970418, fw 4.6.1-bf40f3d1, TX↔RX jumper, 115200 8O1, 32 random bytes per round through both views: 50/50 identical, 0 length mismatches; 10/10 after a physical replug (#408, #409).

    • Replacing the notification callback while notifications arrived could crash the process. onNotification() assigned the callback on the caller’s thread while the polling thread read and called it, so the old one could be freed mid-call. Both sides now take one lock, and the polling thread calls a copy outside it, so a callback that re-registers or holds the Python GIL cannot deadlock. The old callback can still run once after onNotification() returns. Not run on hardware (#270, #413).

    • A truncated or malformed I3C IBI notification made the caller read up to 255 bytes past the buffer. Notification::i3cIbi() and CosmicSDK_notificationAsI3cIbi() returned the length byte as the firmware sent it. Both now clamp it to the bytes the frame holds after the 8-byte IBI header, and the C function uses the C++ decoder. A well-formed frame decodes as before. Not run on hardware (#387, #395).

    • A large SPI or I2C bulk transfer at a slow clock timed out and left the adapter busy. The firmware answers a bulk command only after it clocks the whole transfer: a 32 KB spiReadBulk at 100 kHz takes 2.62 s on the wire, past pycosmicsdk’s 2000 ms default. CosmicSDK now remembers the SPI clock and the per-bus I2C clock the firmware accepted, and adds bytes × bits ÷ rate × 1.5 to the reply wait of spiWriteBulk, spiReadBulk, spiTransferBulk, i2cWriteBulk and i2cReadBulk. With no rate set, the wait is unchanged. Supernova DBDA0FE0, fw integration/4.6.2-r2 (045bb4a9), Linux, SDK timeout 2000 ms: on 1.7.0 the 32 KB read failed with SDK_ERROR_TIMEOUT at 2003 ms, 3/3, and the next 3-byte read with SDK_ERROR_TIMEOUT at 828 ms, 3/3; on 1.7.1 the read returns SUCCESS in 2.69 s, 32768 B, 3/3, and the next read SUCCESS in ~3 ms, 3/3. I2C bulk is not run on hardware (#412).

    • Debug probe: a replug could abort the host process with a double free. The abort reads double free or corruption. hidapi 0.14 frees the handle’s error string inside every read, write and feature report, with no lock, and the polling thread kept re-reading the dead handle while host calls ran on it. On a dead handle the polling thread now parks until close() and commands are refused. On Windows only a failed read marks the handle dead (gc#329, #446).

    • Debug probe: the last firmware status read success after a failed bulk SPI flash program. The closing HID re-init in spiFlashProgramFast() overwrote lastFirmwareStatus(). It now keeps the status of the failed bulk reply (#377, #415).

    • Debug probe: a command could take a stale reply as its answer. hidraw copies the probe’s replies to every open handle, so a second handle in the same process could read an old copy with a matching sequence number. HidDevice::command now drains pending replies before each write (at most 256 reads). A copy that arrives after the write can still collide (#381, #421).

  • Performance

    • Each bulk read waited out a libusb timeout after the data arrived: 1.1 ms on Pulsar, 3.0 ms on Supernova. The SDK drained the IN endpoint after every read; a zero-length packet is owed only when the length is a multiple of the packet size. On fw-hostadapters 4.6.2 and later (read from bcdDevice), the drain now runs only then, and after a failed read. Earlier firmware keeps the drain after every read: without that gap it refuses ~1 in 4400 SPI launches (fw-hostadapters#216). 8 MHz, 3-byte JEDEC read, p50 of 1000: Pulsar 455A9EDB 1.90 ms → 0.75 ms, Supernova 4F970418 5.1–5.3 ms → 2.00 ms, on a test build of fw-hostadapters#216 that reports 4.6.2. Pulsar on that build: 0/60000 errors on back-to-back 3-byte reads (#426).

  • Behavior Changes for 1.7.0 Callers

    • A C++ program compiled against the 1.7.0 headers keeps the old inline onNotification(), which writes the callback with no lock. It runs against 1.7.1, but the #413 fix reaches it only after a rebuild. The C API is not affected.

    • Debug probe, outside Windows: after a failed write or feature report the session refuses every command until close() and open() (#446).

    • Debug probe: HidDevice::refusedOldFirmware() is no longer true when DEV_INFO cannot be read; connectCode() returns SDK_ERROR_UNEXPECTED_RESPONSE for that case (#415).

  • Documentation

    • The debug probe API is no longer labeled experimental, in the debug probe guide and the 1.7.0 entry below. The Atira is a released product; the API follows the same versioning rules as the rest of the SDK (#403, #439).

    • The landing page names the Atira next to Supernova and Pulsar, and the site offers a zip of examples/ (#439).

    • I2C frequency on fw-hostadapters 4.6.2: the default timing picks the fastest SCL that does not exceed the request (550 kHz → 500 kHz) and refuses outside 11 Hz–3 MHz with FW_INVALID_PARAMETER; i2cSetDutyCycle with highPct 0 returns the programmed rate, not the request. The headers keep the earlier firmware behavior (#410).

    • FW_EXTERNAL_VOLTAGE_DETECTED (0x0102): fw-hostadapters 4.7.0 (fw-hostadapters#171) refuses a voltage Set on a port another supply already powers with it; 4.6.2 does not. Every *SetBusVoltage documents it and points to *UseExternalVoltage(). i3cUseExternalVoltage() ignores save; on the shared rail, *UseExternalVoltage(save=true) stores the measured voltage, not “external” (#401, #407).

    • FW_GPIO_WRONG_CONFIGURATION (0x0502) lists every case: a write needs a digital output, a read or an interrupt needs a digital input (#400, #406).

  • Internal

    • Test harness only, no SDK change: the UsbConfig fixture no longer writes an unread config (#402), and the test fake forgets an abandoned request (#416). atiratests accepts firmware newer than the vendored version and keys the JTAG cell on CAP_JTAG (#430). The debug probe symbol gate also runs on macOS (#379, #415).

  • Measured

    • fw-hostadapters 4.6.2 signed (7d362c36) with this SDK line (develop-1.7.1 at 643917af, through pycosmicsdk develop-1.7.1), Supernova 4F970418 and Pulsar 455A9EDB, pycosmicsdk hardware suite, 2 runs: 119 pass / 7 fail / 121 skip, identical; no adapter wedged (the 4.6.1 baseline wedged the Supernova at test 163/247). The 7 failures are the same on fw 4.6.1 (I3C tests written for another target, and o1).

    • Debug probe, Atira Rev B, device reset under traffic, SDK only: the 1.7.0 driver aborted with double free or corruption 20/20, 1.7.1 0/20 (#446).

    • macOS symbol gate (#415): full-ci 14/14 on bf01e735.

v1.7.0

Adds the Binho Atira debug probe as a second library beside libcosmicsdk. Code written for Supernova and Pulsar does not change. 1.7.0 also carries everything in 1.6.0. Needs fw-atira v1.0 or later on the probe; the host adapters keep fw-hostadapters 4.6.0.

  • New Features (debug probe)

    • Added libdebugprobe (debugprobe.dll on Windows) and its static debugprobe_static, with the C++ class debugprobe::DebugProbe (include/debugprobe/DebugProbe.hpp, 67 public methods), the async DebugProbeAsync, and a C API of 69 functions (DebugProbe_* in DebugProbe_API_c.h). Those are the counts a caller reaches; the library also builds the 15 hidden RTT/SWO/UPDI entries, so scripts/check_atira_bindings.py, which reads the headers as text, reports 82 and 84. Every C++ method has a C entry point, and every C and wasm name derives from the C++ one (spiTransferList → DebugProbe_SpiTransferList → DebugProbe_Wasm_SpiTransferList), checked in CI.

    • Named like the host adapters. Interface-scoped calls lead with the interface (spiGetParameters, uartGetConfig, powerGetMonitorActive, debugGetState, spiFlashGetParams), the boot call is enterBootMode(), and the probe mode is the typed ProgMode enum in definitions.h (PROG_MODE_IDLE …) rather than a raw byte.

    • SWD debug (15 methods): debugAttach / debugDetach, debugHalt / debugRun / debugStep / debugReset, registers, memory, hardware breakpoints (debugBreakpointSet / Clear / List) and debugCallFunction. SWD is the only debug wire in 1.7.0.

    • SPI controller (13 methods): spiControllerInit() / spiSetParameters() / spiTransfer() with the same argument lists as CosmicSDK, 1024-byte transfers chunked under one chip select, plus the probe’s own verbs for HID commands 0x70–0x7A (spiTransferChunk, spiTransferList, the on-probe hash, spiGetStatus). CS1–CS3 answer FW_FEATURE_NOT_SUPPORTED_BY_HARDWARE unless the board routes the pin; bus voltage (spiSetBusVoltage) is a host adapter rail the probe does not have.

    • SPI NOR flash library (14 methods, debugprobe/SpiFlash.hpp, owned by DebugProbe as spiFlash*): JEDEC/SFDP detection with every advertised erase type, largest-aligned erase with a footprint identical to sector-at-a-time, page program through the probe’s transaction list, verify through the on-probe CRC-32 with read-back to name the first differing byte. It refuses what it cannot drive rather than guessing: a 16-bit session (DEBUGPROBE_FLASH_SESSION_WIDTH), a page larger than one transaction, 4-byte addressing without its native opcodes, a corrupt SFDP density or erase table; a busy part is waited out before SFDP is trusted.

    • SPI vendor bulk transport (debugprobe/SpiBulkTransport.hpp): spiFlashProgramFast() hands the session HID → bulk → HID, one page per envelope, and falls back to HID where the bulk interface cannot be opened. spiBulkAvailable() reports which path runs; spiFlashGetLastBulkStats() makes a throughput number attributable.

    • Target power (4 methods): powerSetOutput() switches the target rail and powerGetReading() returns voltage in mV and power in mW, like the host adapters, and current in µA: the Rev A/B monitor resolves 62.5 µA, and a sleeping target draws under 1 mA.

    • Device plane: listDevices(), getDeviceInfo() (firmware version, board variant, capability bitmask), settings and mode, uartBridgePort() for the probe’s UART bridge serial port, and enterBootMode() for a firmware update.

    • One result vocabulary. Every probe call returns a CosmicSDK uint16_t code, checked against SUCCESS like any CosmicSDK call (#361, #375). From fw-atira v1.0 the probe firmware itself answers with CosmicSDK codes as a 16-bit status: the host adapters’ FW_* numbers, the new generic FW_RESOURCE_BUSY (0x000E), and two probe codes, FW_SWD_HOST_SESSION_ACTIVE (0x1F01, a host CMSIS-DAP session holds the SWD bus) and FW_TEARDOWN_PENDING (0x1F02, a stop has not finished). A value the firmware does not declare is SDK_ERROR_UNEXPECTED_RESPONSE. The SPI flash verdicts are 0x0320–0x032C in the SPI block and the debug codes 0x1E01–0x1E0B in their own group (group 7 is 1-Wire’s). lastFirmwareStatus() (C: DebugProbe_LastFirmwareStatus(), uint16_t) returns the raw status for support.

    • Minimum firmware: fw-atira v1.0. connect() refuses an older image (no CAP_STATUS16, capability bit 11) with a message naming the cause, because its 8-bit status would be misread.

    • Examples: examples/debugprobe/debugprobe_demo.cpp (C++ tour), debugprobe_c_demo.c (C tour) and spi_flash_example.cpp, which is the stock SPI flash example with two differences (the class, and no bus-voltage block).

  • Not in 1.7.0

    RTT (5 methods), SWO status and trace reads, and UPDI (9) are built into the library but hidden from the public headers and the documentation (#363): each gets its own release when it is ready. JTAG is not in 1.7.0.

  • Behavior Changes for 1.6.0 Callers

    Nothing a Supernova or Pulsar program calls through CosmicSDK, CosmicAsyncSDK or the C API changed name, signature or behavior, and the C API has the same functions as in 1.6.0. Four things are new or moved around it:

    • FW_RESOURCE_BUSY (0x000E), FW_SWD_HOST_SESSION_ACTIVE (0x1F01) and FW_TEARDOWN_PENDING (0x1F02) are new result codes in definitions.h and in the Python, Java and C# tables. Host adapter firmware does not return them.

    • The C++ core gained a transport seam: CosmicDriver now derives from BinhoDriver, and CommunicationManager takes the driver and its TransferProtocol from it. This changes the C++ ABI of three internal classes only: CosmicDriver, UsbTransferProtocol and CommunicationManager change layout, and libcosmicsdk no longer exports CommunicationManager::CommunicationManager() (it takes an optional driver now). CosmicSDK and CosmicAsyncSDK hold these through a pointer, so a program that uses them runs against 1.7.0 without a rebuild: one built against the 1.5.x headers and library ran 10/10 against the 1.7.0 libcosmicsdk on a Supernova. Code that constructs or embeds one of those three classes directly must be rebuilt; it fails at load with symbol lookup error rather than later at a call. The C API is not affected.

    • libdebugprobe carries its own hidapi and libusb and exports none of their symbols, so a process can link both libraries (#338). Before this, one process with both aborted on shutdown 10/10 (double free or corruption); with it, 0/10.

    • The Linux udev rule (udev/65-binho-hid.rules) gains the probe (1fc9:8347: hidraw, the CMSIS-DAP bulk interface and the serial ports, #339). Re-run scripts/install_udev_rules.sh after updating.

  • Packaging

    • Every download carries the debug probe library next to libcosmicsdk: the Linux x64/ARM64 and macOS ARM/Intel zips (.so / .dylib and the static archive) and the three Windows installers (debugprobe.dll, debugprobe.lib, debugprobe_static.lib, release and debug), with include/debugprobe/ and examples/debugprobe/.

  • Target flashing

    • 1.7.0 does not flash a target’s firmware from an image. Use pyOCD with the probe as a standard CMSIS-DAP probe; the Getting Started page has the commands. OpenOCD should work the same way but is not verified yet. The SDK’s own flash engine is #358.

  • Documentation

    • Added “Getting Started with the Debug Probe”: what 1.7 covers, host setup per OS, how to check the probe firmware (fw-atira v1.0 minimum), linking libdebugprobe, and flashing a target with pyOCD. Added the probe’s C API, SPI and result-code pages.

  • Known Limitations

    • On Windows, SPI flash programming uses the HID path until the probe firmware declares its bulk interface to Windows (spiBulkAvailable() reports it unavailable).

    • The UART bridge can hold the last byte of a reply until the next write: 1 event in 120 256-byte echoes at 115200 on fw-atira v1.0.0 (fw-atira#275). The byte is late, not lost.

    • Python support for the probe comes in pycosmicsdk after 1.7.0.

  • Measured

    • SPI flash (dev bench, W25Q128JV, 12 MHz): 1 MiB program over bulk 100.1 KB/s, 4.6× the HID list path; on-probe hash verify 199 KB/s; erase 299 KB/s.

    • Target flashing with stock pyOCD 0.44.1 through the probe (Linux, STM32H503RB): 11/11 program, verify and erase cycles, about 6.5 s per 128 KiB.

    • Linux, Atira Rev A/B on fw-atira #267 (1d8d13d3), 2026-09-30: an 8-bit-status image refused at connect() 5/5; SPI flash suites 34/34 on a W25Q128JV (1 MiB at 8 MHz: erase 3.74 s, program over bulk 6.20 s, verify 5.26 s), 3/3 runs; UART bridge 4/4, 3/3 runs, on an image with SPI off; SWD and power through a NUCLEO-H503RB; after one USB replug, the full suite 375 pass / 0 fail.

    • Linux, Atira Rev A/B on fw-atira v1.0.0 (5d4fe86, dev key), 2026-10-01, one image for SPI and UART: full suite 393 pass / 0 fail, 3/3 runs; SPI flash suites on a W25Q128JV 104 pass / 0 fail, 3/3 runs; the ZLP v1.0 sends after a full-packet bulk reply (skipped since #384) fails 3/3 without the skip; Supernova + Atira in one process 10/10. pycosmicsdk 1.6.0 against CosmicSDK 1.6.0 and 1.7.0 on a Supernova: 211/211 tests with the same result.

    • Release code (aa3bef8, same sources as the v1.7.0 tag), Atira Rev B on fw-atira v1.0.0-dev.1, NUCLEO-H503RB and a UART echo, 3/3 runs, 0 failures: Linux SWD + UART 359 pass, SPI flash on a W25Q128JV 360 pass; Windows (release CI binaries) SWD + UART 351 pass / 38 skip, SPI flash 347 pass / 41 skip (the bulk tests, see above).

v1.5.1

The items from the review of the 1.5.0 merge to main. 1.5.0 is tagged and was bench-tested, so they ship as a new patch version instead of moving its tag.

  • New Features

    • Added getLastBulkError() (C: CosmicSDK_GetLastBulkError()), which says why the bulk plane failed — for example could not claim the vendor interface or libusb_open failed (is the vendor interface bound to WinUSB?) — where the status code only says that it did. Python, Java and C# wrap it. The C API goes from 135 to 136 functions.

    • Added CosmicSDK_notificationAsI3cTargetBusEvent(), the C decoder for I3C target bus events, backed by the same code as C++ Notification::i3cTargetBusEvent(). Python (notification_as_i3c_target_bus_event), Java (i3cTargetBusEvent) and C# (OnI3cTargetBusEvent) wrap it. The C API goes from 136 to 137 functions.

  • Behavior Changes for 1.5.0 Callers

    • CosmicSDK_GetBulkCapabilities() returns SDK_ERROR_TIMEOUT when the device never answered the query, and SUCCESS only when it did, so “no answer” and “no bulk” no longer read the same from the C API and the bindings. Firmware that predates the query now reports SDK_ERROR_TIMEOUT here.

  • Bug Fixes

    • ~CosmicSDK() joins the polling thread before the notification callback and the response slot are destroyed. The thread could run into either after it was gone (the ~CommunicationManager() defect fixed in 1.5.0, one layer up).

    • SDK_ERROR_BULK_UNAVAILABLE (0xC000) is now in the Python, Java and C# result-code tables, so those callers get a name instead of 49152. check_bindings.py now compares the SDK_ERROR_ family as well as FW_, so a missing SDK code fails the gate.

    • I2C and SPI target bus events can be parsed from Python and Java. Python’s notification_as_i2c_target_bus_event / notification_as_spi_target_bus_event raised ctypes.ArgumentError on the Notification a callback receives, and Java’s Notification record carried no way to reach the event. Both bindings now parse the event while the native notification is alive and carry it on Notification (Python i2c_target_bus_event / spi_target_bus_event / i3c_target_bus_event; Java i2cTargetBusEvent() / spiTargetBusEvent() / i3cTargetBusEvent()). Java’s Notification record gains three components, so code that constructs one directly must pass them.

  • Documentation

    • Added Bulk Transport and Target Mode guide pages, a bulk-flow page linked from every *Bulk and *Memory method, and the list of new example directories; the FAQ no longer says target mode is unsupported.

    • Documented that notification callbacks run on the SDK’s receive thread and must not call blocking methods, and fixed the target-mode examples that suggested it.

    • CosmicAsyncSDK’s bulk methods check only the host half; the doc said both.

    • I3C target mode is left with i3cControllerInit(), not only resetDevice(), and a second i3cTargetInit() answers SUCCESS.

    • Corrected two 1.5.0 changelog entries: NOTIF_UNKNOWN did not move, and the C API delivers a short I3C read’s partial payload.

v1.5.0

  • New Features

    • Added a bulk payload transport over the device’s vendor (WebUSB) endpoints, for payloads that do not fit in a HID request. Support is discovered from the device rather than assumed: isBulkTransportAvailable() reports whether this host claimed the endpoints, and getBulkCapabilities() returns the record the device advertises — a per-group payload ceiling and a bitmask of the bulk commands it implements. Prefer BulkCapabilities::maxPayloadFor() over the compile-time *_BULK_MAX_PAYLOAD constants, which are only upper bounds. Every CosmicSDK and C API bulk call refuses locally with SDK_ERROR_BULK_UNAVAILABLE when either half is missing, rather than timing out. CosmicAsyncSDK checks only the host half.

    • Added SPI controller bulk transfers: spiWriteBulk(), spiReadBulk() and spiTransferBulk(). The first two split the directions so each gets the whole staging pool for the side carrying real data; spiTransferBulk() is the full-duplex transaction, whose received bytes return over the bulk endpoint while the outgoing bytes stay inside the request and are therefore bounded by MAX_SPI_TRANSFER_LENGTH.

    • Added I2C controller bulk transfers — i2cWriteBulk() and i2cReadBulk() — which carry the same addressing as their HID twins and move only the payload out of band.

    • Added I3C controller bulk transfers for all three modes: i3cSdrWriteBulk() / i3cSdrReadBulk(), i3cLegacyI2cWriteBulk() / i3cLegacyI2cReadBulk(), and i3cHdrDdrWriteBulk() / i3cHdrDdrReadBulk().

    • Added I2C target mode: i2cTargetInit(), i2cTargetSetParameters(), i2cTargetWriteMemory(), i2cTargetReadMemory(), i2cTargetSetEepromConfig(), i2cTargetSetRegisterRegion() and i2cTargetErase(), with completed bus transactions reported as notifications. The device presents itself on the bus backed by an arena drawn from the shared bulk-staging pool, with selectable emulation models (memory, EEPROM, register map).

    • Added SPI target mode: spiTargetInit(), spiTargetSetParameters(), spiTargetWriteMemory(), spiTargetReadMemory() and spiTargetSetFlashConfig(), with the same notification-based bus-event reporting.

    • Added I3C target mode: i3cTargetInit(), i3cTargetSetParameters(), i3cTargetWriteMemory() and i3cTargetReadMemory(), plus its bus-event notification.

    • Added i2cDeinit() and spiDeinit(), wrapping commands the firmware had been dispatching with no host-side entry point.

    • Added i3cHdrExitPattern() and i3cTargetResetPattern().

    • All of the above are available across the C++ blocking API, the asynchronous C++ API, the C API, the WebAssembly layer, and the Python, Java and C# bindings.

  • Behavior Changes for 1.4.0 Callers

    No symbol was removed, renamed or re-signatured; the C API went from 102 to 135 functions with none missing. Three behaviors changed, and in all three 1.4.0 reported success where it should not have, so the change is the fix. The fourth entry below is the opposite: an enumerator that did not move, listed because the release adds enumerators around it.

    • NOTIF_UNKNOWN did not move: it is 5 in every release, 1.4.0 included. The three target bus-event enumerators were appended after it, at 6, 7 and 8, precisely so that a 1.4.0 comparison against NOTIF_UNKNOWN keeps its meaning. Nothing to change in existing code. include/CosmicNotifications.h carries the invariant next to the enumerator.

    • A HID write that fails returns SDK_ERROR_DISCONNECT at once, where 1.4.0 returned SUCCESS and let the blocking call time out. Callers that retried on SDK_ERROR_TIMEOUT should treat SDK_ERROR_DISCONNECT the same way: no answer came, and the driver reopens the handle on the next call.

    • Output buffers hold only the bytes that arrived. 1.4.0’s i2cRead always sliced readLength, tail included, including on a NACK.

    • Against firmware 4.5.0 a short I3C read returns FW_I3C_TRANSFER_INCOMPLETE_READ (0x061A) where 4.4.0 returned SUCCESS. The bytes that arrived are still delivered: the C API copies whatever the device sent whatever the status, clamped to the caller’s capacity, and reports the real count. So a caller reads the status and the partial payload, and a reply that did not fit is never SUCCESS.

  • Bug Fixes

    • ~CosmicDriver() no longer calls hid_exit(). hidapi’s init/exit pair is process-global, so destroying one driver tore down state every other live user was still holding — reachable on all three backends, and observed as a crash in a downstream consumer’s CI.

    • A failed USB write is now recovered from rather than reported once: a handle whose write side is known poisoned is not written to again until a reopen replaces it, a failed reopen() is retried by the next command instead of being fatal, and a lost handle is noticed from the read side, where the signal is unambiguous. A session now survives an adapter that departs and returns.

    • A command that timed out no longer wedges the session.

    • Every fixed-offset response decoder is now bounded, so a short or truncated reply is refused with SDK_ERROR_WRONG_RESPONSE instead of being read out of the buffer.

    • Fixed the CMD_SYS_GET_BULK_CAPABILITIES opcode, which did not match the firmware’s value.

    • The Windows DLL now exports the nested BulkCapabilities methods.

    • libusb is built position-independent so the shared library links on x86-64 Linux.

    • ~CommunicationManager() joins the polling thread before its own members are destroyed. The class declares driver after onResponseCallback, and the destructor was empty, so a report already in flight could run through a freed std::function. v1.4.0 has the same member order; the target-mode traffic added here is what makes it reachable — 3 of 40 processes died with SIGSEGV on silicon before the fix.

    • spiTransfer refuses a transferLength or inData size above MAX_SPI_TRANSFER_LENGTH with SDK_ERROR_WRONG_REQUEST before the request reaches the device; transferLength == 0 stays allowed. Callers see the SDK’s SDK_ERROR_WRONG_REQUEST where 4.4.0 firmware answered FW_INVALID_PARAMETER.

    • The C# binding routes I2C and SPI target bus events by NotificationType instead of the literals 4 and 5. The real values are 5 and 6, and the dispatcher returned early on 4, which is NOTIF_I3C_CONNECTOR_EVENT — so C# stopped delivering I3C connector events, which worked in v1.4.0.

  • Result Codes

    • Added the firmware result codes the published table was missing: FW_I3C_TRANSFER_INCOMPLETE_READ (0x061A, a controller read that ended cleanly but short — most often the target honouring its own Max Read Length), FW_I3C_ENGINE_BUSY (0x0619, retryable), FW_I3C_TRANSFER_CRC_ERROR (0x0618) and FW_SHELL_MODE_ACTIVE (0x0109, reserved — defined by the firmware but not currently returned).

    • FW_I3C_TRANSFER_PARITY_ERROR (0x0610) is no longer documented as reserved: the firmware returns it on the controller path for a failed HDR-DDR parity check.

    • Documented CMD_SPI_TARGET_SET_REGISTER_REGION and FW_SPI_TARGET_REGION_TABLE_FULL as not implemented in firmware, keeping both numbers reserved.

  • Language Bindings & Examples

    • Added bulk transport and I2C/SPI target-mode examples for C, C++, Python, Java and C#.

    • The Python binding gained first-class I2C and SPI target methods.

    • The USB configuration examples now preserve the current CDC and WebUSB settings when updating one part of the configuration.

  • Testing & CI

    • Added host-only unit test targets covering the response decoders, the bulk plane, the USB transfer protocol and the driver’s recovery behavior, driven through a fake hidapi and a scriptable bulk transport, and a workflow that runs them on Linux, Windows and macOS.

    • The binding consistency checker gained a result-code layer, comparing the FW_* table in definitions.h against the Python, Java and C# transcriptions by name and by value.

  • Documentation

    • Documented the bulk payload transport and the I2C/SPI target-mode architecture in the API reference, and wired the SPI result codes and I2C/SPI target constants into the documentation site.

v1.4.0

  • New Features

    • Added USB configuration API — setUsbConfig() / getUsbConfig() — to the C++, Async C++, and C API, all language bindings (Python, Java, C#), and the WebAssembly layer. Introduces the UsbConfig struct (WebUSB state, CDC state, and CDC mode) with WebusbState, CdcState, and CdcMode enums. CdcMode selects the USB virtual COM (VCOM) behavior: UART passthrough, interactive terminal shell (Supernova only), Binho Nova compatibility, RS-485 bridge (Pulsar only), or CAN-FD bridge (Pulsar only). The *_NO_CHANGE sentinel values allow updating one part of the configuration without touching the others.

    • Extended I3cTransferFlags (previously used only by I3C SDR and Legacy I2C-over-I3C transfers) to every named I3C CCC command across the C++, Async C++, and C API, all language bindings, and the WebAssembly layer. Each CCC method now takes an optional flags parameter (default I3C_XFER_NONE); passing I3C_XFER_NONSTOP completes the CCC without emitting a bus stop. i3cCccENTDAA() does not support this parameter.

    • Extended i3cHdrDdrWrite() / i3cHdrDdrRead() to accept an I3cTransferFlags parameter across the C++, Async C++, and C API, all language bindings, and the WebAssembly layer. Passing I3C_XFER_SKIP_EXIT_PATTERN (an alias of I3C_XFER_NONSTOP, same bit) skips the HDR exit pattern at the end of the transfer.

    • Extended i3cCccENTDAA() with an optional target table so dynamic addresses can be assigned by PID, BCR and DCR match; when the table is empty the call behaves as the legacy broadcast ENTDAA (every target auto-assigned).

    • Added three new slow I3C push-pull clock rates supported by the firmware: 1 MHz, 400 kHz, and 100 kHz.

    • Added an I3C connector event notification (NOTIF_I3C_CONNECTOR_EVENT) reporting the port (I3cConnectorPort), the plug/unplug event (I3cConnectorEvent), and the identified connector type (I3cConnectorType) via the new I3cConnectorEventNotification struct, wired through the C/C++ APIs, all language bindings, and the WebAssembly layer.

    • Extended the GPIO interrupt notification to report triggeredEdge (rising/falling) and logicLevel (HIGH/LOW) at interrupt time, surfaced through the C/C++ APIs and the Python, Java, and C# bindings.

    • The I3C SDR i3cSdrWrite() / i3cSdrRead() flags argument now defaults to I3C_XFER_START_WITH_7E in the C++, Async C++, Python, and C# APIs, so SDR transfers begin with the 0x7E broadcast address unless overridden. The C API, and the Java binding continue to require flags explicitly.

  • Bug Fixes

    • Fixed controller initialization in the I3C DAA examples.

  • Language Bindings & Examples

    • Added USB configuration examples for C++, C, Python, Java, and C#.

    • Added I3C connector event examples for C++, C, Python, Java, and C#.

    • Updated the I3C CCC, DAA, and HDR-DDR examples to demonstrate the new I3cTransferFlags-based CCC options, PID-matched ENTDAA, and HDR-DDR exit-pattern control.

    • Extended examples to exercise getVersion(), uartDeinit(), and spiSetParameters().

  • Documentation

    • Added a “CDC Modes Getting Started” guide for USB configuration, reorganized the documentation navigation, and added System API reference pages plus constants and result-code entries for the USB configuration types.

    • Documented the Linux libudev/libusb build prerequisites.

    • Various Doxygen documentation improvements.

v1.3.0

  • New Features

    • Added uartDeinit() method to the C++, Async C++, and C API, all language bindings (Python, Java, C#), and the WebAssembly layer to properly release the UART interface when it is no longer needed.

    • Added resetDevice() method to the C++, Async C++, C API, all language bindings (Python, Java, C#), and the WebAssembly layer to programmatically reboot the connected device.

    • Added getVersion() method to the Python, Java, and C# language bindings, and the WebAssembly layer to make the SDK version string accessible from all supported languages.

    • Added <protocol>GetBusVoltage() method to the C++ and C API, all language bindings (Python, Java, C#), enabling programmatic readback of the measured bus voltage. In the Async C++ API and the WebAssembly layer, this is consolidated into a single getAnalogMeasurements() call that returns all analog readings at once. <protocol> can be i2c, i3c, spi, or uart. The equivalent method for GPIO is gpioGetVoltage() (C API: CosmicSDK_GpioGetVoltage()), since GPIO pins do not represent a communication bus.

    • Added <protocol>useExternalVoltage() method to the C++, Async C++, and C API, all language bindings (Python, Java, C#), and the WebAssembly layer, allowing the host to signal that an external voltage reference is driving the bus so the SDK skips its internal voltage configuration step. <protocol> can be i2c, i3c, spi, gpio, or uart.

    • Added dedicated named CCC methods to the Async C++ API (CosmicAsyncSDK) for all supported CCC commands. Previously, CCC operations in CosmicAsyncSDK required calling a single generic method and passing the desired CCC code as a parameter; the new wrappers provide a typed, discoverable interface for each supported CCC.

    • Added support for the following I3C CCC commands, previously unsupported by the SDK: ENTAS0, ENTAS1, ENTAS2, and ENTAS3 (broadcast and direct); SETBUSCON (broadcast); SETXTIME (broadcast and direct); RSTGRPA (broadcast and direct); SETGRPA (direct); GETXTIME (direct); and GETMXDS (direct).

    • Added the FW_UART_IN_VCOM_PORT_MODE result code, returned when the UART interface cannot be initialized for direct use because it is currently operating in CDC/VCOM port mode.

  • Bug Fixes

    • Fixed an extra byte being transmitted in the broadcast ENEC, broadcast DISEC, and broadcast RSTACT I3C CCC commands.

  • Documentation

    • Added a new Architecture & Threading Overview page covering the SDK layer stack, the threading model, and notification callback behavior.

    • Added UART-specific FAQ entries covering operating modes, CDC/VCOM initialization behavior, and UART deinitialization.

    • Expanded the FAQ entry on I3C CCC support to add the newly supported CCCs.

v1.2.3

  • New Features

    • Added SDK version API: a static getVersion() method on CosmicSDK and CosmicAsyncSDK, plus a C-API counterpart, along with compile-time macros (COSMICSDK_VERSION_MAJOR, COSMICSDK_VERSION_MINOR, COSMICSDK_VERSION_PATCH, COSMICSDK_VERSION_STRING) for runtime and compile-time version checking.

    • Added a WebAssembly (WASM) build target using wasi-sdk, exposing an async C API (~44 exports wrapping CosmicAsyncSDK) with a lightweight JavaScript host runtime (~430 lines). Includes a connectWasm() path that bypasses HIDAPI enumeration for WASM environments and guards std::thread usage behind #ifndef __wasm__.

  • Bug Fixes

    • Fixed a missing bounds check in i2cScanBus that could cause a buffer overread when the device response payload was smaller than expected.

    • Fixed subaddress byte-order (endianness) in I2C and I3C transfers to correctly serialize the sub-address in big-endian order.

  • Documentation

    • Added known-issue documentation for I2C scan bus timeout behavior, covering both the synchronous CosmicSDK and the CosmicAsyncSDK API paths, across both the API reference documentation and the FAQ section.

    • Added a FAQ entry on Pull-up resistor requirements for I2C communication.

v1.2.2

  • Linux Packaging & Permissions

    • Added a user-facing Linux helper script install_udev_rules.sh for installing CosmicSDK udev permissions from delivered packages.

    • Updated Linux packaging to include scripts/install_udev_rules.sh and udev/65-binho-hid.rules in release artifacts.

    • Updated Linux installation/build docs to use the packaged user-facing script.

  • Bug Fixes

    • Revert the inclusion of only public headers in the include folder.

v1.2.1

  • Language Bindings & Examples

    • Added a new Java reference integration layer wrapping the C API.

    • Added complete Java examples for system, i2c, i3c (basic/ccc/daa/hdr-ddr/hj-ibi), spi, uart, and gpio.

  • Bug Fixes

    • Fixed the inclusion of the static HTML documentation on the docs folder of deliverable artifacts.

    • Fixed the inclusion of only public headers in the include folder.

    • Fixed the Python binding SyntaxError in i2c_scan_bus.

v1.2.0

  • New Features

    • Added full I3C support for Supernova across C++, C API, and Async API, including: controller configuration, bus initialization/reset, SDR and HDR-DDR transfers, target table management, and target configuration.

    • Added broad I3C CCC coverage, including GET/SET operations such as PID/BCR/DCR/STATUS/CAPS, ENEC/DISEC, RSTACT, SETDASA/SETAASA/SETNEWDA, ENTDAA, RSTDAA, MRL, and MWL.

    • Added SPI API support (controller init, parameter configuration, and transfer APIs).

    • Added UART API support enhancements (init and parameter configuration updates).

    • Added GPIO API support enhancements, including digital read/write and interrupt configuration/disable.

    • Added protocol-specific voltage configuration helpers for I2C, I3C, SPI, UART, and GPIO.

    • Added notification callback support and shared notification structures across C/C++ APIs.

    • Added I2C bus scanning support in examples and documentation.

  • Language Bindings & Examples

    • Refactored Python integration examples into a structured binding-style layout.

    • Added complete Python protocol examples for system, i2c, i3c (basic/ccc/daa/hdr-ddr/hj-ibi), spi, uart, and gpio.

    • Added a new C# reference integration layer wrapping the C API.

    • Added complete C# examples for system, i2c, i3c (basic/ccc/daa/hdr-ddr/hj-ibi), spi, uart, and gpio.

    • Reorganized example folders and naming for consistency (for example i3c/basic_api to i3c/basic).

    • Added new blocking C and C++ examples for I2C, I3C, SPI, UART, GPIO, and system APIs.

  • API & Naming Updates

    • Refined API naming consistency across C/C++ layers (including normalized I3c naming in C API symbols and camelCase alignment in I2C C API functions).

    • Standardized parameter naming in transfer APIs (inData / outData) and aligned several data-length types to uint16_t.

    • Updated I3C transfer options/event handling to use flag or mask-based interfaces in relevant APIs.

    • Added output length reporting for read APIs, including I3C SDR read and I3C HDR-DDR read paths.

  • Build, Platform, and CI

    • Improved Linux build and CI support (including Ubuntu arm64 coverage and Linux dependency handling).

    • Updated macOS GitHub Actions runners to current labels to keep Intel and Apple Silicon CI builds supported.

    • Added support scripts and rules for Linux device access setup (udev flow).

    • Improved docs build behavior so documentation generation is optional when tools are unavailable.

  • Documentation

    • Introduced a significantly expanded user-facing documentation set with Sphinx + Doxygen integration.

    • Added protocol guides, API references, constants/structures/result-code references, FAQ content, and improved examples documentation.

    • Improved onboarding/build documentation and README guidance.

  • Bug Fixes

    • Fixed transaction ID rollover handling in blocking APIs.

    • Fixed read-length handling issues in selected I3C paths.

    • Fixed a cross-platform build issue (reported on Windows MinGW and Ubuntu) in the C API implementation of I3cGetDeviceTable.

    • Fixed several build and merge regressions introduced during 1.2.0 development.

    • Fixed multiple documentation rendering/formatting issues.

v1.1.0

  • General Improvements

    • Add support for connecting to a specific USB host adapter by its serial number.

v1.0.0

  • Initial public release of CosmicSDK.

  • C++ synchronous API (CosmicSDK.hpp).

  • C++ asynchronous API (CosmicAsyncSDK.hpp).

  • C API (CosmicSDK_API_c.h).

  • I2C only support for Supernova and Pulsar devices.