Skip to content

Commit e41441c

Browse files
committed
rx: update session state machine
1 parent 5e1778a commit e41441c

File tree

1 file changed

+35
-30
lines changed

1 file changed

+35
-30
lines changed

libserard/serard.c

Lines changed: 35 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@
8181
#define FRAME_INDEX 0U
8282
#define END_OF_TRANSFER (1U << 31U)
8383

84+
#define TRANSFER_ID_DELTA 1000000U
85+
8486
// --------------------------------------------- HEADER CRC ---------------------------------------------
8587

8688
typedef 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

688693
SERARD_PRIVATE int8_t rxAcceptByte(struct SerardRx* const ins,

0 commit comments

Comments
 (0)