Skip to content

Commit b790e6f

Browse files
rx_parse
1 parent ced4076 commit b790e6f

File tree

2 files changed

+109
-11
lines changed

2 files changed

+109
-11
lines changed

libcanard/canard.c

Lines changed: 107 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1052,20 +1052,118 @@ bool canard_0v1_respond(canard_t* const self,
10521052

10531053
// --------------------------------------------- RX ---------------------------------------------
10541054

1055-
/*
10561055
typedef struct
10571056
{
10581057
canard_prio_t priority;
10591058
format_t format;
1060-
uint32_t port_id;
1061-
uint_least8_t dst;
1062-
uint_least8_t src;
1063-
uint_least8_t transfer_id;
1064-
bool start;
1065-
bool end;
1066-
bool toggle;
1059+
1060+
uint32_t port_id; // in v0 this stores the data type ID.
1061+
1062+
byte_t dst;
1063+
byte_t src;
1064+
1065+
byte_t transfer_id;
1066+
1067+
bool start;
1068+
bool end;
1069+
bool toggle;
1070+
1071+
canard_bytes_t payload;
10671072
} frame_t;
1068-
*/
1073+
1074+
// The protocol version is only unambiguously detectable in the first frame of a transfer.
1075+
// In non-first frames, we attempt to parse the frame as both versions simultaneously and then let the caller
1076+
// decide which one is correct by checking for incomplete multi-frame reassembly states.
1077+
// The return value is a bitmask indicating which of the versions have been parsed at this level.
1078+
static byte_t rx_parse(const uint32_t can_id,
1079+
const canard_bytes_t payload,
1080+
frame_t* const out_v0,
1081+
frame_t* const out_v1)
1082+
{
1083+
CANARD_ASSERT(can_id < (UINT32_C(1) << 29U));
1084+
CANARD_ASSERT(out_v0 != NULL);
1085+
CANARD_ASSERT(out_v1 != NULL);
1086+
if (payload.size < 1) {
1087+
return 0;
1088+
}
1089+
CANARD_ASSERT(payload.data != NULL);
1090+
memset(out_v0, 0, sizeof(*out_v0));
1091+
memset(out_v1, 0, sizeof(*out_v1));
1092+
1093+
// Common items.
1094+
const canard_prio_t priority = (canard_prio_t)(can_id >> PRIO_SHIFT);
1095+
const byte_t src = (byte_t)(can_id & CANARD_NODE_ID_MAX);
1096+
1097+
// Parse the tail byte.
1098+
const byte_t tail = ((const byte_t*)payload.data)[payload.size - 1U];
1099+
const bool start = (tail & TAIL_SOT) != 0U;
1100+
const bool end = (tail & TAIL_EOT) != 0U;
1101+
const bool toggle = (tail & TAIL_TOGGLE) != 0U;
1102+
const byte_t transfer_id = tail & CANARD_TRANSFER_ID_MAX;
1103+
1104+
// Version detection: v1 requires the toggle to start from 1, v0 starts from 0.
1105+
// If this is not the first frame of a transfer, the version is not detectable, so we attempt to parse both.
1106+
bool is_v1 = !(start && !toggle);
1107+
bool is_v0 = !(start && toggle);
1108+
if (is_v1) {
1109+
out_v1->priority = priority;
1110+
out_v1->src = src;
1111+
out_v1->transfer_id = transfer_id;
1112+
out_v1->start = start;
1113+
out_v1->end = end;
1114+
out_v1->toggle = toggle;
1115+
out_v1->payload = (canard_bytes_t){ .size = payload.size - 1U, .data = payload.data };
1116+
const bool svc = (can_id & (UINT32_C(1) << 25U)) != 0U;
1117+
const bool bit_23 = (can_id & (UINT32_C(1) << 23U)) != 0U;
1118+
if (svc) {
1119+
is_v1 = is_v1 && !bit_23;
1120+
out_v1->dst = (byte_t)((can_id >> 7U) & CANARD_NODE_ID_MAX);
1121+
out_v1->port_id = (can_id >> 14U) & CANARD_SERVICE_ID_MAX;
1122+
const bool req = (can_id & (UINT32_C(1) << 24U)) != 0U;
1123+
out_v1->format = req ? format_1v0_request : format_1v0_response;
1124+
} else {
1125+
out_v1->dst = CANARD_NODE_ID_ANONYMOUS;
1126+
const bool is_1v1 = (can_id & (UINT32_C(1) << 7U)) != 0U;
1127+
if (is_1v1) {
1128+
out_v1->port_id = (can_id >> 8U) & CANARD_SUBJECT_ID_MAX;
1129+
out_v1->format = format_1v1_message;
1130+
} else {
1131+
is_v1 = is_v1 && !bit_23;
1132+
out_v1->port_id = (can_id >> 8U) & CANARD_SUBJECT_ID_MAX_1v0;
1133+
out_v1->format = format_1v0_message;
1134+
if ((can_id & (UINT32_C(1) << 24U)) != 0U) {
1135+
out_v1->src = CANARD_NODE_ID_ANONYMOUS;
1136+
}
1137+
}
1138+
}
1139+
}
1140+
if (is_v0) {
1141+
out_v0->priority = priority;
1142+
out_v0->src = src;
1143+
out_v0->transfer_id = transfer_id;
1144+
out_v0->start = start;
1145+
out_v0->end = end;
1146+
out_v0->toggle = toggle;
1147+
out_v0->payload = (canard_bytes_t){ .size = payload.size - 1U, .data = payload.data };
1148+
const bool svc = (can_id & (UINT32_C(1) << 7U)) != 0U;
1149+
if (svc) {
1150+
const byte_t dst = (byte_t)((can_id >> 8U) & CANARD_NODE_ID_MAX);
1151+
is_v0 = (dst != 0) && (src != 0); // 0 is reserved in v0 for anonymous/broadcast, not for svc.
1152+
out_v0->dst = dst;
1153+
out_v0->port_id = (can_id >> 16U) & 0xFFU;
1154+
const bool req = (can_id & (UINT32_C(1) << 15U)) != 0U;
1155+
out_v0->format = req ? format_0v1_request : format_0v1_response;
1156+
} else {
1157+
out_v0->dst = CANARD_NODE_ID_ANONYMOUS;
1158+
out_v0->port_id = (can_id >> 8U) & 0xFFFFU;
1159+
out_v0->format = format_0v1_message;
1160+
if (src == 0) {
1161+
out_v0->src = CANARD_NODE_ID_ANONYMOUS;
1162+
}
1163+
}
1164+
}
1165+
return (is_v0 ? 1U : 0U) | (is_v1 ? 2U : 0U);
1166+
}
10691167

10701168
// TODO rx impl
10711169

libcanard/canard.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -396,8 +396,8 @@ bool canard_ingest_frame(canard_t* const self,
396396
void canard_refcount_inc(const canard_bytes_t obj);
397397
void canard_refcount_dec(canard_t* const self, const canard_bytes_t obj);
398398

399-
/// Message ordering observed on the bus is guaranteed per topic as long as the priority of later messages is not higher
400-
/// (numerically not lower) than that of earlier messages.
399+
/// Message ordering observed on the bus is guaranteed per subject as long as the priority of later messages is
400+
/// not higher (numerically not lower) than that of earlier messages.
401401
bool canard_publish(canard_t* const self,
402402
const canard_us_t deadline,
403403
const uint_least8_t iface_bitmap,

0 commit comments

Comments
 (0)