CRC16-CCITT Checksum Routine

Everything else that doesn't fall into one of the other PB categories.
swhite
Addict
Addict
Posts: 808
Joined: Thu May 21, 2009 6:56 pm

CRC16-CCITT Checksum Routine

Post by swhite »

Hi

Does anyone know of a good CRC16-CCITT routine written in PB?

I need one to work with remote client that requires:
The CRC is calculated using the polynomial 0x1021 (also known as CRC-16-CCITT) using the seed 0xFFFF.
Simon
Simon White
dCipher Computing
User avatar
idle
Always Here
Always Here
Posts: 6238
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: CRC16-CCITT Checksum Routine

Post by idle »

Think this is the correct variant of CRC16CCITT

http://introcs.cs.princeton.edu/java/51 ... .java.html

Code: Select all

Procedure CRC16CCITT(*mem.Ascii,len)
 Protected crc.u = $FFFF;        
 While a < len  
      For i = 0 To 7 
            bit =  (*mem\a >> (7-i) & 1) 
            c15 = ((crc >> 15) & 1)
            crc << 1;
            If Bool(c15 ! bit)
               crc ! $1021;
             EndIf 
        Next 
        a+1
        *mem+1
   Wend      
   crc & $ffff;
   ProcedureReturn crc 
EndProcedure    
 
 Global STR.s = "123456789" 
 Debug Hex(CRC16CCITT(@str,Len(STR))) 
 
Windows 11, Manjaro, Raspberry Pi OS
Image
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3944
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: CRC16-CCITT Checksum Routine

Post by wilbert »

Same results as the procedure Idle posted but in table form

Code: Select all

Procedure.u CRC16CCITT(*mem.Ascii, len)
  Protected *table.Unicode, *mem_end = *mem + len
  Protected crc16.u = $ffff
  While *mem < *mem_end
    *table = ?CRC16CCITT_table + crc16 >> 8 ! *mem\a << 1
    crc16 = crc16 << 8 ! *table\u 
    *mem + 1
  Wend
  ProcedureReturn crc16 
  
  DataSection
    CRC16CCITT_table:
    Data.u $0000, $1021, $2042, $3063, $4084, $50A5, $60C6, $70E7
    Data.u $8108, $9129, $A14A, $B16B, $C18C, $D1AD, $E1CE, $F1EF
    Data.u $1231, $0210, $3273, $2252, $52B5, $4294, $72F7, $62D6
    Data.u $9339, $8318, $B37B, $A35A, $D3BD, $C39C, $F3FF, $E3DE
    Data.u $2462, $3443, $0420, $1401, $64E6, $74C7, $44A4, $5485
    Data.u $A56A, $B54B, $8528, $9509, $E5EE, $F5CF, $C5AC, $D58D
    Data.u $3653, $2672, $1611, $0630, $76D7, $66F6, $5695, $46B4
    Data.u $B75B, $A77A, $9719, $8738, $F7DF, $E7FE, $D79D, $C7BC
    Data.u $48C4, $58E5, $6886, $78A7, $0840, $1861, $2802, $3823
    Data.u $C9CC, $D9ED, $E98E, $F9AF, $8948, $9969, $A90A, $B92B
    Data.u $5AF5, $4AD4, $7AB7, $6A96, $1A71, $0A50, $3A33, $2A12
    Data.u $DBFD, $CBDC, $FBBF, $EB9E, $9B79, $8B58, $BB3B, $AB1A
    Data.u $6CA6, $7C87, $4CE4, $5CC5, $2C22, $3C03, $0C60, $1C41
    Data.u $EDAE, $FD8F, $CDEC, $DDCD, $AD2A, $BD0B, $8D68, $9D49
    Data.u $7E97, $6EB6, $5ED5, $4EF4, $3E13, $2E32, $1E51, $0E70
    Data.u $FF9F, $EFBE, $DFDD, $CFFC, $BF1B, $AF3A, $9F59, $8F78
    Data.u $9188, $81A9, $B1CA, $A1EB, $D10C, $C12D, $F14E, $E16F
    Data.u $1080, $00A1, $30C2, $20E3, $5004, $4025, $7046, $6067
    Data.u $83B9, $9398, $A3FB, $B3DA, $C33D, $D31C, $E37F, $F35E
    Data.u $02B1, $1290, $22F3, $32D2, $4235, $5214, $6277, $7256
    Data.u $B5EA, $A5CB, $95A8, $8589, $F56E, $E54F, $D52C, $C50D
    Data.u $34E2, $24C3, $14A0, $0481, $7466, $6447, $5424, $4405
    Data.u $A7DB, $B7FA, $8799, $97B8, $E75F, $F77E, $C71D, $D73C
    Data.u $26D3, $36F2, $0691, $16B0, $6657, $7676, $4615, $5634
    Data.u $D94C, $C96D, $F90E, $E92F, $99C8, $89E9, $B98A, $A9AB
    Data.u $5844, $4865, $7806, $6827, $18C0, $08E1, $3882, $28A3
    Data.u $CB7D, $DB5C, $EB3F, $FB1E, $8BF9, $9BD8, $ABBB, $BB9A
    Data.u $4A75, $5A54, $6A37, $7A16, $0AF1, $1AD0, $2AB3, $3A92
    Data.u $FD2E, $ED0F, $DD6C, $CD4D, $BDAA, $AD8B, $9DE8, $8DC9
    Data.u $7C26, $6C07, $5C64, $4C45, $3CA2, $2C83, $1CE0, $0CC1
    Data.u $EF1F, $FF3E, $CF5D, $DF7C, $AF9B, $BFBA, $8FD9, $9FF8
    Data.u $6E17, $7E36, $4E55, $5E74, $2E93, $3EB2, $0ED1, $1EF0
  EndDataSection
  
