# Telemetry Interface The LiquidCore15 firmware streams a continuous binary telemetry frame over **UART** and **UDP** at **100 Hz**, giving a host controller or operator GUI a real-time view of all monitored control variables. --- ## Frame Format Every frame is exactly **63 bytes**: | Byte(s) | Field | Value | |---------|-------|-------| | `[0]` | Sync low | `0x55` | | `[1]` | Sync high | `0xAA` | | `[2]` | Length | `0x3A` (58 decimal = payload size) | | `[3..60]` | Payload | `TelemetryPayload_t` — 58 bytes, packed | | `[61]` | CRC low | CRC16-CCITT low byte | | `[62]` | CRC high | CRC16-CCITT high byte | Sync bytes form the little-endian word `0xA55A` — check both bytes before decoding. **CRC:** CRC16-CCITT (polynomial `0x1021`, init `0xFFFF`) computed over bytes `[2..60]` (59 bytes: length byte + full payload). No output inversion. --- ## Payload Fields `TelemetryPayload_t` is `__attribute__((packed))`, 58 bytes. Field order is stable — the host decoder assumes this exact layout. | Offset | Type | Field | Description | |--------|------|-------|-------------| | 0 | `float` | `Vdc` | DC bus voltage (V) | | 4 | `float` | `Ia` | Phase A current (A) | | 8 | `float` | `Ib` | Phase B current (A) | | 12 | `float` | `Ic` | Phase C current (A) | | 16 | `float` | `Va` | Phase A grid voltage (V) | | 20 | `float` | `Vb` | Phase B grid voltage (V) | | 24 | `float` | `Vc` | Phase C grid voltage (V) | | 28 | `float` | `Id` | d-axis current feedback (A) | | 32 | `float` | `Iq` | q-axis current feedback (A) | | 36 | `float` | `Id_ref` | d-axis current reference (A) | | 40 | `float` | `Iq_ref` | q-axis current reference (A) | | 44 | `float` | `theta` | PLL grid angle (rad, 0 .. 2π) | | 48 | `float` | `omega` | PLL angular frequency (rad/s) | | 52 | `uint8_t` | `pll_locked` | `1` = locked, `0` = searching | | 53 | `uint8_t` | `mode` | FSM state (see below) | | 54 | `uint32_t` | `fault_flags` | Active fault bitmask (see below) | All floats are IEEE 754 single-precision, little-endian (Cortex-M native byte order). ### `mode` — FSM State | Value | State | |-------|-------| | `0x00` | `FSM_INIT` | | `0x01` | `READY` | | `0x02` | `RUNNING` | | `0x03` | `FAULT` | ### `fault_flags` — Fault Bitmask | Bit | Fault | |-----|-------| | 0 | Over-voltage (OV) | | 1 | Under-voltage (UV) | | 2 | Over-current (OC) | | 3 | Frequency high | | 4 | Frequency low | --- ## Transmission **UART:** USART3 (`hcom_uart[COM1]`), 115200 baud, GPDMA1 Channel 0 (DMA mode). - Cadence: every 160th control tick → **100 Hz**. - If UART DMA is busy when a frame is ready, the frame is **dropped silently**. At 100 Hz × 63 bytes = 6 300 bytes/s versus 11 520 bytes/s line capacity, collision probability is low. - Double-buffering: two 63-byte buffers swap between fill and DMA-in-flight roles. **UDP:** The same 63-byte frame is forwarded to `eth_send_telem()` (implemented in `eth.c`) on every tick, independent of UART DMA state. --- ## Integration Checklist - [ ] Open a 115200-baud serial connection to USART3 (or listen on the UDP socket). - [ ] Scan the byte stream for the two-byte sync sequence `0x55 0xAA`. - [ ] Read the next 61 bytes (length + payload + CRC). - [ ] Verify CRC16-CCITT over bytes `[2..60]`; discard frame on mismatch. - [ ] Deserialize `TelemetryPayload_t` in the field order above (little-endian floats). - [ ] Check `pll_locked` before using `theta` / `omega` for phase-sensitive calculations. - [ ] Check `fault_flags != 0` and handle `mode == 0x03` (FAULT) before commanding.