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):targetFlashLoadAlgorithmtakes the.FLMbytes and a RAM window and checks them on the host;targetFlashWriteerases the touched sectors, programs and optionally verifies in one algorithm session;targetFlashEraseRange,targetFlashProgramandtargetFlashVerifydo one step each;targetFlashGetLastReport,targetFlashGetInfoandtargetFlashUnloadAlgorithm. The C API mirrors them asDebugProbe_TargetFlash*(8 functions).targetFlashEraseChiperases the whole flash region: the FLM’sEraseChipwhen it has one, else every sector (#453).TargetFlashReportgives 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_TargetFlashReportstays 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–0x1D0Dare the.packrefusals. The debug plane’s codes keep their meaning (DEBUGPROBE_DEBUG_NOT_ATTACHED,_NO_TARGET,_TIMEOUT,_CALL_FAULTED).Examples:
examples/debugprobe/target_flash_example.cppandtarget_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
targetFlashWrite10/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 newFW_PIN1_OVERVOLTAGE(0x1F03) come back by name; they used to read asSDK_ERROR_UNEXPECTED_RESPONSE.FW_RESOURCE_BUSYfromsetTargetPowerEnabled(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)
targetFlashListPackDeviceslists a.pack’s devices (name, vendor, family, flash block, whether it is flashable, needs connect steps, or is refused and why);targetFlashLoadPackDeviceloads one by name in place oftargetFlashLoadAlgorithm, 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
DebugPortStarton 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 withDEBUGPROBE_TFLASH_PACK_NEEDS_CONFIRM.TargetFlashPackDevice::variantslists 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::connectStepsSkippednames 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 withDebugProbe_TargetFlashGetLastSkippedSteps, andDebugProbe_TargetFlashReportkeeps its 28-byte layout (#455).The C pack lists take the caller’s
sizeof(entrySize), so later SDKs can append fields toDebugProbe_TargetFlashPackDeviceand_PackVariantwithout breaking older callers. A device’s connect steps have no fixed limit: the struct carriesconnectStepCountandDebugProbe_TargetFlashGetPackDeviceConnectStepreturns step i.reasonholds 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::DebugProbegained 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) andDebugProbe_ConnectCode()(C) say why a connect failed:SDK_ERROR_DISCONNECT(nothing opened),SDK_ERROR_UNEXPECTED_RESPONSE(DEV_INFO unreadable) or the newDEBUGPROBE_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 declaredpayloadLengthunchecked, and every binding copies that many bytes. The length is now clamped to the bytes that arrived, andCosmicSDK_notificationAsUartRxuses 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 afteronNotification()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()andCosmicSDK_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
spiReadBulkat 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 addsbytes × bits ÷ rate × 1.5to the reply wait ofspiWriteBulk,spiReadBulk,spiTransferBulk,i2cWriteBulkandi2cReadBulk. With no rate set, the wait is unchanged. Supernova DBDA0FE0, fwintegration/4.6.2-r2(045bb4a9), Linux, SDK timeout 2000 ms: on 1.7.0 the 32 KB read failed withSDK_ERROR_TIMEOUTat 2003 ms, 3/3, and the next 3-byte read withSDK_ERROR_TIMEOUTat 828 ms, 3/3; on 1.7.1 the read returnsSUCCESSin 2.69 s, 32768 B, 3/3, and the next readSUCCESSin ~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 untilclose()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()overwrotelastFirmwareStatus(). 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::commandnow 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()andopen()(#446).Debug probe:
HidDevice::refusedOldFirmware()is no longer true when DEV_INFO cannot be read;connectCode()returnsSDK_ERROR_UNEXPECTED_RESPONSEfor 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;i2cSetDutyCyclewithhighPct0 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*SetBusVoltagedocuments it and points to*UseExternalVoltage().i3cUseExternalVoltage()ignoressave; 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).
atiratestsaccepts firmware newer than the vendored version and keys the JTAG cell onCAP_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 at643917af, 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, ando1).Debug probe, Atira Rev B, device reset under traffic, SDK only: the 1.7.0 driver aborted with
double free or corruption20/20, 1.7.1 0/20 (#446).macOS symbol gate (#415):
full-ci14/14 onbf01e735.
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.dllon Windows) and its staticdebugprobe_static, with the C++ classdebugprobe::DebugProbe(include/debugprobe/DebugProbe.hpp, 67 public methods), the asyncDebugProbeAsync, and a C API of 69 functions (DebugProbe_*inDebugProbe_API_c.h). Those are the counts a caller reaches; the library also builds the 15 hidden RTT/SWO/UPDI entries, soscripts/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 isenterBootMode(), and the probe mode is the typedProgModeenum indefinitions.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) anddebugCallFunction. SWD is the only debug wire in 1.7.0.SPI controller (13 methods):
spiControllerInit()/spiSetParameters()/spiTransfer()with the same argument lists asCosmicSDK, 1024-byte transfers chunked under one chip select, plus the probe’s own verbs for HID commands0x70–0x7A(spiTransferChunk,spiTransferList, the on-probe hash,spiGetStatus). CS1–CS3 answerFW_FEATURE_NOT_SUPPORTED_BY_HARDWAREunless 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 byDebugProbeasspiFlash*): 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 andpowerGetReading()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, andenterBootMode()for a firmware update.One result vocabulary. Every probe call returns a CosmicSDK
uint16_tcode, checked againstSUCCESSlike 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 genericFW_RESOURCE_BUSY(0x000E), and two probe codes,FW_SWD_HOST_SESSION_ACTIVE(0x1F01, a host CMSIS-DAP session holds the SWD bus) andFW_TEARDOWN_PENDING(0x1F02, a stop has not finished). A value the firmware does not declare isSDK_ERROR_UNEXPECTED_RESPONSE. The SPI flash verdicts are0x0320–0x032Cin the SPI block and the debug codes0x1E01–0x1E0Bin 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 (noCAP_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) andspi_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,CosmicAsyncSDKor 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) andFW_TEARDOWN_PENDING(0x1F02) are new result codes indefinitions.hand in the Python, Java and C# tables. Host adapter firmware does not return them.The C++ core gained a transport seam:
CosmicDrivernow derives fromBinhoDriver, andCommunicationManagertakes the driver and itsTransferProtocolfrom it. This changes the C++ ABI of three internal classes only:CosmicDriver,UsbTransferProtocolandCommunicationManagerchange layout, andlibcosmicsdkno longer exportsCommunicationManager::CommunicationManager()(it takes an optional driver now).CosmicSDKandCosmicAsyncSDKhold 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.0libcosmicsdkon a Supernova. Code that constructs or embeds one of those three classes directly must be rebuilt; it fails at load withsymbol lookup errorrather than later at a call. The C API is not affected.libdebugprobecarries 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-runscripts/install_udev_rules.shafter updating.
Packaging
Every download carries the debug probe library next to
libcosmicsdk: the Linux x64/ARM64 and macOS ARM/Intel zips (.so/.dyliband the static archive) and the three Windows installers (debugprobe.dll,debugprobe.lib,debugprobe_static.lib, release and debug), withinclude/debugprobe/andexamples/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 atconnect()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 thev1.7.0tag), 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 examplecould not claim the vendor interfaceorlibusb_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()returnsSDK_ERROR_TIMEOUTwhen the device never answered the query, andSUCCESSonly 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 reportsSDK_ERROR_TIMEOUThere.
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 of49152.check_bindings.pynow compares theSDK_ERROR_family as well asFW_, 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_eventraisedctypes.ArgumentErroron theNotificationa callback receives, and Java’sNotificationrecord carried no way to reach the event. Both bindings now parse the event while the native notification is alive and carry it onNotification(Pythoni2c_target_bus_event/spi_target_bus_event/i3c_target_bus_event; Javai2cTargetBusEvent()/spiTargetBusEvent()/i3cTargetBusEvent()). Java’sNotificationrecord 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
*Bulkand*Memorymethod, 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 onlyresetDevice(), and a secondi3cTargetInit()answers SUCCESS.Corrected two 1.5.0 changelog entries:
NOTIF_UNKNOWNdid 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, andgetBulkCapabilities()returns the record the device advertises — a per-group payload ceiling and a bitmask of the bulk commands it implements. PreferBulkCapabilities::maxPayloadFor()over the compile-time*_BULK_MAX_PAYLOADconstants, which are only upper bounds. EveryCosmicSDKand C API bulk call refuses locally withSDK_ERROR_BULK_UNAVAILABLEwhen either half is missing, rather than timing out.CosmicAsyncSDKchecks only the host half.Added SPI controller bulk transfers:
spiWriteBulk(),spiReadBulk()andspiTransferBulk(). 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 byMAX_SPI_TRANSFER_LENGTH.Added I2C controller bulk transfers —
i2cWriteBulk()andi2cReadBulk()— 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(), andi3cHdrDdrWriteBulk()/i3cHdrDdrReadBulk().Added I2C target mode:
i2cTargetInit(),i2cTargetSetParameters(),i2cTargetWriteMemory(),i2cTargetReadMemory(),i2cTargetSetEepromConfig(),i2cTargetSetRegisterRegion()andi2cTargetErase(), 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()andspiTargetSetFlashConfig(), with the same notification-based bus-event reporting.Added I3C target mode:
i3cTargetInit(),i3cTargetSetParameters(),i3cTargetWriteMemory()andi3cTargetReadMemory(), plus its bus-event notification.Added
i2cDeinit()andspiDeinit(), wrapping commands the firmware had been dispatching with no host-side entry point.Added
i3cHdrExitPattern()andi3cTargetResetPattern().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_UNKNOWNdid 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 againstNOTIF_UNKNOWNkeeps its meaning. Nothing to change in existing code.include/CosmicNotifications.hcarries the invariant next to the enumerator.A HID write that fails returns
SDK_ERROR_DISCONNECTat once, where 1.4.0 returned SUCCESS and let the blocking call time out. Callers that retried onSDK_ERROR_TIMEOUTshould treatSDK_ERROR_DISCONNECTthe 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
i2cReadalways slicedreadLength, 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 callshid_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_RESPONSEinstead of being read out of the buffer.Fixed the
CMD_SYS_GET_BULK_CAPABILITIESopcode, which did not match the firmware’s value.The Windows DLL now exports the nested
BulkCapabilitiesmethods.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 declaresdriverafteronResponseCallback, and the destructor was empty, so a report already in flight could run through a freedstd::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.spiTransferrefuses atransferLengthorinDatasize aboveMAX_SPI_TRANSFER_LENGTHwithSDK_ERROR_WRONG_REQUESTbefore the request reaches the device;transferLength == 0stays allowed. Callers see the SDK’sSDK_ERROR_WRONG_REQUESTwhere 4.4.0 firmware answeredFW_INVALID_PARAMETER.The C# binding routes I2C and SPI target bus events by
NotificationTypeinstead of the literals 4 and 5. The real values are 5 and 6, and the dispatcher returned early on 4, which isNOTIF_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) andFW_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_REGIONandFW_SPI_TARGET_REGION_TABLE_FULLas 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 indefinitions.hagainst 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 theUsbConfigstruct (WebUSB state, CDC state, and CDC mode) withWebusbState,CdcState, andCdcModeenums.CdcModeselects 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_CHANGEsentinel 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 optionalflagsparameter (defaultI3C_XFER_NONE); passingI3C_XFER_NONSTOPcompletes the CCC without emitting a bus stop.i3cCccENTDAA()does not support this parameter.Extended
i3cHdrDdrWrite()/i3cHdrDdrRead()to accept anI3cTransferFlagsparameter across the C++, Async C++, and C API, all language bindings, and the WebAssembly layer. PassingI3C_XFER_SKIP_EXIT_PATTERN(an alias ofI3C_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 newI3cConnectorEventNotificationstruct, wired through the C/C++ APIs, all language bindings, and the WebAssembly layer.Extended the GPIO interrupt notification to report
triggeredEdge(rising/falling) andlogicLevel(HIGH/LOW) at interrupt time, surfaced through the C/C++ APIs and the Python, Java, and C# bindings.The I3C SDR
i3cSdrWrite()/i3cSdrRead()flagsargument now defaults toI3C_XFER_START_WITH_7Ein 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 requireflagsexplicitly.
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(), andspiSetParameters().
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/libusbbuild 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 singlegetAnalogMeasurements()call that returns all analog readings at once.<protocol>can bei2c,i3c,spi, oruart. The equivalent method for GPIO isgpioGetVoltage()(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 bei2c,i3c,spi,gpio, oruart.Added dedicated named CCC methods to the Async C++ API (
CosmicAsyncSDK) for all supported CCC commands. Previously, CCC operations inCosmicAsyncSDKrequired 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_MODEresult 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 onCosmicSDKandCosmicAsyncSDK, 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 aconnectWasm()path that bypasses HIDAPI enumeration for WASM environments and guardsstd::threadusage behind#ifndef __wasm__.
Bug Fixes
Fixed a missing bounds check in
i2cScanBusthat 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
CosmicSDKand theCosmicAsyncSDKAPI 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.