1/*=============================================================================
2|
3| NAME
4|
5| testCRC.cpp
6|
7| DESCRIPTION
8|
9| Unit test program for CRC generation and checking.
10|
11| AUTHOR
12|
13| Sean O'Connor
14|
15| NOTES/METHOD
16|
17| Create as a console application under Windows NT.
18|
19| LEGAL
20|
21| CRCDemo Version 2.1 - A Program for generating and checking CRC codes.
22| Copyright (C) 1999-2025 by Sean Erik O'Connor. All Rights Reserved.
23|
24| This program is free software: you can redistribute it and/or modify
25| it under the terms of the GNU General Public License as published by
26| the Free Software Foundation, either version 3 of the License, or
27| (at your option) any later version.
28|
29| This program is distributed in the hope that it will be useful,
30| but WITHOUT ANY WARRANTY; without even the implied warranty of
31| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32| GNU General Public License for more details.
33|
34| You should have received a copy of the GNU General Public License
35| along with this program. If not, see <http://www.gnu.org/licenses/>.
36|
37| The author's address is seanerikoconnor!AT!gmail!DOT!com
38| with !DOT! replaced by . and the !AT! replaced by @
39|
40+============================================================================*/
41
42#include <iostream>
43#include <string>
44
45using namespace std ;
46
47#include "dataTypes.hpp" //
48#include "shiftRegister.hpp" // Shift register class (needed for CRC code).
49#include "crcCode.hpp" // CRC code class.
50
51string legalNotice(
52 "\n"
53 "CRCDemo Version 2.1 - A Program for generating and checking CRC codes.\n"
54 "Copyright (C) 1999-2025 by Sean Erik O'Connor. All Rights Reserved.\n"
55 "\n"
56 "CRCDemo comes with ABSOLUTELY NO WARRANTY; for details see the\n"
57 "GNU General Public License. This is free software, and you are welcome\n"
58 "to redistribute it under certain conditions; see the GNU General Public License\n"
59 "for details.\n"
60) ;
61
62int main( int argc, char * argv[] )
63{
64 // Show the legal notice first.
65 cout << legalNotice << endl ;
66
67 // Check parity word is 32 bits long.
68 if (8 * sizeof(syndrome_t) != 32)
69 {
70 cerr << "ERROR: make sure the typedef syndrome_t is a 32-bit unsigned integer on your system." << endl ;
71 return 1 ;
72 }
73
74 cout << "\n\nCRC-16 test: x ^ 16 + x ^ 15 + x ^ 2 + 1" << endl << endl ;
75
76 // Construct CRC code object from the CRC's generator polynomial.
77 // We use the standard code, CRC-16.
78 CRCCode
79 crc16( "x ^ 16 + x ^ 15 + x ^ 2 + 1" ) ;
80
81 // Do an error check to see if the object was constructed OK.
82 if (crc16.getNumParityBytes() == 0)
83 {
84 cerr << "ERROR: Cannot create CRC-16" << endl ;
85 return 1 ;
86 }
87
88 // Create a short sample message to be encoded.
89 // Allow for 16 bits extra space at the end of the buffer for
90 // parity bits.
91 unsigned char buffer[ 18 ] =
92 {
93 0x0E, 0x00, 0x00, 0x00, 0x01, 0x05,
94 0x02, 0x00, 0x63, 0x65, 0x6e, 0x74,
95 0x75, 0x72, 0x61, 0x00,
96 0x00, 0x00 // 16 bits extra space for parity bits.
97 } ;
98
99 long int bufferLen = 16 ;
100
101 // Add the parity bits onto the end of the message to
102 // create a systematically encoded codeword.
103 crc16.addParityToBuffer( buffer, bufferLen ) ;
104
105 // Update the buffer length now, since it has added parity bytes.
106 long int bufferPlusParityLen = bufferLen + crc16.getNumParityBytes() ;
107
108 // Check the codeword.
109 syndrome_t shiftedSyndrome =
110 crc16.shiftedSyndrome( buffer, bufferPlusParityLen ) ;
111
112 cout << "Shifted syndrome of codeword = " << hex << shiftedSyndrome << " (should be zero)" << endl ;
113 if (shiftedSyndrome != 0)
114 {
115 cerr << "ERROR: shifted syndrome of codeword is nonzero for CRC-16" << endl ;
116 return 1 ;
117 }
118
119 // Compute parity bits for the message.
120 syndrome_t parityBits = crc16.parityBits( buffer, bufferLen ) ;
121
122 cout << "Parity bits = " << (unsigned int)( ((parityBits & 0xFFFF0000) >> 16) ) << " (should be 35cf)" << endl ;
123 if ((unsigned int)( ((parityBits & 0xFFFF0000) >> 16) ) != 0x35cf)
124 {
125 cerr << "ERROR: parity bits incorrect for CRC-16" << endl ;
126 return 1 ;
127 }
128
129 // Add noise to the codeword.
130 buffer[ 2 ] |= 0x10 ;
131
132 // Check the codeword.
133 shiftedSyndrome = crc16.shiftedSyndrome( buffer, bufferLen ) ;
134
135 cout << "Shifted syndrome of noisy codeword = " << shiftedSyndrome << " (should be non-zero)" << endl ;
136 if (shiftedSyndrome == 0)
137 {
138 cerr << "ERROR: shifted syndrome of noisy codeword is zero for CRC-16" << endl ;
139 return 1 ;
140 }
141
142
143 //=============================================================
144
145 // Create a short sample message to be encoded.
146 unsigned char buffer32Q[ 6 ] =
147 {
148 0x01, 0x02,
149 0x00, 0x00, 0x00, 0x00 // 32 bits extra space for parity bits.
150 } ;
151
152 bufferLen = 2 ;
153
154 cout << "\n\nCRC-32Q test: x^32+x^31+x^24+x^22+x^16+x^14+x^8+x^7+x^5+x^3+x+1" << endl ;
155
156 // Construct CRC code object from the CRC's generator polynomial.
157 CRCCode
158 crc32Q( "x^32+x^31+x^24+x^22+x^16+x^14+x^8+x^7+x^5+x^3+x+1" ) ;
159
160 // Do an error check to see if the object was constructed OK.
161 if (crc32Q.getNumParityBytes() == 0)
162 {
163 cerr << "ERROR: Cannot create CRC-32Q" << endl ;
164 }
165
166 // Add the parity bits onto the end of the message to
167 // create a systematically encoded codeword.
168 crc32Q.addParityToBuffer( buffer32Q, bufferLen ) ;
169
170 // Update the buffer length now, since it has added parity bytes.
171 bufferPlusParityLen = bufferLen + crc32Q.getNumParityBytes() ;
172
173 // Check the codeword.
174 shiftedSyndrome = crc32Q.shiftedSyndrome( buffer32Q, bufferPlusParityLen ) ;
175
176 cout << "Shifted syndrome of codeword = " << shiftedSyndrome << " (should be zero)" << endl ;
177 if (shiftedSyndrome != 0)
178 {
179 cerr << "ERROR: shifted syndrome of codeword is nonzero for CRC-32Q" << endl ;
180 return 1 ;
181 }
182
183 // Compute parity bits for the message.
184 parityBits = crc32Q.parityBits( buffer32Q, bufferLen ) ;
185
186 cout << "Parity bits = " << (unsigned int)(parityBits) << " (should be 03c371cf)" << endl ;
187 if ((unsigned int)( parityBits ) != 0x03c371cf)
188 {
189 cerr << "ERROR: parity bits incorrect for CRC-32Q" << endl ;
190 return 1 ;
191 }
192
193 // Add noise to the codeword.
194 buffer32Q[ 1 ] |= 0x10 ;
195
196 // Check the codeword.
197 shiftedSyndrome = crc32Q.shiftedSyndrome( buffer32Q, bufferLen ) ;
198
199 cout << "Shifted syndrome of noisy codeword = " << shiftedSyndrome << " (should be non-zero)" << endl ;
200 if (shiftedSyndrome == 0)
201 {
202 cerr << "ERROR: shifted syndrome of noisy codeword is zero for CRC-32Q" << endl ;
203 return 1 ;
204 }
205
206
207 //=============================================================
208
209 cout << "\n\nCRC-CCITT test using shift register preset to FFFF" <<
210 "and parity bit inversion: x ^ 16 + x ^ 12 + x ^ 5 + 1" << endl ;
211
212 // Construct CRC code object from the CRC's generator polynomial.
213 // We use the standard code, CRC-CCITT, but we preset the shift
214 // register contents to FFFF, and we 1's complement the parity
215 // bits.
216 CRCCode
217 crcCCITT( "x ^ 16 + x ^ 12 + x ^ 5 + 1", 0xFFFF, true ) ;
218
219 // Do an error check to see if the object was constructed OK.
220 if (crcCCITT.getNumParityBytes() == 0)
221 {
222 cerr << "ERROR: cannot create CRC-CCITT" << endl ;
223 }
224
225 // Create a short sample message to be encoded.
226 // Allow for 16 bits extra space at the end of the buffer for
227 // parity bits.
228 unsigned char bufferITT[ 7 ] =
229 {
230 0x00, 0x05, 0x04, 0x00, 0x10,
231 0x00, 0x00 // 16 bits extra space for parity bits.
232 } ;
233
234 bufferLen = 5 ;
235
236 // Add the parity bits onto the end of the message to
237 // create a systematically encoded codeword.
238 crcCCITT.addParityToBuffer( bufferITT, bufferLen ) ;
239
240 // Update the buffer length now, since it has added parity bytes.
241 bufferPlusParityLen = bufferLen + crcCCITT.getNumParityBytes() ;
242
243 // Check the codeword.
244 shiftedSyndrome =
245 crcCCITT.shiftedSyndrome( bufferITT, bufferPlusParityLen ) ;
246
247 cout << "Shifted syndrome of codeword = " << shiftedSyndrome << " (should be zero)" << endl ;
248 if (shiftedSyndrome != 0)
249 {
250 cerr << "ERROR: shifted syndrome of codeword is nonzero for CRC-CCITT" << endl ;
251 return 1 ;
252 }
253
254 // Compute parity bits for the message.
255 parityBits = crcCCITT.parityBits( bufferITT, bufferLen ) ;
256
257 cout << "Parity bits = " << (unsigned int)( ((parityBits & 0xFFFF0000) >> 16) ) << " (should be 9c47)" << endl ;
258 if ((unsigned int)( ((parityBits & 0xFFFF0000) >> 16) ) != 0x9c47)
259 {
260 cerr << "ERROR: parity bits incorrect for CRC-CCITT" << endl ;
261 return 1 ;
262 }
263
264 // Add noise to the codeword.
265 bufferITT[ 2 ] |= 0x10 ;
266
267 // Check the codeword.
268 shiftedSyndrome = crcCCITT.shiftedSyndrome( bufferITT, bufferLen ) ;
269
270 cout << "Shifted syndrome of noisy codeword = " << shiftedSyndrome << " (should be non-zero)" << endl ;
271 if (shiftedSyndrome == 0)
272 {
273 cerr << "ERROR: shifted syndrome of noisy codeword is zero for CRC-CCITT" << endl ;
274 return 1 ;
275 }
276
277 //=============================================================
278
279 cout << "\n\nCRC-DNP test using shift register preset to 0 " <<
280 "and no parity bit inversion" <<
281 "x^16 + x^13 + x^12 + x^11 + x^10 + x^8 + x^6 + x^5 + x^2 + 1" << endl ;
282
283 // Construct CRC code object from the CRC's generator polynomial.
284 CRCCode
285 crcDNP(
286 "x^16 + x^13 + x^12 + x^11 + x^10 + x^8 + x^6 + x^5 + x^2 + 1",
287 0x0, false ) ;
288
289 // Do an error check to see if the object was constructed OK.
290 if (crcDNP.getNumParityBytes() == 0)
291 {
292 cerr << "ERROR: cannot create CRC-DNP" << endl ;
293 }
294
295 // Create a short sample message to be encoded.
296 // Allow for 16 bits extra space at the end of the buffer for
297 // parity bits.
298 unsigned char bufferDNP[ 10 ] =
299 {
300 0x05, 0x64, 0x11, 0xc4, 0x65, 0x00, 0x02, 0x00,
301 0x00, 0x00 // 16 bits extra space for parity bits.
302 } ;
303
304 bufferLen = 8 ;
305
306 // Add the parity bits onto the end of the message to
307 // create a systematically encoded codeword.
308 crcDNP.addParityToBuffer( bufferDNP, bufferLen ) ;
309
310 // Update the buffer length now, since it has added parity bytes.
311 bufferPlusParityLen = bufferLen + crcDNP.getNumParityBytes() ;
312
313 // Check the codeword.
314 shiftedSyndrome = crcDNP.shiftedSyndrome( bufferDNP, bufferPlusParityLen ) ;
315
316 cout << "Shifted syndrome of codeword = " << shiftedSyndrome << " (should be zero)" << endl ;
317 if (shiftedSyndrome != 0)
318 {
319 cerr << "ERROR: shifted syndrome of codeword is nonzero for CRC-DNP" << endl ;
320 return 1 ;
321 }
322
323 // Compute parity bits for the message.
324 parityBits = crcDNP.parityBits( bufferDNP, bufferLen ) ;
325
326 cout << "Parity bits = " << (unsigned int)( ((parityBits & 0xFFFF0000) >> 16) ) << " (should be b1ae)" << endl ;
327
328 // Add noise to the codeword.
329 bufferDNP[ 2 ] |= 0xE0 ;
330
331 // Check the codeword.
332 shiftedSyndrome = crcDNP.shiftedSyndrome( bufferDNP, bufferLen ) ;
333
334 cout << "Shifted syndrome of noisy codeword = " << shiftedSyndrome << " (should be non-zero)" << endl ;
335 if (shiftedSyndrome == 0)
336 {
337 cerr << "ERROR: shifted syndrome of noisy codeword is zero for CRC-DNP" << endl ;
338 return 1 ;
339 }
340
341 return( 0 ) ;
342}