EndProcedure
Windows (x64)
Raspberry Pi OS (Arm64)
IdeasVacuum
Always Here
Always Here
Posts: 6426
Joined: Fri Oct 23, 2009 2:33 am
Location: Wales, UK
Contact:

Re: CRC16-CCITT Checksum Routine

Post by IdeasVacuum »

Guys, your results seem to differ from Lammert Bies?

Lammert's C code for CRC:

Code: Select all

    /*******************************************************************\
    *                                                                   *
    *   Library         : lib_crc                                       *
    *   File            : lib_crc.h                                     *
    *   Author          : Lammert Bies  1999-2008                       *
    *   E-mail          : info@lammertbies.nl                           *
    *   Language        : ANSI C                                        *
    *                                                                   *
    *                                                                   *
    *   Description                                                     *
    *   ===========                                                     *
    *                                                                   *
    *   The file lib_crc.h contains public definitions  and  proto-     *
    *   types for the CRC functions present in lib_crc.c.               *
    *                                                                   *
    *                                                                   *
    *   Dependencies                                                    *
    *   ============                                                    *
    *                                                                   *
    *   none                                                            *
    *                                                                   *
    *                                                                   *
    *   Modification history                                            *
    *   ====================                                            *
    *                                                                   *
    *   Date        Version Comment                                     *
    *                                                                   *
    *   2008-04-20  1.16    Added CRC-CCITT routine 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-02-14  1.12    Added CRC-CCITT with initial 0x0000         *
    *                                                                   *
    *   2005-02-05  1.11    Fixed bug in CRC-DNP routine                *
    *                                                                   *
    *   2005-02-04  1.10    Added CRC-DNP routines                      *
    *                                                                   *
    *   2005-01-07  1.02    Changes in tst_crc.c                        *
    *                                                                   *
    *   1999-02-21  1.01    Added FALSE and TRUE mnemonics              *
    *                                                                   *
    *   1999-01-22  1.00    Initial source                              *
    *                                                                   *
    \*******************************************************************/

#define CRC_VERSION     "1.16"

#define FALSE           0
#define TRUE            1

unsigned short          update_crc_16(     unsigned short crc, char c                 );
unsigned long           update_crc_32(     unsigned long  crc, char c                 );
unsigned short          update_crc_ccitt(  unsigned short crc, char c                 );
unsigned short          update_crc_dnp(    unsigned short crc, char c                 );
unsigned short          update_crc_kermit( unsigned short crc, char c                 );
unsigned short          update_crc_sick(   unsigned short crc, char c, char prev_byte );

Code: Select all

#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 */
IdeasVacuum
If it sounds simple, you have not grasped the complexity.
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3944
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: CRC16-CCITT Checksum Routine

Post by wilbert »

IdeasVacuum wrote:Guys, your results seem to differ from Lammert Bies?
Are you sure ?
The online calculation for the string 123456789 on the page you are referring to mentions
CRC-CCITT (0xFFFF) 0x29B1
This is exactly the same as the PB code returns (when compiled in ASCII mode of course).
Windows (x64)
Raspberry Pi OS (Arm64)
IdeasVacuum
Always Here
Always Here
Posts: 6426
Joined: Fri Oct 23, 2009 2:33 am
Location: Wales, UK
Contact:

Re: CRC16-CCITT Checksum Routine

Post by IdeasVacuum »

when compiled in ASCII mode of course
Ah, the devil lies there! :evil:
IdeasVacuum
If it sounds simple, you have not grasped the complexity.
swhite
Addict
Addict
Posts: 808
Joined: Thu May 21, 2009 6:56 pm

Re: CRC16-CCITT Checksum Routine

Post by swhite »

