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