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}