Does anyone know of a good CRC16-CCITT routine written in PB?
I need one to work with remote client that requires:
SimonThe CRC is calculated using the polynomial 0x1021 (also known as CRC-16-CCITT) using the seed 0xFFFF.
SimonThe CRC is calculated using the polynomial 0x1021 (also known as CRC-16-CCITT) using the seed 0xFFFF.
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)))

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
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 */
Are you sure ?IdeasVacuum wrote:Guys, your results seem to differ from Lammert Bies?
This is exactly the same as the PB code returns (when compiled in ASCII mode of course).CRC-CCITT (0xFFFF) 0x29B1

Ah, the devil lies there!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.wilbert wrote:Are you sure ?IdeasVacuum wrote:Guys, your results seem to differ from Lammert Bies?
The online calculation for the string 123456789 on the page you are referring to mentionsThis is exactly the same as the PB code returns (when compiled in ASCII mode of course).CRC-CCITT (0xFFFF) 0x29B1
This code does not appear to produce the correct answers as compared to :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)))
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
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
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.
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 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
EndProcedureCode: 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))This code produces the expected results. Thank-youwilbert wrote:Here's a PB routine without ASMCode: 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)