@@ -1052,20 +1052,118 @@ bool canard_0v1_respond(canard_t* const self,
10521052
10531053// --------------------------------------------- RX ---------------------------------------------
10541054
1055- /*
10561055typedef 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
0 commit comments