Skip to content

Commit dc47b3a

Browse files
wip
1 parent dc9f57a commit dc47b3a

2 files changed

Lines changed: 35 additions & 638 deletions

File tree

libcanard/canard.c

Lines changed: 35 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1188,17 +1188,16 @@ static byte_t rx_transfer_id_forward_difference(const byte_t a, const byte_t b)
11881188

11891189
// Reassembly state at a specific priority level.
11901190
// Maintaining separate state per priority level allows preemption of higher-priority transfers without loss.
1191-
// Each state is only kept as long as the transfer reassembly is in progress; once it's completed, the slot is
1192-
// immediately destroyed.
1191+
// Each state is only kept as long as the transfer reassembly is in progress; once it's completed, the slot is deleted.
11931192
typedef struct
11941193
{
1195-
canard_us_t timestamp; // Timestamp of the start-of-transfer.
1196-
size_t total_payload_size; // The raw payload size before the implicit truncation and CRC removal.
1197-
canard_bytes_mut_t payload; // Dynamically allocated and handed off to the application when done.
1194+
canard_us_t start_ts;
1195+
size_t total_size; // The raw payload size before the implicit truncation and CRC removal.
1196+
canard_bytes_mut_t payload; // Dynamically allocated and handed off to the application when done.
11981197
uint16_t crc;
11991198
byte_t transfer_id : CANARD_TRANSFER_ID_BIT_LENGTH;
1200-
byte_t toggle : 1;
1201-
byte_t single_frame : 1; // Not extent-sized; the payload size is full size.
1199+
byte_t expected_toggle : 1;
1200+
byte_t iface_index;
12021201
} rx_slot_t;
12031202
static_assert((sizeof(void*) > 4) || (sizeof(rx_slot_t) <= 24), "too large");
12041203

@@ -1218,35 +1217,36 @@ typedef struct
12181217
{
12191218
canard_tree_t index;
12201219
canard_listed_t list_animation; // On update, session moved to the tail; oldest pushed to the head.
1221-
canard_us_t timestamp;
1220+
canard_us_t last_admitted_start_ts;
12221221
rx_slot_t* slots[CANARD_PRIO_COUNT]; // Indexed by priority level to allow preemption.
12231222
canard_subscription_t* owner;
1224-
byte_t transfer_id; // Used for deduplication.
1223+
byte_t last_admitted_transfer_id;
12251224
byte_t node_id;
1226-
byte_t iface_index; // Currently accepting frames only from this iface.
12271225
} rx_session_t;
12281226
static_assert((sizeof(void*) > 4) || (sizeof(rx_session_t) <= 120), "too large");
12291227

12301228
static rx_slot_t* rx_slot_new(const canard_subscription_t* const sub,
1231-
const canard_us_t ts,
1229+
const canard_us_t start_ts,
12321230
const byte_t transfer_id,
1231+
const byte_t iface_index,
12331232
const bool v1)
12341233
{
12351234
rx_slot_t* const slot = mem_alloc_zero(sub->owner->mem.rx_slot, sizeof(rx_slot_t));
12361235
if (slot != NULL) {
1237-
slot->timestamp = ts;
1238-
slot->payload.data = NULL;
1239-
slot->crc = sub->crc_seed;
1240-
slot->transfer_id = transfer_id & CANARD_TRANSFER_ID_MAX;
1241-
slot->toggle = v1 ? 1 : 0;
1236+
slot->start_ts = start_ts;
1237+
slot->payload.data = NULL;
1238+
slot->crc = sub->crc_seed;
1239+
slot->transfer_id = transfer_id & CANARD_TRANSFER_ID_MAX;
1240+
slot->expected_toggle = v1 ? 1 : 0;
1241+
slot->iface_index = iface_index;
12421242
}
12431243
return slot;
12441244
}
12451245

