#include "lib_crc.h" /*******************************************************************\ * * * Library : lib_crc * * File : lib_crc.c * * Author : Lammert Bies 1999-2008 * * E-mail : info@lammertbies.nl * * Language : ANSI C * * * * * * Description * * =========== * * * * The file lib_crc.c contains the private and public func- * * tions used for the calculation of CRC-16, CRC-CCITT and * * CRC-32 cyclic redundancy values. * * * * * * Dependencies * * ============ * * * * lib_crc.h CRC definitions and prototypes * * * * * * Modification history * * ==================== * * * * Date Version Comment * * * * 2008-04-20 1.16 Added CRC-CCITT calculation for Kermit * * * * 2007-04-01 1.15 Added CRC16 calculation for Modbus * * * * 2007-03-28 1.14 Added CRC16 routine for Sick devices * * * * 2005-12-17 1.13 Added CRC-CCITT with initial 0x1D0F * * * * 2005-05-14 1.12 Added CRC-CCITT with start value 0 * * * * 2005-02-05 1.11 Fixed bug in CRC-DNP routine * * * * 2005-02-04 1.10 Added CRC-DNP routines * * * * 1999-02-21 1.01 Added FALSE and TRUE mnemonics * * * * 1999-01-22 1.00 Initial source * * * \*******************************************************************/ /*******************************************************************\ * * * #define P_xxxx * * * * The CRC's are computed using polynomials. The coefficients * * for the algorithms are defined by the following constants. * * * \*******************************************************************/ #define P_16 0xA001 #define P_32 0xEDB88320L #define P_CCITT 0x1021 #define P_DNP 0xA6BC #define P_KERMIT 0x8408 #define P_SICK 0x8005 /*******************************************************************\ * * * static int crc_tab...init * * static unsigned ... crc_tab...[] * * * * The algorithms use tables with precalculated values. This * * speeds up the calculation dramaticaly. The first time the * * CRC function is called, the table for that specific calcu- * * lation is set up. The ...init variables are used to deter- * * mine if the initialization has taken place. The calculated * * values are stored in the crc_tab... arrays. * * * * The variables are declared static. This makes them invisi- * * ble for other modules of the program. * * * \*******************************************************************/ static int crc_tab16_init = FALSE; static int crc_tab32_init = FALSE; static int crc_tabccitt_init = FALSE; static int crc_tabdnp_init = FALSE; static int crc_tabkermit_init = FALSE; static unsigned short crc_tab16[256]; static unsigned long crc_tab32[256]; static unsigned short crc_tabccitt[256]; static unsigned short crc_tabdnp[256]; static unsigned short crc_tabkermit[256]; /*******************************************************************\ * * * static void init_crc...tab(); * * * * Three local functions are used to initialize the tables * * with values for the algorithm. * * * \*******************************************************************/ static void init_crc16_tab( void ); static void init_crc32_tab( void ); static void init_crcccitt_tab( void ); static void init_crcdnp_tab( void ); static void init_crckermit_tab( void ); /*******************************************************************\ * * * unsigned short update_crc_ccitt( unsigned long crc, char c ); * * * * The function update_crc_ccitt calculates a new CRC-CCITT * * value based on the previous value of the CRC and the next * * byte of the data to be checked. * * * \*******************************************************************/ unsigned short update_crc_ccitt( unsigned short crc, char c ) { unsigned short tmp, short_c; short_c = 0x00ff & (unsigned short) c; if ( ! crc_tabccitt_init ) init_crcccitt_tab(); tmp = (crc >> 8) ^ short_c; crc = (crc << 8) ^ crc_tabccitt[tmp]; return crc; } /* update_crc_ccitt */ /*******************************************************************\ * * * unsigned short update_crc_sick( * * unsigned long crc, char c, char prev_byte ); * * * * The function update_crc_sick calculates a new CRC-SICK * * value based on the previous value of the CRC and the next * * byte of the data to be checked. * * * \*******************************************************************/ unsigned short update_crc_sick( unsigned short crc, char c, char prev_byte ) { unsigned short short_c, short_p; short_c = 0x00ff & (unsigned short) c; short_p = ( 0x00ff & (unsigned short) prev_byte ) << 8; if ( crc & 0x8000 ) crc = ( crc << 1 ) ^ P_SICK; else crc = crc << 1; crc &= 0xffff; crc ^= ( short_c | short_p ); return crc; } /* update_crc_sick */ /*******************************************************************\ * * * unsigned short update_crc_16( unsigned short crc, char c ); * * * * The function update_crc_16 calculates a new CRC-16 value * * based on the previous value of the CRC and the next byte * * of the data to be checked. * * * \*******************************************************************/ unsigned short update_crc_16( unsigned short crc, char c ) { unsigned short tmp, short_c; short_c = 0x00ff & (unsigned short) c; if ( ! crc_tab16_init ) init_crc16_tab(); tmp = crc ^ short_c; crc = (crc >> 8) ^ crc_tab16[ tmp & 0xff ]; return crc; } /* update_crc_16 */ /*******************************************************************\ * * * unsigned short update_crc_kermit( unsigned short crc, char c ); * * * * The function update_crc_kermit calculates a new CRC value * * based on the previous value of the CRC and the next byte * * of the data to be checked. * * * \*******************************************************************/ unsigned short update_crc_kermit( unsigned short crc, char c ) { unsigned short tmp, short_c; short_c = 0x00ff & (unsigned short) c; if ( ! crc_tabkermit_init ) init_crckermit_tab(); tmp = crc ^ short_c; crc = (crc >> 8) ^ crc_tabkermit[ tmp & 0xff ]; return crc; } /* update_crc_kermit */ /*******************************************************************\ * * * unsigned short update_crc_dnp( unsigned short crc, char c ); * * * * The function update_crc_dnp calculates a new CRC-DNP value * * based on the previous value of the CRC and the next byte * * of the data to be checked. * * * \*******************************************************************/ unsigned short update_crc_dnp( unsigned short crc, char c ) { unsigned short tmp, short_c; short_c = 0x00ff & (unsigned short) c; if ( ! crc_tabdnp_init ) init_crcdnp_tab(); tmp = crc ^ short_c; crc = (crc >> 8) ^ crc_tabdnp[ tmp & 0xff ]; return crc; } /* update_crc_dnp */ /*******************************************************************\ * * * unsigned long update_crc_32( unsigned long crc, char c ); * * * * The function update_crc_32 calculates a new CRC-32 value * * based on the previous value of the CRC and the next byte * * of the data to be checked. * * * \*******************************************************************/ unsigned long update_crc_32( unsigned long crc, char c ) { unsigned long tmp, long_c; long_c = 0x000000ffL & (unsigned long) c; if ( ! crc_tab32_init ) init_crc32_tab(); tmp = crc ^ long_c; crc = (crc >> 8) ^ crc_tab32[ tmp & 0xff ]; return crc; } /* update_crc_32 */ /*******************************************************************\ * * * static void init_crc16_tab( void ); * * * * The function init_crc16_tab() is used to fill the array * * for calculation of the CRC-16 with values. * * * \*******************************************************************/ static void init_crc16_tab( void ) { int i, j; unsigned short crc, c; for (i=0; i<256; i++) { crc = 0; c = (unsigned short) i; for (j=0; j<8; j++) { if ( (crc ^ c) & 0x0001 ) crc = ( crc >> 1 ) ^ P_16; else crc = crc >> 1; c = c >> 1; } crc_tab16[i] = crc; } crc_tab16_init = TRUE; } /* init_crc16_tab */ /*******************************************************************\ * * * static void init_crckermit_tab( void ); * * * * The function init_crckermit_tab() is used to fill the array * * for calculation of the CRC Kermit with values. * * * \*******************************************************************/ static void init_crckermit_tab( void ) { int i, j; unsigned short crc, c; for (i=0; i<256; i++) { crc = 0; c = (unsigned short) i; for (j=0; j<8; j++) { if ( (crc ^ c) & 0x0001 ) crc = ( crc >> 1 ) ^ P_KERMIT; else crc = crc >> 1; c = c >> 1; } crc_tabkermit[i] = crc; } crc_tabkermit_init = TRUE; } /* init_crckermit_tab */ /*******************************************************************\ * * * static void init_crcdnp_tab( void ); * * * * The function init_crcdnp_tab() is used to fill the array * * for calculation of the CRC-DNP with values. * * * \*******************************************************************/ static void init_crcdnp_tab( void ) { int i, j; unsigned short crc, c; for (i=0; i<256; i++) { crc = 0; c = (unsigned short) i; for (j=0; j<8; j++) { if ( (crc ^ c) & 0x0001 ) crc = ( crc >> 1 ) ^ P_DNP; else crc = crc >> 1; c = c >> 1; } crc_tabdnp[i] = crc; } crc_tabdnp_init = TRUE; } /* init_crcdnp_tab */ /*******************************************************************\ * * * static void init_crc32_tab( void ); * * * * The function init_crc32_tab() is used to fill the array * * for calculation of the CRC-32 with values. * * * \*******************************************************************/ static void init_crc32_tab( void ) { int i, j; unsigned long crc; for (i=0; i<256; i++) { crc = (unsigned long) i; for (j=0; j<8; j++) { if ( crc & 0x00000001L ) crc = ( crc >> 1 ) ^ P_32; else crc = crc >> 1; } crc_tab32[i] = crc; } crc_tab32_init = TRUE; } /* init_crc32_tab */ /*******************************************************************\ * * * static void init_crcccitt_tab( void ); * * * * The function init_crcccitt_tab() is used to fill the array * * for calculation of the CRC-CCITT with values. * * * \*******************************************************************/ static void init_crcccitt_tab( void ) { int i, j; unsigned short crc, c; for (i=0; i<256; i++) { crc = 0; c = ((unsigned short) i) << 8; for (j=0; j<8; j++) { if ( (crc ^ c) & 0x8000 ) crc = ( crc << 1 ) ^ P_CCITT; else crc = crc << 1; c = c << 1; } crc_tabccitt[i] = crc; } crc_tabccitt_init = TRUE; } /* init_crcccitt_tab */