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-2019 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 artificer!AT!seanerikoconnor!DOT!freeservers!DOT!com
 38 |     with !DOT! replaced by . and the !AT! replaced by @
 39 |
 40 +============================================================================*/
 41 
 42 #include <iostream>
 43 #include <string>
 44 
 45 using namespace std ;
 46 
 47 #include "dataTypes.h"     // 
 48 #include "shiftRegister.h" // Shift register class (needed for CRC code).
 49 #include "crcCode.h"       // CRC code class.
 50 
 51 string legalNotice(
 52     "\n"
 53     "CRCDemo Version 2.1 - A Program for generating and checking CRC codes.\n"
 54     "Copyright (C) 1999-2019 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 
 62 int 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 }