modules/woz_uwb/src/ccc/ccc_shim_rx.c
openaliro/openaliro
Module

ccc_shim_rx.c

responder-RX CCC STS substitution: woz_uwb_arm_rx() programs the CCC STS…

modules/woz_uwb/src/ccc/ccc_shim_rx.c28 documented symbols

Overview

responder-RX CCC STS substitution: woz_uwb_arm_rx() programs the CCC STS on each RX-arm; target only.

depends on woz_log.h woz_port.h aliro_round_config.h ccc_kdf.h ccc_mac.h ccc_shim.h uwb_min.h uwb_rxdiag.h uwb_seam.h flight_recorder.h woz_bytes.h woz_diag.h fira_session.h

flowchart TD
  arm_final_data_sp0 --> gated_rxenable

API

Fstatic uint32_t ccc_rx_cur_cand(void)

modules/woz_uwb/src/ccc/ccc_shim_rx.c:236

Current candidate index: the latched lock, or the live sweep value.

called by woz_uwb_arm_rx

Fvoid ccc_shim_rx_log_reset(void)

modules/woz_uwb/src/ccc/ccc_shim_rx.c:246

Reset all Per-POLL state: arm count, index tracking, STS warm cache, and optional lock-sweep diagnostic counters; called on entry to a new Pre-POLL listen.

called by ccc_prepoll_listen

Fbool ccc_shim_rx_awaiting_poll(void)

modules/woz_uwb/src/ccc/ccc_shim_rx.c:286

Returns true if the responder is awaiting the POLL frame after a successful Pre-POLL decode.

returns
true if awaiting POLL, false otherwise.

Fbool ccc_shim_rx_deadline_pending(void)

modules/woz_uwb/src/ccc/ccc_shim_rx.c:295

Return true if CCC UWB reception is awaiting either POLL or FINAL frame from the responder, false otherwise.

Fbool ccc_shim_rx_awaiting_final(void)

modules/woz_uwb/src/ccc/ccc_shim_rx.c:303

Return true if CCC UWB reception is awaiting a FINAL frame from the responder, false otherwise.

Fvoid ccc_shim_rx_notify_rx(uint32_t status)

modules/woz_uwb/src/ccc/ccc_shim_rx.c:314

Log one RX event for the optional lock-sweep diagnostic (CONFIG_CCC_RX_LOCK_SWEEP); tracks CPER (STS correlation fail flag) and dwells candidate indices until lock achieved or full cycle exhausted.

status
DW3000 status register value.

Fstatic void prepoll_decode(const uint8_t *frame, uint16_t datalength)

modules/woz_uwb/src/ccc/ccc_shim_rx.c:365

Decode a received Pre-POLL frame: verify MHR and message ID, decrypt SP0 payload, cache UAD-derived keys, extract Poll_STS_Index and stride, and pre-warm the next block's STS triplet (POLL, Response_0, Final) to eliminate KDF latency from the critical path.

frame
Pointer to the received frame buffer.
datalength
Length of the frame in bytes.
called by ccc_shim_rx_try_prepoll, prepoll_rx_rearm, resp_tx_done

Fstatic uint64_t ts5_to_u64(const uint8_t t[5])

modules/woz_uwb/src/ccc/ccc_shim_rx.c:478

Assemble a 5-byte DW3000 (40-bit) timestamp into a uint64 (DTU ticks).

called by final_data_decode, prepoll_rx_rearm, resp_tx_done

Fstatic void final_data_decode(const uint8_t *frame, uint16_t datalength)

modules/woz_uwb/src/ccc/ccc_shim_rx.c:507

Decode a received Final_Data (SP0, msg_id=02): dUDSK-decrypt and parse the initiator's ranging timestamps; not time-critical.

frame
Pointer to the received frame buffer.
datalength
Length of the frame in bytes.
called by ccc_shim_rx_try_prepoll  ·  calls ts5_to_u64

Fvoid ccc_shim_rx_try_prepoll(uint16_t datalength)

modules/woz_uwb/src/ccc/ccc_shim_rx.c:710

Pre-POLL RX entry (from the RX-good shim): stash the frame and DEFER its ~2 ms decrypt+derive off the Pre-POLL->POLL critical path. The decode only feeds the NEXT block's warm (the SP3 arm keys on the pre-warmed prediction, not this block's fresh index), so it has the ~190 ms idle to run in. Running it inline — on the single DW3000 workqueue, ahead of the queued POLL RX-OK callback — pushed the Response TX arm past its slot (dx-now < 0 => HPDWARN). So read the bytes now (cheap SPI), then: - bootstrap (no warm yet): decode inline to seed the first arm's STS — this block is not armed, so blocking its POLL is harmless; - steady state: mark pending; @ref prepoll_rx_rearm runs @ref prepoll_decode after the Response TX is armed. A pending decode orphaned by a missed POLL is flushed on the next Pre-POLL so the warm never goes more than one block stale.

