8181#define FRAME_INDEX 0U
8282#define END_OF_TRANSFER (1U << 31U)
8383
84+ #define TRANSFER_ID_DELTA 1000000U
85+
8486// --------------------------------------------- HEADER CRC ---------------------------------------------
8587
8688typedef uint16_t HeaderCRC ;
@@ -196,6 +198,8 @@ SERARD_PRIVATE TransferCRC transferCRCAdd(const uint32_t crc, const size_t size,
196198
197199/// The memory requirement model provided in the documentation assumes that the maximum size of this structure never
198200/// exceeds 56 bytes on any conventional platform.
201+ /// FIXME: not true anymore
202+ ///
199203/// A user that needs a detailed analysis of the worst-case memory consumption may compute the size of this structure
200204/// for the particular platform at hand manually or by evaluating its sizeof().
201205/// The fields are ordered to minimize the amount of padding on all conventional platforms.
@@ -206,7 +210,6 @@ struct SerardInternalRxSession
206210 SerardMicrosecond transfer_timestamp_usec ; ///< Used to validate transfer delay against restart timeout.
207211 SerardTransferID transfer_id ; ///< Used to deduplicate transfers on redundant or unreliable networks.
208212 SerardNodeID source_node_id ; ///< Sessions are maintained per unique remote node (ID).
209- uint8_t redundant_iface_index ; ///< Arbitrary value in [0, 255].
210213};
211214
212215// --------------------------------------------- COBS ---------------------------------------------
@@ -588,10 +591,9 @@ SERARD_PRIVATE int8_t rxValidateHeader(struct SerardRx* const ins,
588591/// are given and the particular algorithms are left to be implementation-defined. Such abstract approach is much
589592/// advantageous because it allows implementers to choose whatever solution works best for the specific application at
590593/// hand, while the wire compatibility is still guaranteed by the high-level requirements given in the specification.
591- SERARD_PRIVATE void rxSessionUpdate (struct SerardRx * const ins ,
594+ SERARD_PRIVATE bool rxSessionUpdate (struct SerardRx * const ins ,
592595 struct SerardInternalRxSession * const rxs ,
593596 const struct SerardRxTransfer * const transfer ,
594- const uint8_t redundant_iface_index ,
595597 const SerardMicrosecond transfer_id_timeout_usec )
596598{
597599 SERARD_ASSERT (ins != NULL );
@@ -600,19 +602,23 @@ SERARD_PRIVATE void rxSessionUpdate(struct SerardRx* const ins,
600602
601603 const struct SerardTransferMetadata * metadata = & transfer -> metadata ;
602604
605+ // Accept the transfer if the new transfer ID is greater than the previous.
606+ const bool tid_future = metadata -> transfer_id > rxs -> transfer_id ;
607+
608+ // Accept (and restart the session) on transfer ID timeout.
603609 const bool tid_timed_out = (transfer -> timestamp_usec > rxs -> transfer_timestamp_usec ) &&
604610 ((transfer -> timestamp_usec - rxs -> transfer_timestamp_usec ) > transfer_id_timeout_usec );
605611
606- // The monotonic 64 bit transfer ID in UAVCAN/Serial shall not wrap.
607- const bool not_monotonic = (metadata -> transfer_id - rxs -> transfer_id ) > 1 ;
608-
609- const bool need_restart = tid_timed_out || ((rxs -> redundant_iface_index == redundant_iface_index ) && not_monotonic );
612+ // Accept if the transfer ID is at least TRANSFER_ID_DELTA counts less than
613+ // the previous one. This is used to hot-start the rx pipeline after a reboot.
614+ const bool wrap = !tid_future && ((rxs -> transfer_id - metadata -> transfer_id ) >= TRANSFER_ID_DELTA );
610615
611- if (need_restart )
616+ if (tid_timed_out )
612617 {
613- rxs -> transfer_id = metadata -> transfer_id ;
614- rxs -> redundant_iface_index = redundant_iface_index ;
618+ rxs -> transfer_id = metadata -> transfer_id ;
615619 }
620+
621+ return tid_future || tid_timed_out || wrap ;
616622}
617623
618624// TODO: test this
@@ -633,15 +639,12 @@ SERARD_PRIVATE int8_t rxAcceptTransfer(struct SerardRx* const ins,
633639 TransferCRC payload_crc = TRANSFER_CRC_INITIAL ;
634640 payload_crc = transferCRCAdd (payload_crc , payload_size , transfer -> payload );
635641 payload_crc = payload_crc ^ TRANSFER_CRC_OUTPUT_XOR ;
636- const bool valid = payload_crc == TRANSFER_CRC_RESIDUE_AFTER_OUTPUT_XOR ;
637-
638- if (!valid )
639- {
640- return 0 ;
641- }
642+ bool valid = payload_crc == TRANSFER_CRC_RESIDUE_AFTER_OUTPUT_XOR ;
642643
644+ // The CRC is counted in the bytes received but not in the user payload.
643645 transfer -> payload_size = payload_size - TRANSFER_CRC_SIZE_BYTES ;
644646
647+ int8_t ret = 0 ;
645648 if (metadata -> remote_node_id <= SERARD_NODE_ID_MAX )
646649 {
647650 struct SerardInternalRxSession * rxs =
@@ -651,38 +654,40 @@ SERARD_PRIVATE int8_t rxAcceptTransfer(struct SerardRx* const ins,
651654
652655 if (rxs == NULL )
653656 {
654- rxs = (struct SerardInternalRxSession * ) ins -> memory_rx_session
655- .allocate (ins -> memory_rx_session .user_reference , sizeof (struct SerardInternalRxSession ));
656-
657+ rxs = ins -> memory_rx_session .allocate (ins -> memory_rx_session .user_reference ,
658+ sizeof (struct SerardInternalRxSession ));
657659 if (rxs != NULL )
658660 {
659661 rxs -> transfer_timestamp_usec = transfer -> timestamp_usec ;
660662 rxs -> source_node_id = metadata -> remote_node_id ;
661663 rxs -> transfer_id = metadata -> transfer_id ;
662- rxs -> redundant_iface_index = redundant_iface_index ;
663-
664- SERARD_UNUSED (cavl2_find ((struct SerardTreeNode * ) subscription -> sessions ,
665- (void * ) & metadata -> remote_node_id ,
666- & rxSubscriptionPredicateOnSession ));
667- rxSessionUpdate (ins , rxs , transfer , redundant_iface_index , subscription -> transfer_id_timeout_usec );
668-
669- return 1 ;
664+ struct SerardTreeNode * node = cavl2_find_or_insert ((struct SerardTreeNode * * ) & subscription -> sessions ,
665+ (void * ) & metadata -> remote_node_id ,
666+ & rxSubscriptionPredicateOnSession ,
667+ rxs ,
668+ & cavl2_trivial_factory );
669+ ret = 1 ;
670670 }
671671 else
672672 {
673- return - SERARD_ERROR_MEMORY ;
673+ ret = - SERARD_ERROR_MEMORY ;
674674 }
675675 }
676+ else
677+ {
678+ valid = valid && rxSessionUpdate (ins , rxs , transfer , subscription -> transfer_id_timeout_usec );
679+ ret = valid ? 1 : 0 ;
680+ }
676681 }
677682 else
678683 {
679684 SERARD_ASSERT (metadata -> remote_node_id == SERARD_NODE_ID_UNSET );
680685 // Anonymous transfers are stateless. No need to update the state machine,
681686 // just blindly accept it.
682- return 1 ;
687+ ret = 1 ;
683688 }
684689
685- return 1 ;
690+ return ret ;
686691}
687692
688693SERARD_PRIVATE int8_t rxAcceptByte (struct SerardRx * const ins ,
0 commit comments