FAQ === General ------- How do I connect to a specific device? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use serial-number-based connection when you know the adapter serial. Use HID path when you want to bind to a specific OS device path. **C++ API** .. code-block:: cpp auto sdk = std::make_unique(2000); bool okSerial = sdk->connectWithSerialNumber("SN12345678"); bool okPath = sdk->connect(R"(\\?\hid#vid_2e8a&pid_...)"); **C API** .. code-block:: c CosmicSDK_Handle* h = CosmicSDK_Create(2000); bool ok_serial = CosmicSDK_ConnectWithSerialNumber(h, "SN12345678"); bool ok_path = CosmicSDK_Connect(h, "\\\\?\\hid#vid_2e8a&pid_..."); I2C --- Which I2C role is supported by the host adapters? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The host adapter works as I2C Controller (Master) only. Support for the Target (Slave) role is planned for a future release. **C++ API** .. code-block:: cpp // Controller/Master initialization entry point uint16_t rc = sdk->i2cControllerInit(I2C_BUS_A, 400000, I2C_PULLUP_2_2kOhm); **C API** .. code-block:: c // Controller/Master initialization entry point uint16_t rc = CosmicSDK_I2cControllerInit(h, I2C_BUS_A, 400000, I2C_PULLUP_2_2kOhm); How many I2C buses are supported on Supernova and Pulsar? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Supernova supports one I2C bus (``I2C_BUS_A``). Pulsar supports two I2C buses (``I2C_BUS_A`` and ``I2C_BUS_B``). **C++ API** .. code-block:: cpp uint16_t rcA = sdk->i2cControllerInit(I2C_BUS_A, 400000, I2C_PULLUP_2_2kOhm); uint16_t rcB = sdk->i2cControllerInit(I2C_BUS_B, 400000, I2C_PULLUP_2_2kOhm); // Pulsar only **C API** .. code-block:: c uint16_t rcA = CosmicSDK_I2cControllerInit(h, I2C_BUS_A, 400000, I2C_PULLUP_2_2kOhm); uint16_t rcB = CosmicSDK_I2cControllerInit(h, I2C_BUS_B, 400000, I2C_PULLUP_2_2kOhm); // Pulsar only How do I differentiate I2C buses in the API? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use the ``bus`` argument (``I2C_BUS_A`` or ``I2C_BUS_B``) in all I2C methods. **C++ API** .. code-block:: cpp sdk->i2cWrite(I2C_BUS_A, 0x50, {0x00}, {0xAA, 0xBB}); sdk->i2cWrite(I2C_BUS_B, 0x50, {0x00}, {0xCC, 0xDD}); **C API** .. code-block:: c uint8_t sub[] = {0x00}; uint8_t dataA[] = {0xAA, 0xBB}; uint8_t dataB[] = {0xCC, 0xDD}; CosmicSDK_I2cWrite(h, I2C_BUS_A, 0x50, sub, 1, dataA, 2, false); CosmicSDK_I2cWrite(h, I2C_BUS_B, 0x50, sub, 1, dataB, 2, false); How do I initialize the I2C interface? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Set bus voltage (if needed), then call the I2C controller init method. **C++ API** .. code-block:: cpp sdk->i2cSetBusVoltage(3300); uint16_t rc = sdk->i2cControllerInit(I2C_BUS_A, 400000, I2C_PULLUP_2_2kOhm); **C API** .. code-block:: c CosmicSDK_I2cSetBusVoltage(h, 3300, false); uint16_t rc = CosmicSDK_I2cControllerInit(h, I2C_BUS_A, 400000, I2C_PULLUP_2_2kOhm); How do I change I2C bus configuration after initialization? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Call the set-parameters method instead of calling init again. **C++ API** .. code-block:: cpp uint16_t rc = sdk->i2cSetParameters(I2C_BUS_A, 1000000, I2C_PULLUP_1kOhm); **C API** .. code-block:: c uint16_t rc = CosmicSDK_I2cSetParameters(h, I2C_BUS_A, 1000000, I2C_PULLUP_1kOhm); How do I write to and read from an I2C target (slave)? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use ``i2cWrite`` / ``CosmicSDK_I2cWrite`` to send bytes to the target address, and ``i2cRead`` / ``CosmicSDK_I2cRead`` to read bytes from that target. **C++ API** .. code-block:: cpp std::vector tx = {0xAA, 0xBB, 0xCC}; std::vector rx; sdk->i2cWrite(I2C_BUS_A, 0x50, {0x00, 0x10}, tx, false); // Write at subaddress 0x0010 sdk->i2cRead(I2C_BUS_A, 0x50, {0x00, 0x10}, 8, rx, false); // Read 8 bytes from subaddress 0x0010 **C API** .. code-block:: c uint8_t subaddr[] = {0x00, 0x10}; uint8_t tx[] = {0xAA, 0xBB, 0xCC}; uint8_t rx[8] = {0}; CosmicSDK_I2cWrite(h, I2C_BUS_A, 0x50, subaddr, 2, tx, 3, false); // Write at subaddress 0x0010 CosmicSDK_I2cRead(h, I2C_BUS_A, 0x50, subaddr, 2, 8, rx, false); // Read 8 bytes from subaddress 0x0010 How can I scan the bus and discover the static address of the I2C targets connected to the USB host adapter? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use ``i2cScanBus`` / ``CosmicSDK_I2cScanBus``. The discovered static addresses are returned in the output vector/buffer. .. note:: Depending on the bus characteristics, such as frequency, voltage, number of targets connected, and the length of the wires used in the hardware setup, the performance of the I2C SCAN BUS may be affected, and as a result, it might return a wrong list of detected addresses, an ``SDK_ERROR_TIMEOUT`` error, and the firmware might indeed get stuck, especially in the Pulsar. In order to avoid this scenario, consider the following recommendations to run a smooth scan bus procedure: - Set the clock frequency to low values, such as 100KHz and 400 KHz. - Disable the pull-up resistors, or set their value to high values - weak pull-ups. - In the case of the Pulsar, suggested values are: ``I2C_PULLUP_DISABLE`` , ``I2C_PULLUP_4kOhm``, or ``I2C_PULLUP_2_2kOhm`` - In the case of the Supernova, suggested values are: ``I2C_PULLUP_DISABLE`` , ``I2C_PULLUP_10kOhm``, or ``I2C_PULLUP_4_7kOhm`` **C++ API** .. code-block:: cpp std::vector addresses; uint8_t count7Bit = 0; uint8_t count10Bit = 0; uint16_t rc = sdk->i2cScanBus(addresses, &count7Bit, &count10Bit, I2C_BUS_A, true); **C API** .. code-block:: c uint8_t addresses[32] = {0}; uint8_t count7Bit = 0; uint8_t count10Bit = 0; uint16_t rc = CosmicSDK_I2cScanBus(h, addresses, 32, &count7Bit, &count10Bit, I2C_BUS_A, true); Does the API support I2C 10-bit addresses? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Only bus scan supports 10-bit addresses today. 10-bit transfer support already exists in firmware but is not yet exposed in the public API. We plan to add API support for 10-bit transfers in a future release. Which I2C pull-up resistor values are valid for Supernova and which for Pulsar? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The two devices differ on the available pull-up resistor values. The constants from 150 Ω to 2.2 kΩ are shared; above 2.2 kΩ each device provides its own set. Passing an unsupported value returns ``FW_INVALID_PARAMETER``. .. list-table:: I2C pull-up resistor support by device :header-rows: 1 :widths: 40 15 15 * - Constant - Supernova - Pulsar * - ``I2C_PULLUP_150Ohm`` - Yes - Yes * - ``I2C_PULLUP_220Ohm`` - Yes - Yes * - ``I2C_PULLUP_330Ohm`` - Yes - Yes * - ``I2C_PULLUP_470Ohm`` - Yes - Yes * - ``I2C_PULLUP_680Ohm`` - Yes - Yes * - ``I2C_PULLUP_1kOhm`` - Yes - Yes * - ``I2C_PULLUP_1_5kOhm`` - Yes - Yes * - ``I2C_PULLUP_2_2kOhm`` - Yes - Yes * - ``I2C_PULLUP_3_3kOhm`` - Yes - No * - ``I2C_PULLUP_4kOhm`` - No - Yes * - ``I2C_PULLUP_4_7kOhm`` - Yes - No * - ``I2C_PULLUP_10kOhm`` - Yes - No * - ``I2C_PULLUP_DISABLE`` - Yes - Yes SPI --- Which SPI role is supported by the host adapters? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The host adapter works as SPI Controller (Master) only. **C++ API** .. code-block:: cpp uint16_t rc = sdk->spiControllerInit( SPI_BIT_ORDER_MSB, SPI_MODE_0, SPI_DATA_WIDTH_8_BITS, SPI_CHIP_SELECT_0, SPI_CS_ACTIVE_LOW, 1000000); **C API** .. code-block:: c uint16_t rc = CosmicSDK_SpiControllerInit( h, SPI_BIT_ORDER_MSB, SPI_MODE_0, SPI_DATA_WIDTH_8_BITS, SPI_CHIP_SELECT_0, SPI_CS_ACTIVE_LOW, 1000000); How do I initialize the SPI interface? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Set SPI voltage (if needed), then call SPI controller init. **C++ API** .. code-block:: cpp sdk->spiSetBusVoltage(3300); uint16_t rc = sdk->spiControllerInit( SPI_BIT_ORDER_MSB, SPI_MODE_0, SPI_DATA_WIDTH_8_BITS, SPI_CHIP_SELECT_0, SPI_CS_ACTIVE_LOW, 10000000); **C API** .. code-block:: c CosmicSDK_SpiSetBusVoltage(h, 3300, false); uint16_t rc = CosmicSDK_SpiControllerInit( h, SPI_BIT_ORDER_MSB, SPI_MODE_0, SPI_DATA_WIDTH_8_BITS, SPI_CHIP_SELECT_0, SPI_CS_ACTIVE_LOW, 10000000); How do I change SPI bus configuration after initialization? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use SPI set-parameters to reconfigure without reinitializing. **C++ API** .. code-block:: cpp uint16_t rc = sdk->spiSetParameters( SPI_BIT_ORDER_MSB, SPI_MODE_3, SPI_DATA_WIDTH_8_BITS, SPI_CHIP_SELECT_1, SPI_CS_ACTIVE_LOW, 5000000); **C API** .. code-block:: c uint16_t rc = CosmicSDK_SpiSetParameters( h, SPI_BIT_ORDER_MSB, SPI_MODE_3, SPI_DATA_WIDTH_8_BITS, SPI_CHIP_SELECT_1, SPI_CS_ACTIVE_LOW, 5000000); How do I transmit and receive data in SPI? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Current host adapters support 4-wire SPI. In this mode, TX (MOSI) and RX (MISO) run in parallel during a transfer clock window. For this reason, the API exposes a single method, ``spiTransfer`` / ``CosmicSDK_SpiTransfer``, for both transmit and receive. Provide TX data and transfer length, and read the received bytes from the output buffer/vector. **C++ API** .. code-block:: cpp std::vector tx = {0x9F}; // JEDEC ID command std::vector rx; uint16_t rc = sdk->spiTransfer(tx, rx, 4); // 1 command byte + 3 response bytes **C API** .. code-block:: c uint8_t tx[1] = {0x9F}; // JEDEC ID command uint8_t rx[4] = {0}; uint16_t rc = CosmicSDK_SpiTransfer(h, tx, 1, rx, 4); // 1 command byte + 3 response bytes UART ---- How do I initialize the UART interface? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Configure the UART line settings with ``uartInit`` / ``CosmicSDK_UartInit`` before sending data. **C++ API** .. code-block:: cpp uint16_t rc = sdk->uartInit( UART_BAUD_115200, UART_HW_HANDSHAKE_DIS, UART_PARITY_NONE, UART_DATA_SIZE_8, UART_STOP_BIT_1); **C API** .. code-block:: c uint16_t rc = CosmicSDK_UartInit( h, UART_BAUD_115200, UART_HW_HANDSHAKE_DIS, UART_PARITY_NONE, UART_DATA_SIZE_8, UART_STOP_BIT_1); How do I change UART configuration after initialization? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use the UART set-parameters method. **C++ API** .. code-block:: cpp uint16_t rc = sdk->uartSetParameters( UART_BAUD_9600, UART_HW_HANDSHAKE_DIS, UART_PARITY_NONE, UART_DATA_SIZE_8, UART_STOP_BIT_1); **C API** .. code-block:: c uint16_t rc = CosmicSDK_UartSetParameters( h, UART_BAUD_9600, UART_HW_HANDSHAKE_DIS, UART_PARITY_NONE, UART_DATA_SIZE_8, UART_STOP_BIT_1); How do I transmit data in UART? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use ``uartSendMessage`` / ``CosmicSDK_UartSendMessage`` after UART initialization. **C++ API** .. code-block:: cpp std::vector msg = {'H', 'e', 'l', 'l', 'o', '\n'}; uint16_t rc = sdk->uartSendMessage(msg); **C API** .. code-block:: c uint8_t msg[] = "Hello\n"; uint16_t rc = CosmicSDK_UartSendMessage(h, msg, 6); How does UART reception work? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UART RX is asynchronous only. Register a notification callback and parse UART notifications with helper accessors/functions. Polling is not supported. **C++ API** .. code-block:: cpp sdk->onNotification([](const Notification& n) { if (const UartRxNotification* rx = n.uartRx()) { // rx->data / rx->dataLength } }); **C API** .. code-block:: c static void cb(const Notification* n) { UartRxNotification rx; if (CosmicSDK_notificationAsUartRx(n, &rx)) { // rx.data / rx.dataLength } } CosmicSDK_onNotification(h, cb); GPIO ---- How do I configure GPIOs? ^^^^^^^^^^^^^^^^^^^^^^^^^^ Call GPIO configure pin with the pin number and desired mode (input or output). **C++ API** .. code-block:: cpp sdk->gpioConfigurePin(GPIO_1, GPIO_DIGITAL_INPUT); sdk->gpioConfigurePin(GPIO_3, GPIO_DIGITAL_OUTPUT, GPIO_LOW); **C API** .. code-block:: c CosmicSDK_GpioConfigurePin(h, GPIO_1, GPIO_DIGITAL_INPUT, false, GPIO_LOW); CosmicSDK_GpioConfigurePin(h, GPIO_3, GPIO_DIGITAL_OUTPUT, true, GPIO_LOW); How do I enable GPIO interrupts? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ First configure the pin as digital input, then configure the interrupt trigger type. **C++ API** .. code-block:: cpp sdk->gpioConfigurePin(GPIO_1, GPIO_DIGITAL_INPUT); sdk->gpioConfigureInterrupt(GPIO_1, GPIO_TRIGGER_BOTH_EDGES); **C API** .. code-block:: c CosmicSDK_GpioConfigurePin(h, GPIO_1, GPIO_DIGITAL_INPUT, false, GPIO_LOW); CosmicSDK_GpioConfigureInterrupt(h, GPIO_1, GPIO_TRIGGER_BOTH_EDGES); How do I receive and handle asynchronous GPIO interrupt notifications? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Register a notification callback and parse GPIO notifications using helper accessors/functions. **C++ API** .. code-block:: cpp sdk->onNotification([](const Notification& n) { if (const GpioInterruptNotification* g = n.gpio()) { // g->pinNumber } }); **C API** .. code-block:: c static void cb(const Notification* n) { GpioInterruptNotification gpio; if (CosmicSDK_notificationAsGpio(n, &gpio)) { // gpio.pinNumber } } CosmicSDK_onNotification(h, cb); I3C --- Which I3C role does Supernova support? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Supernova supports the I3C Controller role in the current API. **C++ API** .. code-block:: cpp uint16_t rc = sdk->i3cControllerInit( PUSH_PULL_10_MHz_DC_40, OPEN_DRAIN_400_KHz, FAST_MODE, FAST); **C API** .. code-block:: c uint16_t rc = CosmicSDK_I3cControllerInit( h, PUSH_PULL_10_MHz_DC_40, OPEN_DRAIN_400_KHz, FAST_MODE, FAST); Which I3C modes do Supernova and the I3C API support? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The supported transfer modes are: - I3C SDR - Legacy I2C over the I3C bus - I3C HDR-DDR Write/read method mapping per mode: - I3C SDR: ``i3cSdrWrite`` / ``i3cSdrRead`` - Legacy I2C over I3C: ``i3cLegacyI2cWrite`` / ``i3cLegacyI2cRead`` - I3C HDR-DDR: ``i3cHdrDdrWrite`` / ``i3cHdrDdrRead`` **C++ API** .. code-block:: cpp std::vector out; std::vector in = {0x11, 0x22}; // I3C SDR sdk->i3cSdrWrite(0x08, {0x00}, in, I3C_XFER_NONE); sdk->i3cSdrRead(0x08, {0x00}, 8, out, I3C_XFER_NONE); // Legacy I2C over I3C sdk->i3cLegacyI2cWrite(0x50, {0x00}, in, I3C_XFER_NONE); sdk->i3cLegacyI2cRead(0x50, {0x00}, 8, out, I3C_XFER_NONE); // I3C HDR-DDR sdk->i3cHdrDdrWrite(0x08, 0x20, in); sdk->i3cHdrDdrRead(0x08, 0x20, 8, out); **C API** .. code-block:: c uint8_t in[2] = {0x11, 0x22}; uint8_t out[32]; uint8_t out_len = 0; // I3C SDR CosmicSDK_I3cSdrWrite(h, 0x08, NULL, 0, in, 2, I3C_XFER_NONE); CosmicSDK_I3cSdrRead(h, 0x08, NULL, 0, 8, out, &out_len, I3C_XFER_NONE); // Legacy I2C over I3C CosmicSDK_I3cLegacyI2CWrite(h, 0x50, NULL, 0, in, 2, I3C_XFER_NONE); CosmicSDK_I3cLegacyI2CRead(h, 0x50, NULL, 0, 8, out, I3C_XFER_NONE); // I3C HDR-DDR CosmicSDK_I3cHdrDdrWrite(h, 0x08, 0x20, in, 2); CosmicSDK_I3cHdrDdrRead(h, 0x08, 0x20, 8, out); How do I initialize the I3C interface? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Set I3C voltage and then initialize the controller. **C++ API** .. code-block:: cpp sdk->i3cSetBusVoltage(1200); uint16_t rc = sdk->i3cControllerInit( PUSH_PULL_10_MHz_DC_40, OPEN_DRAIN_400_KHz, FAST_MODE, FAST); **C API** .. code-block:: c CosmicSDK_I3cSetBusVoltage(h, 1200); uint16_t rc = CosmicSDK_I3cControllerInit( h, PUSH_PULL_10_MHz_DC_40, OPEN_DRAIN_400_KHz, FAST_MODE, FAST); How do I change I3C bus configuration after initialization? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use I3C set-parameters. **C++ API** .. code-block:: cpp uint16_t rc = sdk->i3cSetParameters( PUSH_PULL_2_5_MHz_DC_25, OPEN_DRAIN_100_KHz, STANDARD_MODE, STANDARD); **C API** .. code-block:: c uint16_t rc = CosmicSDK_I3cSetParameters( h, PUSH_PULL_2_5_MHz_DC_25, OPEN_DRAIN_100_KHz, STANDARD_MODE, STANDARD); How do I initialize the I3C bus with or without a target table? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Call ``InitBus`` with an empty table for controller-driven discovery (RSTDAA + ENTDAA). Pass a target table when you need deterministic setup (mixed I3C/I2C, predefined addressing/configuration). The table uses ``I3cTargetInfo``, including ``I3cBCR`` and ``I3cTargetConfiguration``. **C++ API** .. code-block:: cpp // Discovery flow (no predefined table) sdk->i3cInitBus(); // Deterministic flow with predefined targets I3cBCR bcrI3c{}; bcrI3c.byte = 0x27; // non-zero BCR I3cTargetConfiguration confI3c{}; confI3c.bits.targetType = 0; // I3C target confI3c.bits.daaUseENTDAA = true; confI3c.bits.IBIRequest = true; I3cBCR bcrI2c{}; bcrI2c.byte = 0x00; I3cTargetConfiguration confI2c{}; confI2c.bits.targetType = 1; // Legacy I2C target confI2c.bits.daaUseENTDAA = false; std::vector targets = { // Supernova can use this desired dynamic address during ENTDAA by matching PID/BCR/DCR. {0x69, 0x2A, {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC}, bcrI3c, 0x5D, 0, 0, 0, confI3c}, {0x50, 0x00, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, bcrI2c, 0x00, 0, 0, 0, confI2c} }; sdk->i3cInitBus(targets); **C API** .. code-block:: c // Discovery flow (no predefined table) CosmicSDK_I3cInitBus(h, NULL, 0); // Deterministic flow with predefined targets I3cBCR bcr_i3c = {0}; bcr_i3c.byte = 0x27; // non-zero BCR I3cTargetConfiguration conf_i3c = {0}; conf_i3c.bits.targetType = 0; // I3C target conf_i3c.bits.daaUseENTDAA = true; conf_i3c.bits.IBIRequest = true; I3cBCR bcr_i2c = {0}; bcr_i2c.byte = 0x00; I3cTargetConfiguration conf_i2c = {0}; conf_i2c.bits.targetType = 1; // Legacy I2C target conf_i2c.bits.daaUseENTDAA = false; I3cTargetInfo targets[2] = { // Supernova can use this desired dynamic address during ENTDAA by matching PID/BCR/DCR. {0x69, 0x2A, {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC}, bcr_i3c, 0x5D, 0, 0, 0, conf_i3c}, {0x50, 0x00, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, bcr_i2c, 0x00, 0, 0, 0, conf_i2c} }; CosmicSDK_I3cInitBus(h, targets, 2); How do I assign dynamic addresses? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use ``InitBus`` for default assignment, or explicit CCCs: ``ENTDAA`` for dynamic discovery, ``SETDASA`` for static-to-dynamic mapping, and ``SETAASA`` for assigning from known static-address targets. **C++ API** .. code-block:: cpp sdk->i3cInitBus(); sdk->i3cCccENTDAA(); sdk->i3cCccSETDASA(0x69, 0x0B); sdk->i3cCccSETAASA({0x69, 0x6B}); **C API** .. code-block:: c CosmicSDK_I3cInitBus(h, NULL, 0); CosmicSDK_I3cCccENTDAA(h); CosmicSDK_I3cCccSETDASA(h, 0x69, 0x0B); uint8_t static_addresses[] = {0x69, 0x6B}; CosmicSDK_I3cCccSETAASA(h, static_addresses, 2); Which CCCs are supported by the API? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The API supports common controller-side CCC operations, including: - Address assignment and discovery: ``RSTDAA``, ``ENTDAA``, ``SETDASA``, ``SETAASA``, ``SETNEWDA`` - Target identification and capabilities: ``GETPID``, ``GETBCR``, ``GETDCR``, ``GETSTATUS``, ``GETCAPS`` - Event and reset control: ``ENEC`` (broadcast/direct), ``DISEC`` (broadcast/direct), ``RSTACT`` (broadcast/direct) - Transfer limits: ``GETMWL``, ``SETMWL`` (broadcast/direct), ``GETMRL``, ``SETMRL`` (broadcast/direct) **C++ API** .. code-block:: cpp sdk->i3cCccRSTDAA(); sdk->i3cCccENTDAA(); sdk->i3cCccSETDASA(0x69, 0x0B); sdk->i3cCccSETAASA({0x69, 0x6B}); sdk->i3cCccSETNEWDA(0x08, 0x09); std::vector pid, status, caps; uint8_t bcr = 0, dcr = 0; uint16_t mwl = 0, mrl = 0; std::optional ibiLen; sdk->i3cCccGETPID(0x08, pid); sdk->i3cCccGETBCR(0x08, bcr); sdk->i3cCccGETDCR(0x08, dcr); sdk->i3cCccGETSTATUS(0x08, status, ibiLen); sdk->i3cCccGETCAPS(0x08, caps, ibiLen); sdk->i3cCccENECBroadcast(IBI); sdk->i3cCccENECDirect(0x08, IBI); sdk->i3cCccDISECBroadcast(IBI); sdk->i3cCccDISECDirect(0x08, IBI); sdk->i3cCccRSTACTBroadcast(RESET_I3C_PERIPHERAL); uint8_t resetTime = 0; sdk->i3cCccRSTACTDirect(0x08, RETURN_TIME_RESET_PERIPHERAL, resetTime); sdk->i3cCccGETMWL(0x08, mwl); sdk->i3cCccSETMWLBroadcast(256); sdk->i3cCccSETMWLDirect(0x08, 256); sdk->i3cCccGETMRL(0x08, mrl, ibiLen); sdk->i3cCccSETMRLBroadcast(256); sdk->i3cCccSETMRLDirect(0x08, 256); **C API** .. code-block:: c CosmicSDK_I3cCccRSTDAA(h); CosmicSDK_I3cCccENTDAA(h); CosmicSDK_I3cCccSETDASA(h, 0x69, 0x0B); uint8_t static_addresses[] = {0x69, 0x6B}; CosmicSDK_I3cCccSETAASA(h, static_addresses, 2); CosmicSDK_I3cCccSETNEWDA(h, 0x08, 0x09); uint8_t pid[6] = {0}; uint8_t bcr = 0, dcr = 0; uint8_t status[8] = {0}, caps[8] = {0}; uint8_t status_len = 0, caps_len = 0; uint16_t mwl = 0, mrl = 0; bool has_ibi_len = false; uint8_t ibi_len = 0; CosmicSDK_I3cCccGETPID(h, 0x08, pid); CosmicSDK_I3cCccGETBCR(h, 0x08, &bcr); CosmicSDK_I3cCccGETDCR(h, 0x08, &dcr); CosmicSDK_I3cCccGETSTATUS(h, 0x08, status, sizeof(status), &status_len, &has_ibi_len, &ibi_len); CosmicSDK_I3cCccGETCAPS(h, 0x08, caps, sizeof(caps), &caps_len, &has_ibi_len, &ibi_len); CosmicSDK_I3cCccENECBroadcast(h, IBI); CosmicSDK_I3cCccENECDirect(h, 0x08, IBI); CosmicSDK_I3cCccDISECBroadcast(h, IBI); CosmicSDK_I3cCccDISECDirect(h, 0x08, IBI); CosmicSDK_I3cCccRSTACTBroadcast(h, RESET_I3C_PERIPHERAL); uint8_t reset_time = 0; CosmicSDK_I3cCccRSTACTDirect(h, 0x08, RETURN_TIME_RESET_PERIPHERAL, &reset_time); CosmicSDK_I3cCccGETMWL(h, 0x08, &mwl); CosmicSDK_I3cCccSETMWLBroadcast(h, 256); CosmicSDK_I3cCccSETMWLDirect(h, 0x08, 256); CosmicSDK_I3cCccGETMRL(h, 0x08, &mrl, &has_ibi_len, &ibi_len); CosmicSDK_I3cCccSETMRLBroadcast(h, 256, false, 0); CosmicSDK_I3cCccSETMRLDirect(h, 0x08, 256, false, 0); How can I know the actual transfer length in an I3C SDR read? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ An I3C target can terminate a read early using End-Of-Data (EOD, T-bit = 0), so the actual returned length may be shorter than requested. - In C++, check ``outData.size()`` after ``i3cSdrRead``. - In C, check ``outDataLength`` from ``CosmicSDK_I3cSdrRead``. **C++ API** .. code-block:: cpp std::vector outData; uint16_t rc = sdk->i3cSdrRead(0x08, {0x00}, 32, outData, I3C_XFER_NONE); if (rc == SUCCESS) { size_t actualLen = outData.size(); // May be < 32 when target signals EOD } **C API** .. code-block:: c uint8_t out[32]; uint8_t actual_len = 0; uint16_t rc = CosmicSDK_I3cSdrRead(h, 0x08, NULL, 0, 32, out, &actual_len, I3C_XFER_NONE); if (rc == SUCCESS) { // actual_len may be < 32 when target signals EOD } How do I handle I3C IBIs? ^^^^^^^^^^^^^^^^^^^^^^^^^ IBIs are asynchronous notifications. Register a callback and decode notifications using the helper accessors/functions. **C++ API** .. code-block:: cpp sdk->onNotification([](const Notification& n) { if (const I3cIbiNotification* ibi = n.i3cIbi()) { // ibi->address, ibi->payload, ibi->payloadLength } }); **C API** .. code-block:: c static void cb(const Notification* n) { I3cIbiNotification ibi; if (CosmicSDK_notificationAsI3cIbi(n, &ibi)) { // ibi.address, ibi.payload, ibi.payloadLength } } CosmicSDK_onNotification(h, cb); How do I handle I3C Hot-Join notifications? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Hot-Join is also asynchronous. Register a callback and parse the notification using the helper accessors/functions. **C++ API** .. code-block:: cpp sdk->onNotification([](const Notification& n) { if (const I3cHotJoinNotification* hj = n.i3cHotJoin()) { // hj->dynamicAddress, hj->bcr, hj->dcr // PID bytes: hj->pid[0] ... hj->pid[5] } }); **C API** .. code-block:: c static void cb(const Notification* n) { I3cHotJoinNotification hj; if (CosmicSDK_notificationAsI3cHotJoin(n, &hj)) { // hj.dynamicAddress, hj.bcr, hj.dcr // PID bytes: hj.pid[0] ... hj.pid[5] } } CosmicSDK_onNotification(h, cb);