COMMS
Template library intended to help with implementation of communication protocols.
Loading...
Searching...
No Matches
Crc.h
Go to the documentation of this file.
1//
2// Copyright 2017 - 2025 (C). Alex Robenko. All rights reserved.
3//
4// This Source Code Form is subject to the terms of the Mozilla Public
5// License, v. 2.0. If a copy of the MPL was not distributed with this
6// file, You can obtain one at http://mozilla.org/MPL/2.0/.
7
10
11#pragma once
12
13#include "comms/cast.h"
14#include "comms/details/tag.h"
16
17#include <array>
18#include <cstdint>
19#include <limits>
20#include <type_traits>
21
22
23namespace comms
24{
25
26namespace frame
27{
28
29namespace checksum
30{
31
32namespace details
33{
34
35template <typename TResult>
36using CrcInitTableType = std::array<TResult, 256>;
37
38template <typename TResult, TResult TPoly>
39struct CrcInitTable
40{
41 using Table = CrcInitTableType<TResult>;
42 static const Table& get()
43 {
44 static Table table;
45 static bool tableFilled = false;
46
47 if (!tableFilled) {
48 fillTable(table);
49 tableFilled = true;
50 }
51
52 return table;
53 }
54
55private:
56 static void fillTable(Table& table)
57 {
58 static const std::size_t Width =
59 sizeof(TResult) * std::numeric_limits<std::uint8_t>::digits;
60 static const auto Msb =
61 static_cast<TResult>(1) << (Width - 1);
62
63 for (unsigned idx = 0U; idx < table.size(); ++idx)
64 {
65 auto rem = static_cast<TResult>(idx << (Width - 8));
66
67 for (auto bit = 8U; bit > 0U; --bit)
68 {
69 if ((rem & Msb) != 0)
70 {
71 rem = (rem << 1) ^ TPoly;
72 }
73 else
74 {
75 rem = (rem << 1);
76 }
77 }
78
79 table[idx] = rem;
80 }
81 }
82};
83
84template <>
85struct CrcInitTable<std::uint16_t, 0x1021>
86{
87 using Table = CrcInitTableType<std::uint16_t>;
88 static const Table& get()
89 {
90 static const Table table = {{
91 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
92 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
93 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
94 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
95 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
96 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
97 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
98 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
99 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
100 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
101 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
102 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
103 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
104 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
105 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
106 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
107 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
108 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
109 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
110 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
111 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
112 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
113 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
114 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
115 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
116 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
117 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
118 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
119 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
120 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
121 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
122 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
123 }};
124 return table;
125 }
126};
127
128template <>
129struct CrcInitTable<std::uint16_t, 0x8005>
130{
131 using Table = CrcInitTableType<std::uint16_t>;
132 static const Table& get()
133 {
134 static const Table table = {{
135 0x0000, 0x8005, 0x800f, 0x000a, 0x801b, 0x001e, 0x0014, 0x8011,
136 0x8033, 0x0036, 0x003c, 0x8039, 0x0028, 0x802d, 0x8027, 0x0022,
137 0x8063, 0x0066, 0x006c, 0x8069, 0x0078, 0x807d, 0x8077, 0x0072,
138 0x0050, 0x8055, 0x805f, 0x005a, 0x804b, 0x004e, 0x0044, 0x8041,
139 0x80c3, 0x00c6, 0x00cc, 0x80c9, 0x00d8, 0x80dd, 0x80d7, 0x00d2,
140 0x00f0, 0x80f5, 0x80ff, 0x00fa, 0x80eb, 0x00ee, 0x00e4, 0x80e1,
141 0x00a0, 0x80a5, 0x80af, 0x00aa, 0x80bb, 0x00be, 0x00b4, 0x80b1,
142 0x8093, 0x0096, 0x009c, 0x8099, 0x0088, 0x808d, 0x8087, 0x0082,
143 0x8183, 0x0186, 0x018c, 0x8189, 0x0198, 0x819d, 0x8197, 0x0192,
144 0x01b0, 0x81b5, 0x81bf, 0x01ba, 0x81ab, 0x01ae, 0x01a4, 0x81a1,
145 0x01e0, 0x81e5, 0x81ef, 0x01ea, 0x81fb, 0x01fe, 0x01f4, 0x81f1,
146 0x81d3, 0x01d6, 0x01dc, 0x81d9, 0x01c8, 0x81cd, 0x81c7, 0x01c2,
147 0x0140, 0x8145, 0x814f, 0x014a, 0x815b, 0x015e, 0x0154, 0x8151,
148 0x8173, 0x0176, 0x017c, 0x8179, 0x0168, 0x816d, 0x8167, 0x0162,
149 0x8123, 0x0126, 0x012c, 0x8129, 0x0138, 0x813d, 0x8137, 0x0132,
150 0x0110, 0x8115, 0x811f, 0x011a, 0x810b, 0x010e, 0x0104, 0x8101,
151 0x8303, 0x0306, 0x030c, 0x8309, 0x0318, 0x831d, 0x8317, 0x0312,
152 0x0330, 0x8335, 0x833f, 0x033a, 0x832b, 0x032e, 0x0324, 0x8321,
153 0x0360, 0x8365, 0x836f, 0x036a, 0x837b, 0x037e, 0x0374, 0x8371,
154 0x8353, 0x0356, 0x035c, 0x8359, 0x0348, 0x834d, 0x8347, 0x0342,
155 0x03c0, 0x83c5, 0x83cf, 0x03ca, 0x83db, 0x03de, 0x03d4, 0x83d1,
156 0x83f3, 0x03f6, 0x03fc, 0x83f9, 0x03e8, 0x83ed, 0x83e7, 0x03e2,
157 0x83a3, 0x03a6, 0x03ac, 0x83a9, 0x03b8, 0x83bd, 0x83b7, 0x03b2,
158 0x0390, 0x8395, 0x839f, 0x039a, 0x838b, 0x038e, 0x0384, 0x8381,
159 0x0280, 0x8285, 0x828f, 0x028a, 0x829b, 0x029e, 0x0294, 0x8291,
160 0x82b3, 0x02b6, 0x02bc, 0x82b9, 0x02a8, 0x82ad, 0x82a7, 0x02a2,
161 0x82e3, 0x02e6, 0x02ec, 0x82e9, 0x02f8, 0x82fd, 0x82f7, 0x02f2,
162 0x02d0, 0x82d5, 0x82df, 0x02da, 0x82cb, 0x02ce, 0x02c4, 0x82c1,
163 0x8243, 0x0246, 0x024c, 0x8249, 0x0258, 0x825d, 0x8257, 0x0252,
164 0x0270, 0x8275, 0x827f, 0x027a, 0x826b, 0x026e, 0x0264, 0x8261,
165 0x0220, 0x8225, 0x822f, 0x022a, 0x823b, 0x023e, 0x0234, 0x8231,
166 0x8213, 0x0216, 0x021c, 0x8219, 0x0208, 0x820d, 0x8207, 0x0202
167 }};
168 return table;
169 }
170};
171
172template <>
173struct CrcInitTable<std::uint32_t, 0x04c11db7>
174{
175 using Table = CrcInitTableType<std::uint32_t>;
176 static const Table& get()
177 {
178 static const Table table = {{
179 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9,
180 0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005,
181 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
182 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
183 0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9,
184 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
185 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011,
186 0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd,
187 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
188 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5,
189 0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81,
190 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
191 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49,
192 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
193 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
194 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d,
195 0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae,
196 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
197 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,
198 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca,
199 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
200 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02,
201 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066,
202 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
203 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e,
204 0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692,
205 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
206 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a,
207 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,
208 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
209 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686,
210 0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a,
211 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
212 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
213 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f,
214 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
215 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47,
216 0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b,
217 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
218 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623,
219 0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7,
220 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
221 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f,
222 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
223 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
224 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b,
225 0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f,
226 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
227 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
228 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c,
229 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
230 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24,
231 0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30,
232 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
233 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088,
234 0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654,
235 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
236 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c,
237 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,
238 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
239 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0,
240 0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c,
241 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
242 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
243 }};
244 return table;
245 }
246};
247
248} // namespace details
249
261template <
262 typename TResult,
263 TResult TPoly,
264 TResult TInit = 0,
265 TResult TFin = 0,
266 bool TReflect = false,
267 bool TReflectRem = false
268>
269class Crc
270{
271 static_assert(std::is_unsigned<TResult>::value,
272 "The TResult type is expected to be unsigned integral one");
273public:
279 template <typename TIter>
280 TResult operator()(TIter& iter, std::size_t len) const
281 {
282 static const std::size_t Width =
283 sizeof(TResult) * std::numeric_limits<std::uint8_t>::digits;
284
285 TResult rem = TInit;
286 auto& initTable = details::CrcInitTable<TResult, TPoly>::get();
287
288 for (std::size_t byte = 0U; byte < len; ++byte)
289 {
290 using ByteType = typename std::make_unsigned<
291 typename std::decay<decltype(*iter)>::type
292 >::type;
293
294 auto val = static_cast<std::uint8_t>(static_cast<ByteType>(*iter));
295 comms::cast_assign(val) = reflect(val) ^ static_cast<decltype(val)>(rem >> (Width - 8));
296 comms::cast_assign(rem) = initTable[val] ^ static_cast<decltype(rem)>(rem << 8);
297 ++iter;
298 }
299
300 return (reflectRem(rem) ^ TFin);
301 }
302
303private:
304 template <typename... TParams>
305 using NoReflectTag = comms::details::tag::Tag1<>;
306
307 template <typename... TParams>
308 using DoReflectTag = comms::details::tag::Tag2<>;
309
310 template <typename...>
311 using ReflectTag =
312 typename comms::util::LazyShallowConditional<
313 TReflect
314 >::template Type<
315 DoReflectTag,
316 NoReflectTag
317 >;
318
319 template <typename...>
320 using ReflectRemTag =
321 typename comms::util::LazyShallowConditional<
322 TReflectRem
323 >::template Type<
324 DoReflectTag,
325 NoReflectTag
326 >;
327
328 static std::uint8_t reflect(std::uint8_t byte)
329 {
330 return reflectInternal(byte, 8U, ReflectTag<>());
331 }
332
333 static TResult reflectRem(TResult value)
334 {
335 static const std::size_t Width =
336 sizeof(TResult) * std::numeric_limits<std::uint8_t>::digits;
337
338 return reflectInternal(value, Width, ReflectRemTag<>());
339 }
340
341 template <typename TVal, typename... TParams>
342 static TVal reflectInternal(TVal value, std::size_t bitsCount, DoReflectTag<TParams...>)
343 {
344 return static_cast<TVal>(doReflect(value, bitsCount));
345 }
346
347 template <typename TVal, typename... TParams>
348 static constexpr TVal reflectInternal(TVal value, std::size_t, NoReflectTag<TParams...>)
349 {
350 return value;
351 }
352
353 static TResult doReflect(TResult value, std::size_t bitsCount)
354 {
355 TResult reflection = 0U;
356 for (auto bit = 0U; bit < bitsCount; ++bit)
357 {
358 if (value & 0x01)
359 {
360 comms::cast_assign(reflection) =
361 reflection |
362 static_cast<decltype(reflection)>(1 << ((bitsCount - 1) - bit));
363 }
364
365 value = static_cast<decltype(value)>(value >> 1);
366 }
367
368 return (reflection);
369 }
370
371};
372
382
392
402
403} // namespace checksum
404
405} // namespace frame
406
407} // namespace comms
408
409
410
Contains definition of various casts.
Calculate CRC values of all the bytes in the sequence.
Definition Crc.h:270
TResult operator()(TIter &iter, std::size_t len) const
Operator that is invoked to calculate the checksum value.
Definition Crc.h:280
Main namespace for all classes / functions of COMMS library.
details::ValueAssignWrapper< T > cast_assign(T &value)
Helper function to assign value with static_cast to appropriate type.
Definition cast.h:29
STL namespace.
Replacement to some types from standard type_traits.