@@ -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.
11931192typedef 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 ;
12031202static_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 ;
12281226static_assert ((sizeof (void * ) > 4 ) || (sizeof (rx_session_t ) <= 120 ), "too large" );
12291227
12301228static 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
12461246static 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.
12961296static 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