Skip to content

Commit 95dd1e4

Browse files
committed
Implement crc-16-ccitt-false for cyphal header checksum
1 parent 2e30464 commit 95dd1e4

File tree

3 files changed

+52
-0
lines changed

3 files changed

+52
-0
lines changed

libudpard/udpard.c

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,45 @@ UDPARD_PRIVATE TransferCRC crcValue(const TransferCRC crc)
182182
return (uint32_t) (crc ^ CRC_XOR);
183183
}
184184

185+
/// --------------------------------------------- CYPHAL HEADER CRC ---------------------------------------------
186+
187+
typedef uint16_t CyphalHeaderCRC;
188+
189+
// Based on CRC-16-CCITT-FALSE Function
190+
#define CYPHAL_HEADER_CRC_INITIAL 0xFFFFU
191+
#define CYPHAL_HEADER_CRC_SIZE_BYTES 2U
192+
193+
UDPARD_PRIVATE CyphalHeaderCRC CyphalHeaderCrcAddByte(const CyphalHeaderCRC crc, const uint8_t byte)
194+
{
195+
// Based on CRC-16-CCITT-FALSE Function
196+
static const CyphalHeaderCRC Top = 0x8000U;
197+
static const CyphalHeaderCRC Poly = 0x1021U;
198+
CyphalHeaderCRC out = crc ^ (uint16_t) ((uint16_t) (byte) << BITS_PER_BYTE);
199+
// Do not fold this into a loop because a size-optimizing compiler won't unroll it degrading the performance.
200+
out = (uint16_t) ((uint16_t) (out << 1U) ^ (((out & Top) != 0U) ? Poly : 0U));
201+
out = (uint16_t) ((uint16_t) (out << 1U) ^ (((out & Top) != 0U) ? Poly : 0U));
202+
out = (uint16_t) ((uint16_t) (out << 1U) ^ (((out & Top) != 0U) ? Poly : 0U));
203+
out = (uint16_t) ((uint16_t) (out << 1U) ^ (((out & Top) != 0U) ? Poly : 0U));
204+
out = (uint16_t) ((uint16_t) (out << 1U) ^ (((out & Top) != 0U) ? Poly : 0U));
205+
out = (uint16_t) ((uint16_t) (out << 1U) ^ (((out & Top) != 0U) ? Poly : 0U));
206+
out = (uint16_t) ((uint16_t) (out << 1U) ^ (((out & Top) != 0U) ? Poly : 0U));
207+
out = (uint16_t) ((uint16_t) (out << 1U) ^ (((out & Top) != 0U) ? Poly : 0U));
208+
return out;}
209+
210+
UDPARD_PRIVATE CyphalHeaderCRC CyphalHeaderCrcAdd(const CyphalHeaderCRC crc, const void* const header)
211+
{
212+
UDPARD_ASSERT(header != NULL);
213+
CyphalHeaderCRC out = crc;
214+
const uint8_t* p = (const uint8_t*) header;
215+
size_t cyphal_header_size_without_crc = sizeof(UdpardFrameHeader) - CYPHAL_HEADER_CRC_SIZE_BYTES;
216+
for (size_t i = 0; i < cyphal_header_size_without_crc; i++)
217+
{
218+
out = CyphalHeaderCrcAddByte(out, *p);
219+
++p;
220+
}
221+
return out;
222+
}
223+
185224
// --------------------------------------------- TRANSMISSION ---------------------------------------------
186225

187226
/// This is a subclass of UdpardTxQueueItem. A pointer to this type can be cast to UdpardTxQueueItem safely.
@@ -329,6 +368,7 @@ UDPARD_PRIVATE void txMakeFrameHeader(UdpardFrameHeader* const header,
329368
header->frame_index_eot = end_of_transfer_mask | frame_index;
330369
header->source_node_id = src_node_id;
331370
header->destination_node_id = dst_node_id;
371+
header->cyphal_header_checksum = CyphalHeaderCrcAdd(CYPHAL_HEADER_CRC_INITIAL, header);
332372
if (transfer_kind == UdpardTransferKindMessage)
333373
{
334374
header->data_specifier = (uint16_t) UPDARD_DATA_SPECIFIER_MESSAGE & port_id; // SNM (0) + Subject ID

tests/exposed.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ extern "C" {
7979

8080
auto crcAdd(const std::uint32_t crc, const std::size_t size, const void* const bytes) -> std::uint32_t;
8181

82+
auto CyphalHeaderCrcAdd(const std::uint16_t crc, const void* const bytes) -> std::uint16_t;
83+
8284
auto crcValue(const std::uint32_t crc) -> std::uint32_t;
8385

8486
auto txMakeMessageSessionSpecifier(const UdpardPortID subject_id,

tests/test_private_crc.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,13 @@ TEST_CASE("TransferCRC")
2121
crc = crcAdd(crc, 6, "456789");
2222
REQUIRE(0xE3069283U == crcValue(crc));
2323
}
24+
25+
TEST_CASE("CyphalHeaderCRC")
26+
{
27+
using exposed::CyphalHeaderCrcAdd;
28+
29+
std::uint16_t crc = 0xFFFFU;
30+
const uint8_t* header = reinterpret_cast<const uint8_t*>("\x01\x02\x03\x04\x05\x06\x07\x08\x09\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x20\x21\x22\x23\x24");
31+
crc = CyphalHeaderCrcAdd(crc, header);
32+
REQUIRE(0xB731 == crc);
33+
}

0 commit comments

Comments
 (0)