wilbert wrote:
IdeasVacuum wrote:Guys, your results seem to differ from Lammert Bies?
Are you sure ?
The online calculation for the string 123456789 on the page you are referring to mentions
CRC-CCITT (0xFFFF) 0x29B1
This is exactly the same as the PB code returns (when compiled in ASCII mode of course).
This link shows that the above result is incorrect as there are a number of incorrect algorithms on the Internet.

http://srecord.sourceforge.net/crc16-ccitt.html
Simon White
dCipher Computing
swhite
Addict
Addict
Posts: 808
Joined: Thu May 21, 2009 6:56 pm

Re: CRC16-CCITT Checksum Routine

Post by swhite »

Procedure CRC16CCITT(*mem.Ascii,len)
Protected crc.u = $FFFF;
While a < len
For i = 0 To 7
bit = (*mem\a >> (7-i) & 1)
c15 = ((crc >> 15) & 1)
crc << 1;
If Bool(c15 ! bit)
crc ! $1021;
EndIf
Next
a+1
*mem+1
Wend
crc & $ffff;
ProcedureReturn crc
EndProcedure

Global STR.s = "123456789"
Debug Hex(CRC16CCITT(@str,Len(STR)))
This code does not appear to produce the correct answers as compared to :

http://srecord.sourceforge.net/crc16-ccitt.html
Simon White
dCipher Computing
swhite
Addict
Addict
Posts: 808
Joined: Thu May 21, 2009 6:56 pm

Re: CRC16-CCITT Checksum Routine

Post by swhite »

Code: Select all

#COMPILE EXE
#DIM ALL
'
#INCLUDE "win32api.inc"

%POLY_CRC16  = &H11021

FUNCTION Crc_16(dStr AS STRING) AS WORD
  LOCAL Cnt AS LONG, Buff AS STRING, Crc AS WORD, dwTemp AS DWORD
  Buff = STRING$(16, "1")
  FOR Cnt = 1 TO LEN(dStr)
    Buff = Buff & BIN$(ASC(dStr, Cnt), 8)
  NEXT
  Buff = Buff & STRING$(16, "0")
  dwTemp = VAL ("&b" & MID$(Buff, 1, 16))
  FOR Cnt = 17 TO LEN(Buff)
    SHIFT LEFT dwTemp, 1
    BIT CALC dwTemp, 0, (MID$(Buff,Cnt,1) = "1")
    IF BIT (dwTemp, 16) THEN dwTemp = dwTemp XOR %POLY_CRC16
  NEXT
  FUNCTION = dwTemp
END FUNCTION

'===============================
FUNCTION PBMAIN () AS LONG
  LOCAL lcStr AS STRING
  lcStr="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
  MSGBOX "CRC-16 of string " & $DQ & "123456789" & $DQ & " is:   0x" & HEX$(Crc_16("123456789"),4),,"Result: (expected: 0xE5CC)"
  MSGBOX "CRC-16 of string " & $DQ & "A" & $DQ & " is:   0x" & HEX$(Crc_16("A"),4),,"Result: (expected: 0x9479)"
  MSGBOX "CRC-16 of string " & $DQ & "" & $DQ & " is:   0x" & HEX$(Crc_16(""),4),,"Result: (expected: 0x1D0F)"
  MSGBOX "CRC-16 of string " & $DQ & lcStr & lcStr & $DQ & " is:   0x" & HEX$(Crc_16(lcStr+lcStr),4),,"Result: (expected: 0xE938)"
END FUNCTION
This code I created in PowerBasic does seem to produce the correct results. So now I just need an optimized version.

Simon
Simon White
dCipher Computing
IdeasVacuum
Always Here
Always Here
Posts: 6426
Joined: Fri Oct 23, 2009 2:33 am
Location: Wales, UK
Contact:

Re: CRC16-CCITT Checksum Routine

Post by IdeasVacuum »

...interesting article. Effectively, with different approaches producing different results (but both being prevalent), unless your code is used by all parties involved in exchanging data/files, CRC16-CCITT would be an unwise choice since false-positives could occur.
IdeasVacuum
If it sounds simple, you have not grasped the complexity.
swhite
Addict
Addict
Posts: 808
Joined: Thu May 21, 2009 6:56 pm

Re: CRC16-CCITT Checksum Routine

Post by swhite »

Code: Select all

;----------------------------------------------------------------------------
; Compute CRC16 (CRC-CCITT)
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; INPUT:
;   CX      - data length in bytes
;   DS:SI   - pointer to data
;
; OUTPUT:
;   AX      - computed CRC
;
; AFFECTS:
;   CX, DX, SI
;----------------------------------------------------------------------------
crc16ccitt:
  mov ax, 0xffff
  add cx, 2
.start:
  test cx, cx
  jz short .ret
  XOr dx, dx
  cmp cx, 2
  jbe short @f
  mov dl, [si]
@@:
  mov dh, 8
.Next:
  shl dl, 1
  rcl ax, 1
  jnc short @f
  XOr ax, 0x1021