calls final_data_decode, prepoll_decode

Fstatic void pack_key(dwt_sts_cp_key_t *out, const uint8_t dursk[CCC_DURSK_LEN])

modules/woz_uwb/src/ccc/ccc_shim_rx.c:754

Pack a 16-byte dURSK into the DW3000 STS-key image (whole-16 reverse).

called by ccc_pack_selftest, sts_key_load, woz_uwb_arm_rx

Fstatic void pack_iv(dwt_sts_cp_iv_t *out, const uint8_t sts_v[CCC_STS_V_LEN])

modules/woz_uwb/src/ccc/ccc_shim_rx.c:773

Pack a 16-byte STS-V into the DW3000 STS-IV image (whole-16 reverse then per-word LE, same as pack_key).

out
Pointer to the DW3000 STS-IV register image.
sts_v
16-byte STS vector to pack.
called by arm_final_sp3, arm_poll_sp3, ccc_pack_selftest, tx_response_sp3, woz_uwb_arm_rx

Fstatic void sts_key_load(const uint8_t dursk[CCC_DURSK_LEN])

modules/woz_uwb/src/ccc/ccc_shim_rx.c:794

The STS key (dURSK) is per ranging CYCLE — POLL, Response, Final and every block in the cycle share it — but each arm re-wrote all four STS_KEY registers: ~258 us of SPI on the critical path, ~40% of the arm latency that misses the ~1836 us slot deadline. Cache the loaded dURSK and skip dwt_configurestskey when unchanged; the STS_KEY registers persist across the per-frame IV/loadiv/mode reprogramming within a session. ccc_shim_rx_log_reset() clears the cache (a new session's dwt_configure re-clears the registers). Only the ~16-byte IV write remains per arm. (g_sts_key_cache / g_sts_key_cached are declared up top so ccc_shim_rx_log_reset can clear them.)

called by arm_final_sp3, arm_poll_sp3, tx_response_sp3  ·  calls pack_key

Fstatic void pack_iv_rev(dwt_sts_cp_iv_t *out, const uint8_t v[CCC_STS_V_LEN])

modules/woz_uwb/src/ccc/ccc_shim_rx.c:830

Pack a 16-byte V whole-16-reversed then word-LE (the pack_key/blob convention).

called by ccc_pack_selftest

Fstatic void ccc_pack_selftest(void)

modules/woz_uwb/src/ccc/ccc_shim_rx.c:844

One-shot: dump STS register lanes for the KAT V under three packings.

called by woz_uwb_arm_rx  ·  calls pack_iv, pack_iv_rev, pack_key

Fint32_t woz_uwb_arm_rx(int32_t mode)

modules/woz_uwb/src/ccc/ccc_shim_rx.c:887

Program the CCC STS for the current ranging slot, then arm RX.

calls ccc_pack_selftest, ccc_rx_cur_cand, pack_iv, pack_key

Fstatic int32_t gated_rxenable(int32_t mode)

modules/woz_uwb/src/ccc/ccc_shim_rx.c:1010

Gate-checked RX arm for every self-rearm site below; refuses once the listen-gate is closed. Arms the radio directly: each caller has just programmed the STS for the window it is opening, so re-running woz_uwb_arm_rx would overwrite it with the current slot's.

called by arm_final_data_sp0, arm_final_sp3, arm_poll_sp3, prepoll_rx_rearm, revert_to_sp0_listen

Fstatic int arm_poll_sp3(uint32_t prepoll_ip)

modules/woz_uwb/src/ccc/ccc_shim_rx.c:1020

Flip to SP3/ND, load the pre-warmed CCC STS (g_warm_index), and arm a delayed RX to catch the POLL that follows the Pre-POLL.

called by prepoll_rx_rearm  ·  calls gated_rxenable, pack_iv, sts_key_load

Fstatic void revert_to_sp0_listen(void)

modules/woz_uwb/src/ccc/ccc_shim_rx.c:1077

Revert SP3/ND -> SP0 and re-arm the permanent Pre-POLL listen (no timeout).

called by prepoll_rx_rearm, resp_tx_done  ·  calls gated_rxenable

Fstatic int arm_final_data_sp0(uint32_t final_ip)

modules/woz_uwb/src/ccc/ccc_shim_rx.c:1132

Arm the DW3000 radio to receive Final_Data in SP0 mode (data frame, not STS) at a delayed time calculated from the Final frame's ideal arrival. Record margin metrics and adjust the open time if it has already passed. Return 0 on success or -EIO if the arm fails.

called by prepoll_rx_rearm  ·  calls gated_rxenable

Fstatic int tx_response_sp3(uint32_t poll_ip, uint32_t resp_idx)

modules/woz_uwb/src/ccc/ccc_shim_rx.c:1174

Delayed-TX the responder's Response_0 (SP3-ND) one slot after the POLL, at STS index Poll_STS_Index + 1 (same dURSK, STS-V advances).

called by prepoll_rx_rearm  ·  calls pack_iv, sts_key_load

Fstatic int arm_final_sp3(uint32_t poll_ip)

modules/woz_uwb/src/ccc/ccc_shim_rx.c:1213

Arm the delayed SP3-ND RX for the phone's Final at STS index Poll_STS_Index+ALIRO_FINAL_SLOT_OFFSET, packing the g_armed_final_* STS (no KDF). EXPERIMENT-2RESP: the 1:1 baseline uses POLL + 2 slots / index+2; a 2-responder round puts the Final at POLL + 3 (responder 1's silent slot sits at POLL + 2).

