Skip to content

Commit 9a4c454

Browse files
wip
1 parent 599b721 commit 9a4c454

File tree

2 files changed

+16
-21
lines changed

2 files changed

+16
-21
lines changed

AGENTS.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,11 @@ Keep code compact and add brief comments before non-obvious logic.
1919

2020
Treat warnings as errors and keep compatibility with strict warning flags.
2121

22+
**FORCE PUSH MUST NEVER BE USED**. The git history is sacrosanct and must not be rewritten. If you need to undo a change, make a new commit.
23+
2224
For agent-authored commits, set `GIT_AUTHOR_NAME="Agent"` and `GIT_COMMITTER_NAME="Agent"`.
2325

24-
**FORCE PUSH MUST NEVER BE USED**. The git history is sacrosanct and must not be rewritten. If you need to undo a change, make a new commit.
26+
The build system will reject code that is not clang-formatted; use build target `format` to invoke clang-format.
2527

2628
## Adversarial validation and verification
2729

libcanard/canard.c

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,9 @@ typedef unsigned char byte_t;
6363

6464
#define FOREACH_IFACE(i) for (size_t i = 0; (i) < CANARD_IFACE_COUNT; (i)++)
6565

66-
#if CANARD_IFACE_COUNT <= 4
66+
#if CANARD_IFACE_COUNT <= 2
67+
#define IFACE_INDEX_BIT_LENGTH 1U
68+
#elif CANARD_IFACE_COUNT <= 4
6769
#define IFACE_INDEX_BIT_LENGTH 2U
6870
#elif CANARD_IFACE_COUNT <= 8
6971
#define IFACE_INDEX_BIT_LENGTH 3U
@@ -1193,7 +1195,6 @@ static byte_t rx_transfer_id_forward_difference(const byte_t a, const byte_t b)
11931195

11941196
// Reassembly state at a specific priority level.
11951197
// Maintaining separate state per priority level allows preemption of higher-priority transfers without loss.
1196-
// Each state is only kept as long as the transfer reassembly is in progress; once it's completed, the slot is deleted.
11971198
typedef struct
11981199
{
11991200
canard_us_t start_ts;
@@ -1211,14 +1212,6 @@ typedef struct
12111212
// resulting in 1 KiB o1heap blocks per session, very expensive. Here we use a much less RAM-heavy approach with
12121213
// sparse nodes in a tree with log-time lookup.
12131214
//
1214-
// The session keeps the last transfer-ID, plus each slot holds one as well. This is needed because a low-priority
1215-
// transfer may be temporarily preempted by a higher-priority one; each transfer has a unique transfer-ID within
1216-
// the transfer-ID wraparound window. It is possible that a low-priority transfer with ID N is preempted by a sequence
1217-
// of transfers whose count is a multiple of the wraparound window; if the transfer-ID deduplication was done at the
1218-
// slot level only, then such sequence could cause the slot to reject a new transfer as a duplicate. To avoid this,
1219-
// transfer-ID state in the slots is only used for start-of-transfer loss detection, while deduplication relies on the
1220-
// single shared state at the session level.
1221-
//
12221215
// Core invariants:
12231216
// - Only start-of-transfer may create/replace a slot.
12241217
// - Non-start frames never create state.
@@ -1280,8 +1273,9 @@ static canard_tree_t* rx_session_factory(void* const user)
12801273
FOREACH_SLOT (i) {
12811274
ses->slots[i] = NULL;
12821275
}
1283-
ses->owner = ctx->owner;
1284-
ses->node_id = ctx->node_id;
1276+
ses->last_admitted_start_ts = BIG_BANG;
1277+
ses->owner = ctx->owner;
1278+
ses->node_id = ctx->node_id;
12851279
enlist_tail(&ctx->owner->owner->rx.list_session_by_animation, &ses->list_animation);
12861280
return &ses->index;
12871281
}
@@ -1356,16 +1350,15 @@ static bool rx_session_update(canard_subscription_t* const sub,
13561350

13571351
// Frame admittance state machine. A highly complex piece, redesigned after v4 to support priority preemption.
13581352
// TID forward difference illustration: f(2,3)==31, f(2,2)==0, f(2,1)==1
1359-
const bool tid_new = rx_transfer_id_forward_difference(ses->last_admitted_transfer_id, frame->transfer_id) > 1;
1360-
const canard_us_t timed_out = (ts - ses->last_admitted_start_ts) > ses->owner->transfer_id_timeout;
1361-
bool accept = false;
1353+
const bool tid_new = rx_transfer_id_forward_difference(ses->last_admitted_transfer_id, frame->transfer_id) > 1;
1354+
const bool timed_out = ts > (ses->last_admitted_start_ts + ses->owner->transfer_id_timeout);
1355+
bool accept = false;
1356+
const rx_slot_t* const slot = ses->slots[frame->priority];
13621357
if (!frame->start) {
1363-
const rx_slot_t* const slot = ses->slots[frame->priority];
13641358
accept = (slot != NULL) && (slot->transfer_id == frame->transfer_id) && (slot->iface_index == iface_index) &&
13651359
(slot->expected_toggle == frame->toggle);
13661360
} else {
1367-
const rx_slot_t* const slot = ses->slots[frame->priority];
1368-
accept = (slot == NULL) || (slot->transfer_id != frame->transfer_id) || tid_new || timed_out; // --
1361+
accept = ((slot == NULL) || (slot->transfer_id != frame->transfer_id)) && (tid_new || timed_out);
13691362
}
13701363
if (!accept) {
13711364
return true; // Frame not needed; not a failure to accept.
@@ -1374,8 +1367,6 @@ static bool rx_session_update(canard_subscription_t* const sub,
13741367
// The frame must be accepted. If this is the start of a new transfer, we must update state.
13751368
enlist_tail(&sub->owner->rx.list_session_by_animation, &ses->list_animation);
13761369
if (frame->start) {
1377-
ses->last_admitted_start_ts = ts;
1378-
ses->last_admitted_transfer_id = frame->transfer_id;
13791370
rx_slot_destroy(sub, ses->slots[frame->priority]);
13801371
ses->slots[frame->priority] = NULL;
13811372
if (!frame->end) { // more frames to follow, must store in-progress state
@@ -1385,6 +1376,8 @@ static bool rx_session_update(canard_subscription_t* const sub,
13851376
return false;
13861377
}
13871378
}
1379+
ses->last_admitted_start_ts = ts;
1380+
ses->last_admitted_transfer_id = frame->transfer_id;
13881381
}
13891382

13901383
// TODO acceptance

0 commit comments

Comments
 (0)