decodeRaw

fun decodeRaw(packet: ByteArray, config: DeviceConfig, state: DecodeState, contactOut: (BooleanArray) -> Unit? = null, hardware: DeviceHardware = DeviceHardware.legacyDefault(config.model), out: (values: FloatArray, isDummy: Boolean) -> Unit): Boolean

Decode one stream packet, emitting a positional layout per sample: [ch_0 … ch_{A-1}, (accX, accY, accZ if accel), (gyroX, gyroY, gyroZ if gyro), sampleIndex, dummyFlag, battery], where dummy (gap-fill) samples use channelCount leading zeros and dummyFlag = 1. IMU values are raw int16 counts. Its sampleIndex column is a Float, exact only up to 2^24 — long recordings must take the index from decode instead.

Footer, from the end of the packet: [gyro 6]? [accel 6]? [contact c] [timestamp 4] [sampleSize 1].

Sample numbering and gap-fill:

  • normal mode: missing indices up to MAX_FILLED_GAP_SECONDS of signal become dummies; a longer jump resyncs the cursor without dummies, a packet only partly behind the cursor appends at it; both count in DecodeState.counterJumps. A packet wholly behind it is dropped, decoding to nothing (DecodeState.stalePackets); a counter that moved back and stays there resyncs the cursor to it (see takePacket). The counter is unsigned 32-bit.

  • impedance mode: no gap-fill — the counter skips a whole measurement sweep between values on purpose. Value j of a packet with S values is numbered with the ADC sample it was taken at, timestamp − (S−1−j)·25·A, and contact reads all-true (the lead-off bits mean nothing while the device drives the impedance current).

The trailing sampleSize byte is only the delta offset in normal mode; the firmware sends 0 in impedance mode, so impedance samples are strided by 3·A from the config.