.. _bulk_transport: Bulk Transfers ============== Why bulk exists --------------- Every command travels in HID reports, which cap one transfer at the report size: 64 bytes on Supernova, 1024 bytes on Pulsar. That is enough for register-level traffic, but a page-sized payload — a flash image, an EEPROM dump, a large sensor FIFO — pays the HID framing cost many times over, and the ordinary calls stop at ``MAX_I2C_TRANSFER_LENGTH`` and ``MAX_SPI_TRANSFER_LENGTH`` (1024 bytes). Bulk transfers add a second, larger pipe for **payload bytes only**, over the device's vendor bulk endpoints. Nothing else changes route. How it works: the command and the payload travel separately ----------------------------------------------------------- - The **request** (command code, lengths, addresses, sub-addresses) and the **reply** (result code, announced payload length) travel over HID exactly like every other command. - Only the **data bytes** — what a write clocks out, or what a read brings back — move over the vendor bulk endpoints. So if the host cannot claim the vendor endpoints, every HID command keeps working, including the ordinary ``i2cWrite``, ``i2cRead`` and ``spiTransfer``. Only the bulk calls become unavailable, and they say so with ``SDK_ERROR_BULK_UNAVAILABLE`` (0xC000) instead of hanging. Which calls use it ------------------ .. list-table:: :widths: 15 45 40 :header-rows: 1 * - Protocol - Controller - Target * - I2C - ``i2cWriteBulk``, ``i2cReadBulk`` - ``i2cTargetWriteMemory``, ``i2cTargetReadMemory`` * - SPI - ``spiWriteBulk``, ``spiReadBulk``, ``spiTransferBulk`` - ``spiTargetWriteMemory``, ``spiTargetReadMemory`` * - I3C - ``i3cSdrWriteBulk``, ``i3cSdrReadBulk``, ``i3cHdrDdrWriteBulk``, ``i3cHdrDdrReadBulk``, ``i3cLegacyI2cWriteBulk``, ``i3cLegacyI2cReadBulk`` - none — ``i3cTargetWriteMemory`` / ``i3cTargetReadMemory`` use HID (see :ref:`target_mode`) Each has the same name, prefixed with ``CosmicSDK_``, in the C API. The asynchronous C++ API has the same calls, but does not check the device's capability record before sending (see below). Layer by layer -------------- - **Blocking C++ API** (``CosmicSDK``) — the intended entry point. Every bulk call checks both the host and the device before it sends anything, then moves the payload and returns an ordinary result code. - **C API** — mirrors the blocking C++ API one to one. ``CosmicSDK_GetBulkCapabilities`` fills a caller-supplied ``CosmicSDK_BulkGroup`` array. - **Asynchronous C++ API** (``CosmicAsyncSDK``) — checks only that the host claimed the vendor endpoints. Query ``getBulkCapabilities`` yourself before sending a bulk command there, or a device that does not implement it costs a full timeout. - **Python, Java and C# bindings** — wrap the C API, with the same calls. - **WebAssembly** — the bulk entry points exist for parity and always answer 0xC000; the vendor endpoints are not reachable from the browser build. When to use it -------------- - Use a bulk call when the payload exceeds what the ordinary call accepts, or when throughput matters: flash programming, memory dumps, streaming a target arena. - Keep the ordinary call for register-sized traffic. It works on every host, needs no vendor endpoint, and has no per-connection capability query. - **I3C HDR-DDR gains nothing today**: it is capped at ``I3C_HDR_DDR_MAX_PAYLOAD`` (1024 bytes), which the ordinary call already reaches. SDR is the I3C mode where bulk buys a larger transfer. - The SDK does not split transfers. Anything larger than one call's ceiling is several calls. .. doxygengroup:: CosmicSDK_Bulk