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