12461246
static void rx_slot_destroy(const canard_subscription_t* const sub, rx_slot_t* const slot)
12471247
{
12481248
if (slot != NULL) {
1249-
mem_free(sub->owner->mem.rx_payload, slot->single_frame ? slot->payload.size : sub->extent, slot->payload.data);
1249+
mem_free(sub->owner->mem.rx_payload, slot->payload.size, slot->payload.data);
12501250
mem_free(sub->owner->mem.rx_slot, sizeof(rx_slot_t), slot);
12511251
}
12521252
}
@@ -1295,67 +1295,41 @@ static void rx_session_destroy(rx_session_t* const ses)
12951295
// Checks the state and purges stale slots to reclaim memory early. Returns the number of in-progress slots remaining.
12961296
static size_t rx_session_scan(rx_session_t* const ses, const canard_us_t now)
12971297
{
1298-
const canard_us_t deadline = now - later(RX_SESSION_TIMEOUT, ses->owner->transfer_id_timeout);
1299-
size_t in_progress_slots = 0;
1298+
const canard_us_t deadline = now - later(RX_SESSION_TIMEOUT, ses->owner->transfer_id_timeout);
1299+
size_t n_slots = 0;
13001300
FOREACH_SLOT (i) {
13011301
const rx_slot_t* const slot = ses->slots[i];
13021302
if (slot == NULL) {
13031303
continue;
13041304
}
1305-
CANARD_ASSERT(slot->timestamp >= 0);
1306-
if (slot->timestamp < deadline) { // Too old, destroy even if in progress -- unlikely to complete anyway.
1305+
CANARD_ASSERT(slot->start_ts >= 0);
1306+
CANARD_ASSERT(ses->last_admitted_start_ts >= slot->start_ts);
1307+
if (slot->start_ts < deadline) { // Too old, destroy even if in progress -- unlikely to complete anyway.
13071308
rx_slot_destroy(ses->owner, ses->slots[i]);
13081309
ses->slots[i] = NULL;
13091310
} else {
1310-
ses->timestamp = later(ses->timestamp, slot->timestamp);
1311-
if (slot->total_payload_size > 0) {
1312-
in_progress_slots++;
1313-
}
1311+
n_slots++;
13141312
}
13151313
}
1316-
return in_progress_slots;
1314+
return n_slots;
13171315
}
13181316

1319-
// Returns false on OOM, no other failure modes. Stores at most extent bytes.
1320-
// Has an optimization for single-frame transfers where the allocated size is capped by min(extent, payload_size).
1321-
// The idea is that if we receive the first frame that is also the last, there is no need to allocate full extent-sized
1322-
// buffer if the actual frame payload is smaller.
1323-
static bool rx_slot_write_payload(rx_session_t* const ses,
1324-
rx_slot_t* const slot,
1325-
const canard_bytes_t payload,
1326-
const bool end)
1317+
// Returns false on OOM, no other failure modes. Stores at most extent bytes. This is ONLY for multi-frame transfers.
1318+
static bool rx_slot_write_payload(rx_session_t* const ses, rx_slot_t* const slot, const canard_bytes_t payload)
13271319
{
13281320
CANARD_ASSERT(slot->payload.size <= ses->owner->extent); // enforced by the subscription logic
1329-
CANARD_ASSERT(slot->payload.size <= slot->total_payload_size);
1330-
1331-
const bool start = slot->total_payload_size == 0;
1332-
slot->single_frame = start && end;
1333-
slot->total_payload_size += payload.size; // Before truncation.
1334-
1335-
// For simplicity, the case of zero extent is handled separately. It cannot fail.
1336-
// The case of nonzero extent but an empty frame is handled similarly.
1337-
if ((ses->owner->extent == 0) || (payload.size == 0)) {
1338-
return true;
1339-
}
1340-
1341-
// The single-frame non-empty case is also extracted for simplicity.
1342-
if (slot->single_frame) {
1343-
CANARD_ASSERT((payload.size > 0) && (ses->owner->extent > 0) && (slot->payload.data == NULL));
1344-
slot->payload.size = smaller(payload.size, ses->owner->extent);
1345-
slot->payload.data = mem_alloc(ses->owner->owner->mem.rx_payload, slot->payload.size);
1346-
if (slot->payload.data == NULL) {
1347-
return false; // OOM. Must reset the slot.
1348-
}
1349-
(void)memcpy(slot->payload.data, payload.data, slot->payload.size);
1321+
CANARD_ASSERT(slot->payload.size <= slot->total_size);
1322+
CANARD_ASSERT(payload.size > 0); // a multi-frame transfer cannot contain empty frames; enforced externally
1323+
const bool start = slot->total_size == 0;
1324+
slot->total_size += payload.size; // Before truncation.
1325+
if (ses->owner->extent == 0) {
13501326
return true;
13511327
}
1352-
1353-
// The general multi-frame case with non-empty payload.
13541328
if (start) {
1355-
CANARD_ASSERT((payload.size > 0) && (ses->owner->extent > 0) && (slot->payload.data == NULL));
1329+
CANARD_ASSERT((ses->owner->extent > 0) && (slot->payload.data == NULL));
13561330
slot->payload.data = mem_alloc(ses->owner->owner->mem.rx_payload, ses->owner->extent);
13571331
if (NULL == slot->payload.data) {
1358-
return false; // OOM. Must reset the slot.
1332+
return false; // OOM. Must destroy the slot.
13591333
}
13601334
}
13611335
CANARD_ASSERT(slot->payload.data != NULL);
@@ -1379,7 +1353,7 @@ static bool rx_session_update(canard_subscription_t* const sub, const canard_us_
13791353
if (ses == NULL) {
13801354
return false;
13811355
}
1382-
ses->transfer_id++; // TODO stub
1356+
ses->last_admitted_transfer_id++; // TODO stub
13831357
(void)ts;
13841358

13851359
return false;
@@ -1447,7 +1421,7 @@ void canard_poll(canard_t* const self, const uint_least8_t tx_ready_iface_bitmap
14471421
rx_session_t* const ses = LIST_HEAD(self->rx.list_session_by_animation, rx_session_t, list_animation);
14481422
if (ses != NULL) {
14491423
const size_t in_progress_slots = rx_session_scan(ses, now);
1450-
if ((in_progress_slots == 0) && (ses->timestamp < (now - ses->owner->transfer_id_timeout))) {
1424+
if ((in_progress_slots == 0) && (ses->last_admitted_start_ts < (now - ses->owner->transfer_id_timeout))) {
14511425
rx_session_destroy(ses);
14521426
}
14531427
}

0 commit comments

Comments
 (0)