Mercury Modem
Mercury ARQ/Broadcast modem
Loading...
Searching...
No Matches
carousel.h
Go to the documentation of this file.
1/* datalink_arq/carousel.h -- the carousel data plane: erasure-coded rounds
2 *
3 * One connected session moves data both ways. Per direction the RECEIVER
4 * chooses: what each block still needs, and the next round's mode and size
5 * ("send me up to N frames in mode M"). The receiver chooses the mode because
6 * it is the side whose payload decoder must be bound to it in advance, and the
7 * side that sees what arrives.
8 *
9 * Who keys, and when (docs/CAROUSEL-TURNS.md, proved in specs/turns): the
10 * caller is the session's only timing master (M). It alone keys on timers of
11 * its own, and only where the callee (S) cannot be on the air. S keys only in
12 * slots anchored to the end of an M keydown it decoded. M carries both
13 * directions: it sends its own rounds, which S answers with its poll; and it
14 * polls S for S's rounds, which S sends in its slots.
15 *
16 * Data is cut into blocks of up to CAR_MAX_K pieces of CAR_PIECE bytes,
17 * Reed-Solomon coded (rs_erasure.h): any K pieces rebuild a block, so a poll
18 * says how many pieces a block needs, never which. Pieces fit every mode, so
19 * a block is never re-encoded when the mode changes.
20 *
21 * At the MFSK floor the control mode no longer gets through, so a round is
22 * answered with a pattern instead (car_io_t.pattern): ACK "keep going", BREAK
23 * "the block you are on is delivered". There silence also means "keep going":
24 * M continues once S's slot is over, S in its continuation slots.
25 *
26 * This module is the protocol only: no threads, no clock of its own, no I/O
27 * but the callbacks. tests/sim/carousel_bench.c runs two of them on the sim
28 * channel; the ARQ runtime runs one against the modem.
29 *
30 * Copyright (C) 2026 Rhizomatica
31 * SPDX-License-Identifier: GPL-3.0-or-later
32 */
33#ifndef CAROUSEL_H
34#define CAROUSEL_H
35
36#include <stdbool.h>
37#include <stddef.h>
38#include <stdint.h>
39
40#include "rs_erasure.h"
41
42#define CAR_PIECE 24 /* bytes per piece: fits DATAC15 with the headers */
43/* ...and in a session that starts on the floor: an MFSK frame (98 bytes,
44 * 6 of headers) holds 4 of 23 where it held 3 of 24 -- 92 bytes, not 72.
45 * A whole session uses one size (car_piece_for_start), so blocks
46 * stay uniform; the DATAC rungs carry 4 % less at 23, so only a session
47 * expected to live at the floor takes it. */
48#define CAR_PIECE_FLOOR 23
49#define CAR_MAX_K 96 /* data pieces per block (see carousel.c) */
50#define CAR_WIN 8 /* open blocks at once */
51#define CAR_NLEVELS 7 /* the payload mode ladder (3 bits on the wire) */
52#define CAR_FRAME_MAX 1280 /* largest payload-mode frame, bytes */
53#define CAR_POLL_BYTES 14 /* a poll fills one control-mode (DATAC16) frame */
54#define CAR_KEYDOWN_MAX 16 /* frames in one keydown (a round) */
55#define CAR_MLOG 16 /* M's keydowns whose slots may still be open */
56
57/* One frame of a keydown, as the modem sends it. */
58typedef struct {
59 int mode; /* FREEDV_MODE_* */
60 size_t len;
61 uint8_t bytes[CAR_FRAME_MAX];
62 uint32_t gap_ms; /* silence before this frame (not the first) */
64
65typedef struct {
66 /* Key the radio for these frames, back to back with their gaps. The
67 * frames are only valid during the call. The runtime calls
68 * car_on_tx_done() when the keydown has ended. */
69 void (*keydown)(void *ctx, const car_frame_t *frames, int n);
70 /* Bind the payload decoder to this mode (the control decoder always runs). */
71 void (*bind_rx)(void *ctx, int mode);
72 /* Is the peer on the air? A decoder in sync, held for the sync-loss
73 * latency after it ends. */
74 bool (*peer_keyed)(void *ctx);
75 /* The application's queue: take up to max bytes; how many are waiting. */
76 size_t (*tx_read)(void *ctx, uint8_t *buf, size_t max);
77 size_t (*tx_pending)(void *ctx);
78 /* Bytes for the application, in order. */
79 void (*deliver)(void *ctx, const uint8_t *buf, size_t len);
80 /* This many of our bytes have reached the peer. */
81 void (*tx_confirmed)(void *ctx, size_t len);
82 /* Key a pattern: CAR_PATTERN_ACK or CAR_PATTERN_BREAK. Optional: without
83 * it the floor polls in the control mode like every other rung. The
84 * runtime calls car_on_tx_done() when it has ended. */
85 void (*pattern)(void *ctx, int kind);
86 /* The callee ending the session (car_request_end): key the session's
87 * DISCONNECT now, in the slot the carousel was given. */
88 void (*end)(void *ctx);
89 /* One line on each decision (optional): what the receiver measured and
90 * chose, what the sender was told. For debug logs. */
91 void (*trace)(void *ctx, const char *line);
92 void *ctx;
93 /* Keys each block's check (the session's CRC seed): a block rebuilt from
94 * another session's pieces fails it. */
95 uint32_t block_key;
96} car_io_t;
97
99
100enum { CAR_T_M, CAR_T_S, CAR_T_F, CAR_T_W, CAR_NTIMERS }; /* M's next decision or keydown; S's next slot;
101 * S's fallback to the floor, and its watch
102 * for the round it asked for (listening only) */
103
104typedef struct {
105 uint8_t id;
106 int K, len, next, need; /* next: the next piece index to send */
107 int app_len; /* of len, the application's bytes (the rest: the check) */
108 int resend; /* data piece the receiver waits on, -1 */
109 int sent; /* distinct pieces sent so far (capped) */
110 int round_sent; /* fresh pieces of it in my last round */
111 bool stopped; /* a floor BREAK said it is in; a poll retires it */
112 uint8_t data[CAR_MAX_K][CAR_PIECE];
114
115typedef struct {
116 bool known, done;
117 uint8_t id;
118 int K, len, have; /* len: with the check */
119 int delivered; /* bytes already handed to the application */
120 bool got[RS_MAX_PIECES];
121 uint8_t piece[RS_MAX_PIECES][CAR_PIECE];
123
124typedef struct {
125 uint64_t e; /* when it ended (exact: my own keydown) */
126 uint32_t r, d; /* the longest S keydown it allows; S's lateness */
127 uint32_t p; /* the period of its continuation slots */
128 uint32_t tg; /* when its response slot opens, after it */
129 uint8_t k; /* continuation slots after the response slot */
130 uint8_t done; /* slots I heard S's keydown in, end to end */
131 uint8_t mk; /* its id */
132 bool pat; /* a pattern: S's answers name no id */
133} car_mlog_t;
134
135typedef struct {
137 bool master; /* the caller: the session's only timing master */
138 bool idle; /* nothing in flight either way */
139 int rx_level; /* what the payload decoder is bound to */
140 int snr_level; /* where the SNR measured here starts the peer */
141 int max_level; /* the highest rung the session's bandwidth
142 * allows (car_set_max_level) */
143 bool ctl_deaf; /* I hear the peer below the control mode: its
144 * control must reach me on MFSK (reported) */
145 bool peer_ctl_deaf; /* ...and the peer, of me, as it reports */
146 float snr_ema; /* SNR of what the peer sends us, smoothed */
148 uint64_t deadline[CAR_NTIMERS]; /* 0 = disarmed */
149 uint64_t last_carrier_ms; /* the peer was last heard on the air */
150 bool tx_busy; /* our keydown is on the air */
151
152 /* M: the turn */
153 int phase; /* sending my data, polling the peer's, or idle */
154 uint64_t phase_start;
155 uint8_t mk; /* id of my next keydown, mod 16 */
157 int nmlog;
158 int m_kind; /* my keydown on the air, its id, and the slots it opens: */
159 uint8_t m_id;
160 uint32_t m_r, m_d, m_p;
161 uint8_t m_k;
162 int m_state; /* waiting for S's answer, or for a free time */
163 int plan, plan_lv, plan_n; /* the keydown decided */
164 bool m_heard; /* S keyed since my last keydown, and I heard it end */
165 bool s_answered; /* ...with a poll or a pattern for my round */
166 bool offered; /* M: my round offered S its turn as well (offer_both) */
167 uint64_t kd_allowed; /* M: the length my keydown was checked against FreeFor at */
168 int overruns; /* M: keydowns longer than that (a bug: see keydown()) */
169 int piece; /* the session's piece size (0: CAR_PIECE) */
170 uint32_t deliver_seq; /* deliveries to my application so far */
171 uint32_t seq_at_ask; /* ...when I last asked or answered */
172 uint64_t plan_not_before; /* M: an ack-only DONE waits for my application till then */
173 int last_lv, last_nf; /* my last round, for a REQ */
174 uint8_t last_mk;
175 bool idle_poll; /* my poll on the air only asks whether S has data */
177 bool traffic; /* data moved since I was last idle */
178 int reqs; /* REQs in a row unanswered */
179
180 /* S: the slots */
181 struct {
182 bool on;
183 uint8_t mk; /* the M keydown (its id; patterns carry none) */
184 int kind;
185 uint64_t eh; /* its end, as I learned it */
186 uint32_t p; /* slot period */
187 uint8_t k, i; /* continuation slots; the next slot */
188 bool sent_round; /* I sent a round in this anchor's slots */
189 uint32_t d; /* its lateness allowance: my start may be this late */
190 bool waited; /* its slot 0 already waited for my application */
191 } anc;
192 bool end_req; /* S: my next slot carries the session's DISCONNECT */
193 int req_lv, req_n; /* a REQ: M's round I may not have heard */
194 uint8_t req_mk;
195 uint8_t rx_mk; /* the M round whose frames I am counting */
196 uint64_t s_tx_end; /* when my last keydown ended */
197 bool rx_late; /* the frame being handled was decoded too late to answer */
198 int s_prev_lv; /* the rung M's rounds last came on (-1: none) */
199 bool s_asked_new; /* my poll on the air asks M for another rung */
200 int ok_lv; /* the rung of my last round the peer answered (-1: none) */
201 uint64_t peer_data_ms; /* when a frame of the peer's data last came */
202 bool fell_back; /* M: my last round went back to it */
203
204 /* as sender */
206 int nsb;
207 uint8_t next_blk_id;
208 int tx_level, tx_n; /* as the last poll directed (-1: never polled) */
209 uint8_t tx_poll_id; /* the poll my rounds answer (its keydown id) */
210 int tx_slot; /* ...in this slot (S) */
211 bool tx_pat_anchor; /* ...anchored on a pattern (S) */
212 double tx_loss; /* the receiver's loss estimate, for the margin */
213 bool floor_waiting; /* my floor round is out: a pattern may come */
214 bool pat_waiting; /* my round above the floor is out: a pattern
215 * ("it came whole, the same again") may come */
216 int floor_silent; /* floor rounds in a row with no answer */
217 uint8_t floor_blk; /* the block my last floor round carried */
218 int peer_snr_level; /* where the SNR the peer measures starts me */
219 bool peer_level_known; /* ...as the peer reported it (ACCEPT, poll) */
220 int rx_data_lv; /* the rung of the last data frame I took; -1 none */
221 bool peer_has_data; /* the peer said it has data for me */
222
223 /* as receiver: the peer's direction, measured here */
224 double lv_sent[CAR_NLEVELS], lv_lost[CAR_NLEVELS];
225 int lv_rounds[CAR_NLEVELS], lv_dead_run[CAR_NLEVELS];
226 int lv_probe_fails[CAR_NLEVELS]; /* its rounds in a row that lost half */
227 double lv_p_ok[CAR_NLEVELS]; /* the delivery it showed when it last delivered */
228 uint32_t lv_round_at[CAR_NLEVELS];
229 uint64_t lv_probe_at[CAR_NLEVELS], lv_backoff_ms[CAR_NLEVELS];
230 uint32_t polls;
231 double loss_est;
232 double polled_loss; /* the loss my last poll told the sender */
233 uint8_t poll_id; /* my last poll's keydown id (M), or the one I answer (S) */
234 int poll_level, poll_n; /* what I asked the peer for */
235 int round_seen, round_frames;
236 int round_lv; /* the rung the frames came on */
237 bool rx_tail; /* ...and its last frame among them */
241 uint8_t peer_hi;
242 uint8_t polled_base; /* the window base my last poll reported */
243 bool round_fresh; /* this round carried a block I do not have yet */
244 int stale_rounds; /* floor rounds in a row that carried nothing new */
245 const char *failed; /* car_failed() */
248 uint8_t rbase;
250 bool rx_break; /* the last round delivered the block it carried */
251 int floor_patterns; /* patterns since my last poll */
252 bool floor_streaming; /* a floor round came since my last poll */
254} car_t;
255
256/* Start a connected session. rx_level: the rung the SNR measured here gives
257 * the peer's direction; tx_level: the rung the peer gave ours (-1: unknown,
258 * then rx_level until the peer's frames say). car_start_sender() on the
259 * caller, the session's timing master; car_start_receiver() on the callee. */
260void car_init(car_t *c, const car_io_t *io, int rx_level, int tx_level);
261/* Cap both directions at rung lv: a BW500 session stays below the wideband
262 * modes (DATAC1, DATAC17, QAM16C2). Both ends set the same cap, from the
263 * bandwidth the connect negotiated, after car_init and before starting. */
264void car_set_max_level(car_t *c, int lv);
265/* The highest rung a session bandwidth (Hz, VARA's BW500/BW2300/BW2750)
266 * allows. */
268/* Seed, from the connect exchange, whether each end hears the other below the
269 * control mode (see ctl_on_floor in carousel.c). Frames keep both current. */
270void car_seed_ctl_deaf(car_t *c, bool mine, bool peers);
271/* The peer hears us below the control mode, as it last reported: our control
272 * frames go on MFSK. The session's own control frames follow the same rule. */
273bool car_peer_ctl_deaf(const car_t *c);
274void car_start_sender(car_t *c, uint64_t now);
275void car_start_receiver(car_t *c, uint64_t now);
276
277/* A frame came in. control: the control decoder (DATAC16) produced it;
278 * otherwise mode is the payload decoder's. snr_db: the decoder's estimate
279 * for it, 0 when unknown. age_ms: how long ago the frame ended (0 when the
280 * decode was immediate); one older than its mode's decode bound is data,
281 * never a time to answer at. */
282void car_on_frame(car_t *c, uint64_t now, const uint8_t *bytes, size_t len, int mode, bool control,
283 float snr_db, uint32_t age_ms);
284void car_on_tx_done(car_t *c, uint64_t now);
285/* A pattern was heard: CAR_PATTERN_ACK or CAR_PATTERN_BREAK. */
286void car_on_pattern(car_t *c, uint64_t now, int kind);
287/* Whether a pattern can arrive now (the runtime runs its detector only then). */
288bool car_expect_pattern(const car_t *c);
289/* The application queued data. */
290void car_on_app_data(car_t *c, uint64_t now);
291
292/* The earliest armed deadline (UINT64_MAX: none), and firing what is due. */
293uint64_t car_next_deadline(const car_t *c);
294void car_on_time(car_t *c, uint64_t now);
295
296/* The ladder rung for an SNR, mapped the way trunk enters a mode from DATAC15. */
297int car_start_level(float snr_db);
298int car_level_mode(int level);
299/* The session's piece size, from the rung the callee's ACCEPT starts the
300 * caller's rounds on (both ends know it; the FSM also folds it into the
301 * session seed, so ends that disagree hear none of each other's frames). */
302int car_piece_for_start(int caller_start_level);
303/* The piece size this session cuts its blocks into (tests). */
304int car_piece(const car_t *c);
305/* For the UI: the mode of my last data round, of the last data frame I took,
306 * and of the rung the peer last reported hearing me on. -1: none yet. */
307int car_ui_tx_mode(const car_t *c);
308int car_ui_rx_mode(const car_t *c);
309int car_ui_peer_mode(const car_t *c);
310bool car_is_idle(const car_t *c);
311/* The session can no longer be trusted: a block failed its check, or did not
312 * decode. What it carried may already be partly delivered (the stream runs
313 * ahead of the check), so the session must end -- never carry on. NULL: fine. */
314const char *car_failed(const car_t *c);
315/* Keydowns of M's longer than the slot check allowed them: always 0 (tests). */
316int car_overruns(const car_t *c);
317/* For tests, the turn rules checked from outside: does M's log hold a slot,
318 * not yet over, for a keydown of S's on the air over [start, end)? M keys
319 * clear of every such slot, so S inside one cannot meet M. */
320bool car_slot_reserved(const car_t *m, uint64_t start, uint64_t end);
321/* Every keydown of mine opens with a NAV header this long (0: none), where
322 * car_wants_nav() says the peer may not sense it otherwise (car_set_nav_below_db). */
323void car_set_nav_ms(uint32_t ms);
324void car_set_nav_below_db(float db);
325void car_set_nav_loss(double loss); /* ...or at this loss estimate (default 0.3) */
326bool car_wants_nav(const car_t *c);
327/* A rung's geometry (bytes of data per frame, frames per full keydown, its
328 * airtime, a round's fixed overhead): for computing bounds. */
329void car_rung_geometry(int lv, bool floor_patterns, int *bytes_per_frame, int *frames,
330 uint64_t *round_air_ms, uint64_t *overhead_ms);
331
332/* The session's own control keydowns (its DISCONNECT) follow the turn rules
333 * too. The caller: car_free_at() is the earliest time from now a keydown of
334 * len ms misses every slot the callee could be using; once one has gone out,
335 * car_log_ctl() keeps the callee's reply (tg ms after it) clear of the next.
336 * The callee: car_request_end() makes its next slot call io.end instead of
337 * answering -- it never keys a DISCONNECT on a timer of its own. */
338bool car_is_master(const car_t *c);
339uint64_t car_free_at(const car_t *c, uint64_t now, uint64_t len);
340void car_log_ctl(car_t *c, uint64_t end, uint32_t tg);
341void car_request_end(car_t *c);
342
343/* How long delivering what is left may take on the rung the session is on:
344 * a few exchanges -- my round, the peer's control answer -- there. Seconds
345 * on a fast rung; minutes at the MFSK floor. */
346uint64_t car_drain_budget_ms(const car_t *c);
347/* Bytes taken from the application that the peer has not confirmed yet. */
348size_t car_tx_inflight(const car_t *c);
349
350#endif
static void bind_rx(car_t *c, int lv)
Definition carousel.c:523
int mode
Definition carousel.c:2330
int bw_hz
Definition carousel.c:2369
static bool peer_keyed(car_t *c, uint64_t now)
Definition carousel.c:484
static void keydown(car_t *c, car_frame_t *fr, int n)
Definition carousel.c:503
void car_start_receiver(car_t *c, uint64_t now)
Definition carousel.c:2432
void car_set_nav_loss(double loss)
Definition carousel.c:86
bool car_slot_reserved(const car_t *m, uint64_t start, uint64_t end)
Definition carousel.c:183
void car_init(car_t *c, const car_io_t *io, int rx_level, int tx_level)
Definition carousel.c:2349
bool car_is_master(const car_t *c)
Definition carousel.c:2627
void car_set_max_level(car_t *c, int lv)
Definition carousel.c:2383
void car_log_ctl(car_t *c, uint64_t end, uint32_t tg)
Definition carousel.c:2636
@ CAR_T_M
Definition carousel.h:100
@ CAR_T_F
Definition carousel.h:100
@ CAR_T_S
Definition carousel.h:100
@ CAR_T_W
Definition carousel.h:100
@ CAR_NTIMERS
Definition carousel.h:100
#define CAR_PIECE
Definition carousel.h:42
int car_max_level_for_bw(int bw_hz)
Definition carousel.c:2375
void car_on_tx_done(car_t *c, uint64_t now)
Definition carousel.c:2504
#define CAR_MAX_K
Definition carousel.h:49
void car_on_time(car_t *c, uint64_t now)
Definition carousel.c:2588
int car_ui_tx_mode(const car_t *c)
Definition carousel.c:2408
void car_rung_geometry(int lv, bool floor_patterns, int *bytes_per_frame, int *frames, uint64_t *round_air_ms, uint64_t *overhead_ms)
Definition carousel.c:930
void car_on_app_data(car_t *c, uint64_t now)
Definition carousel.c:2576
#define CAR_NLEVELS
Definition carousel.h:51
int car_piece(const car_t *c)
Definition carousel.c:2406
size_t car_tx_inflight(const car_t *c)
Definition carousel.c:171
int car_level_mode(int level)
Definition carousel.c:161
#define CAR_WIN
Definition carousel.h:50
uint64_t car_drain_budget_ms(const car_t *c)
Definition carousel.c:2618
bool car_peer_ctl_deaf(const car_t *c)
Definition carousel.c:2450
#define CAR_MLOG
Definition carousel.h:55
int car_overruns(const car_t *c)
Definition carousel.c:179
bool car_expect_pattern(const car_t *c)
Definition carousel.c:2571
int car_start_level(float snr_db)
Definition carousel.c:2341
int car_piece_for_start(int caller_start_level)
Definition carousel.c:2401
int car_ui_peer_mode(const car_t *c)
Definition carousel.c:2410
void car_seed_ctl_deaf(car_t *c, bool mine, bool peers)
Definition carousel.c:2452
void car_start_sender(car_t *c, uint64_t now)
Definition carousel.c:2418
void car_on_frame(car_t *c, uint64_t now, const uint8_t *bytes, size_t len, int mode, bool control, float snr_db, uint32_t age_ms)
Definition carousel.c:2460
bool car_wants_nav(const car_t *c)
Definition carousel.c:87
const char * car_failed(const car_t *c)
Definition carousel.c:178
bool car_is_idle(const car_t *c)
Definition carousel.c:166
void car_on_pattern(car_t *c, uint64_t now, int kind)
Definition carousel.c:2546
@ CAR_PATTERN_BREAK
Definition carousel.h:98
@ CAR_PATTERN_ACK
Definition carousel.h:98
void car_set_nav_below_db(float db)
Definition carousel.c:85
#define CAR_KEYDOWN_MAX
Definition carousel.h:54
void car_set_nav_ms(uint32_t ms)
Definition carousel.c:82
#define CAR_FRAME_MAX
Definition carousel.h:52
uint64_t car_next_deadline(const car_t *c)
Definition carousel.c:476
void car_request_end(car_t *c)
Definition carousel.c:2644
uint64_t car_free_at(const car_t *c, uint64_t now, uint64_t len)
Definition carousel.c:2629
int car_ui_rx_mode(const car_t *c)
Definition carousel.c:2409
#define RS_MAX_PIECES
Definition rs_erasure.h:20
Definition carousel.h:58
int mode
Definition carousel.h:59
uint32_t gap_ms
Definition carousel.h:62
size_t len
Definition carousel.h:60
Definition carousel.h:65
void * ctx
Definition carousel.h:92
uint32_t block_key
Definition carousel.h:95
Definition carousel.h:124
uint8_t k
Definition carousel.h:129
uint64_t e
Definition carousel.h:125
uint8_t mk
Definition carousel.h:131
bool pat
Definition carousel.h:132
uint32_t d
Definition carousel.h:126
uint32_t tg
Definition carousel.h:128
uint32_t p
Definition carousel.h:127
uint8_t done
Definition carousel.h:130
Definition carousel.h:115
bool done
Definition carousel.h:116
uint8_t id
Definition carousel.h:117
int delivered
Definition carousel.h:119
int have
Definition carousel.h:118
Definition carousel.h:104
int sent
Definition carousel.h:109
int round_sent
Definition carousel.h:110
int app_len
Definition carousel.h:107
bool stopped
Definition carousel.h:111
int K
Definition carousel.h:106
uint8_t id
Definition carousel.h:105
int resend
Definition carousel.h:108
Definition carousel.h:135
int floor_silent
Definition carousel.h:216
int rx_level
Definition carousel.h:139
uint64_t eh
Definition carousel.h:185
int poll_level
Definition carousel.h:234
double tx_loss
Definition carousel.h:212
bool peer_hi_known
Definition carousel.h:246
bool m_heard
Definition carousel.h:164
uint8_t last_mk
Definition carousel.h:174
bool end_req
Definition carousel.h:192
uint64_t peer_data_ms
Definition carousel.h:201
bool peer_ctl_deaf
Definition carousel.h:145
bool traffic
Definition carousel.h:177
uint8_t tx_poll_id
Definition carousel.h:209
int round_frames
Definition carousel.h:235
int reqs
Definition carousel.h:178
uint32_t d
Definition carousel.h:189
int req_lv
Definition carousel.h:193
int m_kind
Definition carousel.h:158
bool floor_waiting
Definition carousel.h:213
bool peer_unopened
Definition carousel.h:240
bool tx_pat_anchor
Definition carousel.h:211
bool master
Definition carousel.h:137
uint64_t phase_start
Definition carousel.h:154
int kind
Definition carousel.h:184
uint8_t i
Definition carousel.h:187
int round_lv
Definition carousel.h:236
int tx_slot
Definition carousel.h:210
bool on
Definition carousel.h:182
int stale_rounds
Definition carousel.h:244
int done_in_round
Definition carousel.h:249
uint8_t polled_base
Definition carousel.h:242
uint8_t next_blk_id
Definition carousel.h:207
bool idle
Definition carousel.h:138
uint32_t idle_backoff_ms
Definition carousel.h:176
uint8_t m_k
Definition carousel.h:161
bool waited
Definition carousel.h:190
double loss_est
Definition carousel.h:231
int s_prev_lv
Definition carousel.h:198
uint8_t m_id
Definition carousel.h:159
float snr_ema
Definition carousel.h:146
uint8_t rbase
Definition carousel.h:248
uint8_t mk
Definition carousel.h:155
uint32_t polls
Definition carousel.h:230
const char * failed
Definition carousel.h:245
bool peer_level_known
Definition carousel.h:219
uint32_t deliver_seq
Definition carousel.h:170
double polled_loss
Definition carousel.h:232
bool round_fresh
Definition carousel.h:243
bool tx_busy
Definition carousel.h:150
bool idle_poll
Definition carousel.h:175
int ok_lv
Definition carousel.h:200
int nsb
Definition carousel.h:206
bool fell_back
Definition carousel.h:202
int snr_level
Definition carousel.h:140
int overruns
Definition carousel.h:168
bool rx_late
Definition carousel.h:197
int max_level
Definition carousel.h:141
uint8_t req_mk
Definition carousel.h:194
bool sent_round
Definition carousel.h:188
bool rx_tail
Definition carousel.h:237
bool pat_waiting
Definition carousel.h:214
uint64_t s_tx_end
Definition carousel.h:196
int phase
Definition carousel.h:153
bool rx_break
Definition carousel.h:250
bool snr_valid
Definition carousel.h:147
uint8_t floor_blk
Definition carousel.h:217
uint64_t plan_not_before
Definition carousel.h:172
int rx_data_lv
Definition carousel.h:220
int nmlog
Definition carousel.h:157
int plan
Definition carousel.h:163
uint8_t poll_id
Definition carousel.h:233
int piece
Definition carousel.h:169
bool offered
Definition carousel.h:166
bool ctl_deaf
Definition carousel.h:143
uint32_t m_d
Definition carousel.h:160
car_io_t io
Definition carousel.h:136
bool peer_has_data
Definition carousel.h:221
uint32_t seq_at_ask
Definition carousel.h:171
uint8_t peer_hi
Definition carousel.h:241
bool s_asked_new
Definition carousel.h:199
uint64_t last_carrier_ms
Definition carousel.h:149
int last_lv
Definition carousel.h:173
uint32_t p
Definition carousel.h:186
uint8_t rx_mk
Definition carousel.h:195
int peer_snr_level
Definition carousel.h:218
bool floor_streaming
Definition carousel.h:252
int m_state
Definition carousel.h:162
int tx_level
Definition carousel.h:208
uint64_t kd_allowed
Definition carousel.h:167
bool status_seen
Definition carousel.h:238
int floor_patterns
Definition carousel.h:251
bool s_answered
Definition carousel.h:165
int silent_polls
Definition carousel.h:239