called by prepoll_rx_rearm, resp_tx_done  ·  calls gated_rxenable, pack_iv, sts_key_load

Fstatic void resp_tx_done(const dwt_cb_data_t *cb)

modules/woz_uwb/src/ccc/ccc_shim_rx.c:1245

TX-done (TXFRS) callback: our Response_0 left the antenna, so arm the Final RX one slot later, then run the block's deferred Pre-POLL decode in the idle.

calls arm_final_sp3, prepoll_decode, revert_to_sp0_listen, ts5_to_u64

Fstatic void prepoll_rx_rearm(const dwt_cb_data_t *cb)

modules/woz_uwb/src/ccc/ccc_shim_rx.c:1296

RX callback for Pre-POLL listen and POLL/Final results. Re-arms SP0 by default, or arms SP3/ND for POLL if a warmed index is ready, or fires the delayed-TX Response_0 and Final RX arm on valid POLL CPER; logs free-running timing and optionally defers Pre-POLL decode to warm the next block.

calls arm_final_data_sp0, arm_final_sp3, arm_poll_sp3, gated_rxenable, prepoll_decode, revert_to_sp0_listen, ts5_to_u64, tx_response_sp3

Fstatic int prepoll_apply_phy(uint8_t channel, uint8_t preamble_code)

modules/woz_uwb/src/ccc/ccc_shim_rx.c:1589

Radio init + forcetrxoff + (cached) dwt_configure. Session-start context only — never the RX re-arm path.

called by ccc_prepoll_listen, ccc_prepoll_prewarm

Fint ccc_prepoll_prewarm(uint8_t channel, uint8_t preamble_code)

modules/woz_uwb/src/ccc/ccc_shim_rx.c:1638

Pre-apply the expected session PHY ahead of M4. Leaves the radio configured with TRX off: no callbacks are (re)installed and RX is not enabled, so nothing can fire until ccc_prepoll_listen() arms the listener.

calls prepoll_apply_phy

Fint ccc_prepoll_listen(uint8_t channel, uint8_t preamble_code)

modules/woz_uwb/src/ccc/ccc_shim_rx.c:1646

Initialize the DW3000 radio for permanent SP0 Pre-POLL listen: configure PHY (6.8 Mbps, preamble length 64, SFD 4a, no STS), install RX callbacks that self-rearm on every frame outcome, and enable all RX/TX interrupts; returns 0 on success.

calls ccc_shim_rx_log_reset, prepoll_apply_phy

Fvoid ccc_prepoll_stop(void)

modules/woz_uwb/src/ccc/ccc_shim_rx.c:1688

Stop the permanent Pre-POLL listener: close the listen-gate (every self-rearm site checks it via gated_rxenable), then force the radio out of RX/TX. The DW3000 callbacks run on the dedicated coop (-11) isr workqueue with busy-polled SPI and synchronous woz_printf, so a callback never yields mid-flight: one in flight when a preemptive-thread caller gets here has already run to completion (its rearm landed BEFORE our forcetrxoff), and any later callback sees the gate closed. A residual rearm window exists only if this is ever called from an ISR or a coop thread at prio <= -11.