6 #define P1_VMODULE_NAME rtcm_framer
11 #if P1_HAVE_STD_OSTREAM
14 # include <type_traits>
41 0x000000, 0x864CFB, 0x8AD50D, 0x0C99F6, 0x93E6E1, 0x15AA1A, 0x1933EC,
42 0x9F7F17, 0xA18139, 0x27CDC2, 0x2B5434, 0xAD18CF, 0x3267D8, 0xB42B23,
43 0xB8B2D5, 0x3EFE2E, 0xC54E89, 0x430272, 0x4F9B84, 0xC9D77F, 0x56A868,
44 0xD0E493, 0xDC7D65, 0x5A319E, 0x64CFB0, 0xE2834B, 0xEE1ABD, 0x685646,
45 0xF72951, 0x7165AA, 0x7DFC5C, 0xFBB0A7, 0x0CD1E9, 0x8A9D12, 0x8604E4,
46 0x00481F, 0x9F3708, 0x197BF3, 0x15E205, 0x93AEFE, 0xAD50D0, 0x2B1C2B,
47 0x2785DD, 0xA1C926, 0x3EB631, 0xB8FACA, 0xB4633C, 0x322FC7, 0xC99F60,
48 0x4FD39B, 0x434A6D, 0xC50696, 0x5A7981, 0xDC357A, 0xD0AC8C, 0x56E077,
49 0x681E59, 0xEE52A2, 0xE2CB54, 0x6487AF, 0xFBF8B8, 0x7DB443, 0x712DB5,
50 0xF7614E, 0x19A3D2, 0x9FEF29, 0x9376DF, 0x153A24, 0x8A4533, 0x0C09C8,
51 0x00903E, 0x86DCC5, 0xB822EB, 0x3E6E10, 0x32F7E6, 0xB4BB1D, 0x2BC40A,
52 0xAD88F1, 0xA11107, 0x275DFC, 0xDCED5B, 0x5AA1A0, 0x563856, 0xD074AD,
53 0x4F0BBA, 0xC94741, 0xC5DEB7, 0x43924C, 0x7D6C62, 0xFB2099, 0xF7B96F,
54 0x71F594, 0xEE8A83, 0x68C678, 0x645F8E, 0xE21375, 0x15723B, 0x933EC0,
55 0x9FA736, 0x19EBCD, 0x8694DA, 0x00D821, 0x0C41D7, 0x8A0D2C, 0xB4F302,
56 0x32BFF9, 0x3E260F, 0xB86AF4, 0x2715E3, 0xA15918, 0xADC0EE, 0x2B8C15,
57 0xD03CB2, 0x567049, 0x5AE9BF, 0xDCA544, 0x43DA53, 0xC596A8, 0xC90F5E,
58 0x4F43A5, 0x71BD8B, 0xF7F170, 0xFB6886, 0x7D247D, 0xE25B6A, 0x641791,
59 0x688E67, 0xEEC29C, 0x3347A4, 0xB50B5F, 0xB992A9, 0x3FDE52, 0xA0A145,
60 0x26EDBE, 0x2A7448, 0xAC38B3, 0x92C69D, 0x148A66, 0x181390, 0x9E5F6B,
61 0x01207C, 0x876C87, 0x8BF571, 0x0DB98A, 0xF6092D, 0x7045D6, 0x7CDC20,
62 0xFA90DB, 0x65EFCC, 0xE3A337, 0xEF3AC1, 0x69763A, 0x578814, 0xD1C4EF,
63 0xDD5D19, 0x5B11E2, 0xC46EF5, 0x42220E, 0x4EBBF8, 0xC8F703, 0x3F964D,
64 0xB9DAB6, 0xB54340, 0x330FBB, 0xAC70AC, 0x2A3C57, 0x26A5A1, 0xA0E95A,
65 0x9E1774, 0x185B8F, 0x14C279, 0x928E82, 0x0DF195, 0x8BBD6E, 0x872498,
66 0x016863, 0xFAD8C4, 0x7C943F, 0x700DC9, 0xF64132, 0x693E25, 0xEF72DE,
67 0xE3EB28, 0x65A7D3, 0x5B59FD, 0xDD1506, 0xD18CF0, 0x57C00B, 0xC8BF1C,
68 0x4EF3E7, 0x426A11, 0xC426EA, 0x2AE476, 0xACA88D, 0xA0317B, 0x267D80,
69 0xB90297, 0x3F4E6C, 0x33D79A, 0xB59B61, 0x8B654F, 0x0D29B4, 0x01B042,
70 0x87FCB9, 0x1883AE, 0x9ECF55, 0x9256A3, 0x141A58, 0xEFAAFF, 0x69E604,
71 0x657FF2, 0xE33309, 0x7C4C1E, 0xFA00E5, 0xF69913, 0x70D5E8, 0x4E2BC6,
72 0xC8673D, 0xC4FECB, 0x42B230, 0xDDCD27, 0x5B81DC, 0x57182A, 0xD154D1,
73 0x26359F, 0xA07964, 0xACE092, 0x2AAC69, 0xB5D37E, 0x339F85, 0x3F0673,
74 0xB94A88, 0x87B4A6, 0x01F85D, 0x0D61AB, 0x8B2D50, 0x145247, 0x921EBC,
75 0x9E874A, 0x18CBB1, 0xE37B16, 0x6537ED, 0x69AE1B, 0xEFE2E0, 0x709DF7,
76 0xF6D10C, 0xFA48FA, 0x7C0401, 0x42FA2F, 0xC4B6D4, 0xC82F22, 0x4E63D9,
77 0xD11CCE, 0x575035, 0x5BC9C3, 0xDD8538};
80 static uint32_t
CRC24Hash(
const uint8_t* data,
size_t len) {
84 for (i = 0; i < len; i++) {
85 crc = (crc << 8) ^
RTCM_CRC24Q[data[i] ^ (
unsigned char)(crc >> 16)];
88 crc = (crc & 0x00ffffff);
96 return (num_ptr[0] << 8) | (num_ptr[1] << 0);
101 return (num_ptr[0] << 16) | (num_ptr[1] << 8) | (num_ptr[2] << 0);
105 template <
typename T>
110 template <
typename U>
118 template <
typename T>
121 #if P1_HAVE_STD_OSTREAM
122 static_assert(std::is_integral<T>::value,
"Integer required.");
124 stream <<
"0x" << std::hex << std::setfill(
'0') << std::setw(
sizeof(obj) * 2);
126 if (
sizeof(T) == 1) {
127 stream << (((unsigned)obj.
value_) & 0xFF);
134 if (
sizeof(obj) == 1) {
136 stream <<
" ('" << (char)obj.
value_ <<
"')";
170 template <
typename T>
178 if (buffer ==
nullptr) {
195 LOG(ERROR) <<
"RTCM framing buffer too small. [capacity=" << capacity_bytes
204 else if (capacity_bytes > 0x7FFFFFFF) {
205 LOG(WARNING) <<
"Limiting buffer capacity to 2^31 B. [original_capacity="
206 << capacity_bytes <<
" B]";
207 capacity_bytes = 0x7FFFFFFF;
211 if (buffer ==
nullptr) {
212 buffer =
new uint8_t[capacity_bytes];
217 uint8_t* buffer_unaligned =
static_cast<uint8_t*
>(buffer);
218 buffer_ =
reinterpret_cast<uint8_t*
>(
219 (
reinterpret_cast<size_t>(buffer_unaligned) + 3) &
220 ~(
static_cast<size_t>(3)));
222 static_cast<uint32_t
>(capacity_bytes - (
buffer_ - buffer_unaligned));
241 VLOG(2) <<
"Received " << length_bytes <<
" bytes.";
242 size_t total_dispatched_bytes = 0;
243 for (
size_t idx = 0; idx < length_bytes; ++idx) {
244 uint8_t
byte = buffer[idx];
246 int32_t dispatched_message_size =
OnByte(
false);
247 if (dispatched_message_size == 0) {
249 }
else if (dispatched_message_size > 0) {
252 total_dispatched_bytes += (size_t)dispatched_message_size;
264 total_dispatched_bytes +=
Resync();
270 return total_dispatched_bytes;
290 LOG(ERROR) <<
"Byte not found in buffer.";
301 bool crc_check_needed =
false;
306 VLOG(4) <<
"Found sync byte 0.";
338 uint16_t payload_size_bytes = header_byte_1_2_le & 0x3FF;
340 VLOG(3) <<
"Header complete. Waiting for payload. [payload_size="
341 << payload_size_bytes <<
" B]";
348 VLOG(2) <<
"Message too large for buffer. [size="
350 <<
" B (payload=" << payload_size_bytes
355 LOG(WARNING) <<
"Message too large for buffer. [size="
357 <<
" B (payload=" << payload_size_bytes
359 <<
" B (max_payload="
377 VLOG(3) <<
"Payload complete. Checking CRC.";
378 crc_check_needed =
true;
383 LOG(ERROR) <<
"Impossible parsing state.";
389 if (crc_check_needed) {
392 uint16_t message_type = header_byte_3_4_le >> 4;
395 if (calculated_crc == crc_expected) {
397 VLOG(1) <<
"CRC passed. Dispatching message. [message=" << message_type
408 VLOG(2) <<
"CRC check failed. [message=" << message_type
414 LOG(WARNING) <<
"CRC check failed. [message=" << message_type
455 VLOG(1) <<
"Attempting resynchronization. [" << available_bytes - 1
456 <<
" candidate bytes]";
457 uint32_t total_message_size = 0;
460 for (uint32_t offset = 1; offset < available_bytes; ++offset) {
461 uint8_t current_byte =
buffer_[offset];
466 VLOG(1) <<
"Candidate message start found @ offset " << offset <<
"/"
467 << available_bytes <<
".";
469 available_bytes -= offset;
473 VLOG(4) <<
"Skipping non-sync byte 0 @ offset " << offset <<
"/"
493 int32_t message_size =
OnByte(
true);
498 if (message_size > 0) {
499 total_message_size += message_size;
500 offset = message_size - 1;
502 <<
"Resync found a complete message. Continuing search @ offset "
503 << offset + 1 <<
"/" << available_bytes
504 <<
". [message_size=" << message_size <<
", "
505 << (available_bytes - message_size - 1)
506 <<
" candidate bytes remaining]";
508 size_t prev_offset = offset;
510 VLOG(1) <<
"Candidate message rejected after " << prev_offset
511 <<
" bytes. Restarting search @ offset " << offset + 1 <<
"/"
512 << available_bytes <<
". [" << available_bytes - 1
513 <<
" candidate bytes remaining]";
521 <<
" bytes remaining in buffer.";
523 return total_message_size;