crc.c
10.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
/***********************************************************************CMOD**
* NAME: crc.c
*
* PURPOSE: Provides functions for calculating Cyclic Redundancy Checks
* (CRCs).
*
*****************************************************************************/
#define CRC_DEFINE_VARS
#include "crc.h"
/***********************************************************************INFN**
* NAME: crc_reflect
*
* PURPOSE: Reverses the bit order of a CRC value, if is_rev is CRC_TRUE
*
* PARAMS: crc Address of the value to reverse
* width Width (in bits) of the value
* is_rev Set to TRUE to reverse the bit order; FALSE is
* no operation
*
* RETURNS: None
*
* OPERATION: Loop through each bit, shifting new value left, moving LSB of
* old value to LSB of new value, shifting old value right.
*
*****************************************************************************/
void crc_reflect(CRC_VAL *crc, int width, int is_rev)
{
CRC_VAL rev = 0;
int ii;
if (is_rev)
{
for (ii = 1; ii <= width; ii++)
{
rev <<= 1;
rev |= ((*crc) & 1L);
(*crc) >>= 1;
}
(*crc) = rev;
}
}
/***********************************************************************EXFN**
* NAME: crc_mk_std_tbl
*
* PURPOSE: Initialises a CRC_TBL structure to make it calculate a
* standard type of crc
*
* PARAMS: tbl Address of the structure to initialise
* std_type The type of CRC, one of the following constants:
* CRC_STD_CRC16, CRC_STD_CRC32, CRC_STD_JAM,
* CRC_STD_XMODEM, CRC_STD_ZMODEM
*
* RETURNS: TRUE Structure successfully initialised
* FALSE Error
*
* OPERATION: Calls crc_mk_tbl with hard coded values based on std_type
*
*****************************************************************************/
CRC_BOOL crc_mk_std_tbl(CRC_TBL *tbl, int std_type)
{
CRC_BOOL rc;
switch (std_type)
{
case CRC_STD_CRC16:
rc = crc_mk_tbl(tbl, 16, 0x1021, 0xFFFF, 0x0000, CRC_FALSE);
break;
case CRC_DNP_CRC16:
rc = crc_mk_tbl(tbl, 16, 0x13D65, 0x0000, 0xFFFF, CRC_TRUE);
break;
case CRC_MOD_CRC16:
rc = crc_mk_tbl(tbl, 16, 0x8005, 0xFFFF, 0x0000, CRC_TRUE);
break;
case CRC_STD_XMODEM:
rc = crc_mk_tbl(tbl, 16, 0x8408, 0x0000, 0x0000, CRC_TRUE);
break;
case CRC_STD_ZMODEM16:
rc = crc_mk_tbl(tbl, 16, 0x1021, 0x0000, 0x0000, CRC_FALSE);
break;
case CRC_STD_CRC32:
rc = crc_mk_tbl(tbl, 32, 0x04C11DB7, 0xFFFFFFFF, 0xFFFFFFFF, CRC_TRUE);
break;
case CRC_STD_JAM:
rc = crc_mk_tbl(tbl, 32, 0x04C11DB7, 0xFFFFFFFF, 0x00000000, CRC_TRUE);
break;
default:
rc = CRC_FALSE;
break;
}
return rc;
}
#define CRC_STD_ZMODEM CRC_STD_CRC32
/***********************************************************************EXFN**
* NAME: crc_mk_tbl
*
* PURPOSE: Initialises a CRC_TBL structure for CRC calculation
*
* PARAMS: tbl Address of structure to initialize
* width Register width. Must be 8, 16, 24 or 32
* poly Calculation polynomial
* init_val Initial value of register
* xor_out Value to XOR register width before outputting
* is_rev Reversed bit order mode? TRUE/FALSE
*
* RETURNS: TRUE Structure successfully initialised
* FALSE Error
*
* OPERATION: Stores all parameters in the structure, and the calculates
* a table entry for each input character.
*
*****************************************************************************/
CRC_BOOL crc_mk_tbl(CRC_TBL *tbl, int width, CRC_VAL poly, CRC_VAL init_val,
CRC_VAL xor_out, int is_rev)
{
CRC_VAL pre_calc;
int is_carry;
int ii;
int jj;
int rc = CRC_TRUE;
// add freefrug
CRC_VAL mask = 0xffff;
switch( width )
{
case 8 : mask = 0xff; break;
case 24 : mask = 0xffffff; break;
case 32 : mask = 0xffffffff; break;
}
// ---
/***************************************************************************
* Store parameters
***************************************************************************/
tbl->width = width;
tbl->poly = poly;
tbl->init_val = init_val;
tbl->xor_out = xor_out;
tbl->is_rev = is_rev;
/***************************************************************************
* Check that register width is valid
***************************************************************************/
if ( ((width % CRC_BITS_BYTE) != 0) ||
(width > (sizeof(CRC_VAL) * CRC_BITS_BYTE)) )
{
rc = CRC_FALSE;
goto ERROR;
}
/***************************************************************************
* Calculate a table entry for each possible input character. Each entry is
* stats as with the input byte occupying the most significant byte of the
* register. This is then repeatedly shifted left by one bit, until the
* all the original bits have been moved out. After each shift, if the bit
* just removed is 1 then the register is XORed with the polynomial.
***************************************************************************/
for (ii = 0; ii <= CRC_UCHAR_MAX; ii++)
{
pre_calc = (CRC_VAL) ii;
crc_reflect(&pre_calc, CRC_BITS_BYTE, is_rev);
pre_calc <<= (width - CRC_BITS_BYTE);
for (jj = 0; jj < CRC_BITS_BYTE; jj++)
{
is_carry = pre_calc & (1 << (width - 1));
pre_calc <<= 1;
if (is_carry)
{
pre_calc ^= poly;
}
}
crc_reflect(&pre_calc, width, is_rev);
tbl->pre_calc[ii] = pre_calc & mask; // adjust freefrug
}
ERROR:
return rc;
}
/***********************************************************************EXFN**
* NAME: crc_init
*
* PURPOSE: Initialise a CRC register, so data can be applied to it
*
* PARAMS: crc Address of the CRC register
* tbl Address of the table to use for calculation
*
* RETURNS: None
*
* OPERATION: Sets the CRC register to initial value and reflects it if
* necessary
*
*****************************************************************************/
void crc_init(CRC_VAL *crc, CRC_TBL *tbl)
{
(*crc) = tbl->init_val;
crc_reflect(crc, tbl->width, tbl->is_rev);
}
/***********************************************************************EXFN**
* NAME: crc_final
*
* PURPOSE: Finalise calculation of CRC register, so it can be used
*
* PARAMS: crc Address of the CRC register
* tbl Address of the table to use for calculation
*
* RETURNS: Usable CRC
*
* OPERATION: XOR the CRC register with mask, and then strip off unused bits.
* Leave register unmodified; return modified value.
*
*****************************************************************************/
CRC_VAL crc_final(CRC_VAL *crc, CRC_TBL *tbl)
{
return ((*crc) ^ tbl->xor_out); /* & ~(0xFFFFFFFF << tbl->width); */
}
/***********************************************************************EXFN**
* NAME: crc_add_chr
*
* PURPOSE: Apply row of one or more characters to the CRC register
*
* PARAMS: crc Address of the CRC register
* tbl Address of the table to use for calculation
* chr Character to apply
* cnt Number of time to apply it
*
* RETURNS: None
*
* OPERATION: Shift the register along by a byte, then XOR with the
* appropriate value in the table
*
*****************************************************************************/
void crc_add_chr(CRC_VAL *crc, CRC_TBL *tbl, unsigned char chr, int cnt)
{
if(tbl->is_rev)
{
for(; cnt > 0; cnt--)
{
(*crc) = ((*crc) >> CRC_BITS_BYTE) ^
tbl->pre_calc[((*crc) & CRC_BYTE_MASK) ^ chr];
}
}
else
{
for(; cnt > 0; cnt--)
{
(*crc) = ((*crc) << CRC_BITS_BYTE) ^ tbl->pre_calc[(((*crc) >>
(tbl->width - CRC_BITS_BYTE)) & CRC_BYTE_MASK) ^ chr];
}
}
}
/***********************************************************************EXFN**
* NAME: crc_add_str
*
* PURPOSE: Apply a null-terminated string to the CRC register
*
* PARAMS: crc Address of the CRC register
* tbl Address of the table to use for calculation
* str Address of null-terminated string to apply
*
* RETURNS: None
*
* OPERATION: Loop through the string until the null-terminator is found,
* applying the action for crc_add_chr on each character
*
*****************************************************************************/
void crc_add_str(CRC_VAL *crc, CRC_TBL *tbl, unsigned char *str)
{
if(tbl->is_rev)
{
while(*str)
{
(*crc) = ((*crc) >> CRC_BITS_BYTE) ^
tbl->pre_calc[((*crc) & CRC_BYTE_MASK) ^ (*str)];
str++;
}
}
else
{
while(*str)
{
(*crc) = ((*crc) << CRC_BITS_BYTE) ^ tbl->pre_calc[(((*crc) >>
(tbl->width - CRC_BITS_BYTE)) & CRC_BYTE_MASK) ^ (*str)];
str++;
}
}
}
/***********************************************************************EXFN**
* NAME: crc_add_data
*
* PURPOSE: Apply data with specified length to the CRC register
*
* PARAMS: crc Address of the CRC register
* tbl Address of the table to use for calculation
* data Address of beginning of data
* len Length of data
*
* RETURNS: None
*
* OPERATION: Loop through the data buffer applying the action for
* crc_add_chr on each character
*
*****************************************************************************/
void crc_add_data(CRC_VAL *crc, CRC_TBL *tbl, unsigned char *data, int len)
{
int ii;
if(tbl->is_rev)
{
for(ii = 0; ii < len; ii++)
{
(*crc) = ((*crc) >> CRC_BITS_BYTE) ^
tbl->pre_calc[((*crc) & CRC_BYTE_MASK) ^ data[ii]];
}
}
else
{
for(ii = 0; ii < len; ii++)
{
(*crc) = ((*crc) << CRC_BITS_BYTE) ^ tbl->pre_calc[(((*crc) >>
(tbl->width - CRC_BITS_BYTE)) & CRC_BYTE_MASK) ^ data[ii]];
}
}
}