@@:
  dec dh
  jnz short .Next
  inc si
  dec cx
  jmp short .start
.ret:
ret
The above code is from a Russian programmer http://zhak-notes.blogspot.ca/2014/04/fasm-crc-16.html

Not being an assembly language programmer I am wondering how I use this in Purebasic in particular how do I call the function crc16ccitt?

Thanks,
Simon
Simon White
dCipher Computing
swhite
Addict
Addict
Posts: 808
Joined: Thu May 21, 2009 6:56 pm

Re: CRC16-CCITT Checksum Routine

Post by swhite »

IdeasVacuum wrote:...interesting article. Effectively, with different approaches producing different results (but both being prevalent), unless your code is used by all parties involved in exchanging data/files, CRC16-CCITT would be an unwise choice since false-positives could occur.

The problem I have is that I have to use because I am interfacing with equipment that uses CRC16-CCITT. I have contacted the manufacturer to try to determine their implementation otherwise as you say there will be false positives. The assembly code I quoted from the Russian programmer produces the results I expected so I am hoping it matches the equipment I am communicating with.

Thanks,
Simon
Simon White
dCipher Computing
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3944
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: CRC16-CCITT Checksum Routine

Post by wilbert »

Here's a PB routine without ASM

Code: Select all

Procedure CRC16CCITT(*mem.Ascii, len)
  Protected.i i, *mem_end = *mem + len, crc = -1    
  While *mem < *mem_end  
    i = $80
    While i
      crc << 1
      If *mem\a & i
        crc + 1
      EndIf
      If crc & $10000
        crc ! $1021
      EndIf
      i >> 1 
    Wend
    *mem + 1
  Wend
  For i = 0 To 15
    crc << 1
    If crc & $10000
      crc ! $1021
    EndIf    
  Next
  ProcedureReturn crc & $ffff
EndProcedure 
Windows (x64)
Raspberry Pi OS (Arm64)
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3944
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: CRC16-CCITT Checksum Routine

Post by wilbert »

And here's the PB routine with ASM

Code: Select all

Procedure CRC16CCITT(*mem, len)
  !mov eax, 0xffff
  !mov ecx, [p.v_len]
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
    !mov rdx, [p.p_mem]
    !push rbx
    !crc16ccitt0:
    !mov bl, [rdx]
    !inc rdx
  CompilerElse
    !mov edx, [p.p_mem]
    !push ebx
    !crc16ccitt0:
    !mov bl, [edx]
    !inc edx
  CompilerEndIf
  !mov bh, 8
  !crc16ccitt1:
  !shl bl, 1
  !rcl ax, 1
  !jnc crc16ccitt2
  !xor ax, 0x1021
  !crc16ccitt2:
  !dec bh
  !jnz crc16ccitt1
  !dec ecx
  !jnz crc16ccitt0
  !mov bh, 16
  !crc16ccitt3:
  !shl bl, 1
  !rcl ax, 1
  !jnc crc16ccitt4
  !xor ax, 0x1021
  !crc16ccitt4:
  !dec bh
  !jnz crc16ccitt3
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
    !pop rbx
  CompilerElse
    !pop ebx
  CompilerEndIf
  ProcedureReturn
EndProcedure
Test code

Code: Select all

Global STR.s = "123456789"

str_len = StringByteLength(STR, #PB_Ascii)
*mem = AllocateMemory(str_len)
PokeS(*mem, STR, str_len, #PB_Ascii)

Debug Hex(CRC16CCITT(*mem, str_len))
Windows (x64)
Raspberry Pi OS (Arm64)
swhite
Addict
Addict
Posts: 808
Joined: Thu May 21, 2009 6:56 pm

Re: CRC16-CCITT Checksum Routine

Post by swhite »

wilbert wrote:Here's a PB routine without ASM

Code: Select all

Procedure CRC16CCITT(*mem.Ascii, len)
  Protected.i i, *mem_end = *mem + len, crc = -1    
  While *mem < *mem_end  
    i = $80
    While i
      crc << 1
      If *mem\a & i
        crc + 1
      EndIf
      If crc & $10000
        crc ! $1021
      EndIf
      i >> 1 
    Wend
    *mem + 1
  Wend
  For i = 0 To 15
    crc << 1
    If crc & $10000
      crc ! $1021
    EndIf    
  Next
  ProcedureReturn crc & $ffff
EndProcedure
lcStr.s=RSet("",256,"A")
Debug Hex(CRC16CCITT(@"",0),#PB_Word)
Debug Hex(CRC16CCITT(@"A",1),#PB_Word)
Debug Hex(CRC16CCITT(@"123456789",9),#PB_Word)
Debug Hex(CRC16CCITT(@lcStr,256),#PB_Word)
This code produces the expected results. Thank-you :D
Simon White
dCipher Computing
Post Reply