CRC-16 problems

Windows specific forum
User avatar
Dreamland Fantasy
Enthusiast
Enthusiast
Posts: 335
Joined: Fri Jun 11, 2004 9:35 pm
Location: Glasgow, UK
Contact:

CRC-16 problems

Post by Dreamland Fantasy »

Hi there,

I'm trying to convert some C code for calculating CRC-16 checksums. Here is the original C code:

Code: Select all

// Example Table Driven CCITT 0x8408 Checksum


#include <stdio.h>
#include <string.h>


#define BYTE unsigned char


const unsigned int Feedback = 0x8408;
const int TABLE_SIZE = 256;


const unsigned short Table[ TABLE_SIZE ] =
{
0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
};


unsigned short CRC_table( BYTE *, int );


int main()
{
BYTE t1[1], t2[1], t3[4], t4[64];
unsigned short a1, a2, a3, a4;


// Load Test Cases
t1[0] = 'M';
t2[0] = 'T';
strcpy( (char *)&t3[0],"THE" );
strcpy((char*)&t4[0],"THE,QUICK,BROWN,FOX,0123456789" );


// Calculate CRC Checksum
a1 = CRC_table( t1, 1 );
a2 = CRC_table( t2, 1 );
a3 = CRC_table( t3, 3 );
a4 = CRC_table( t4, 30 );


// Print Results
printf( "Answers %4x %4x %4x %4x\n", a1, a2, a3, a4 );
printf( "Expected 99e1 14a1 7d8d 7dc5\n" );
}


// Function to Calculate the CRC
unsigned short CRC_table( BYTE *pt, int length )
{
int i;
unsigned short CRC_val = 0;


for( i = 0; i < length; i++ )
CRC_val = (CRC_val >> 8) ^ Table[*(pt+i) ^ (CRC_val & 0x00FF)];


return( CRC_val );
}


// EOF CRC.cc ------------------------------------------------
Here is my converted PB (version 4.00) code:

Code: Select all

Procedure InitCRC16()
  Global Dim CRC16_Table.l(255)

  CRC16_Table(  0) = $0000
  CRC16_Table(  1) = $1189
  CRC16_Table(  2) = $2312
  CRC16_Table(  3) = $329B
  CRC16_Table(  4) = $4624
  CRC16_Table(  5) = $57AD
  CRC16_Table(  6) = $6536
  CRC16_Table(  7) = $74BF
  
  CRC16_Table(  8) = $8C48
  CRC16_Table(  9) = $9DC1
  CRC16_Table( 10) = $AF5A
  CRC16_Table( 11) = $BED3
  CRC16_Table( 12) = $CA6C
  CRC16_Table( 13) = $DBE5
  CRC16_Table( 14) = $E97E
  CRC16_Table( 15) = $F8F7

  CRC16_Table( 16) = $1081
  CRC16_Table( 17) = $0108
  CRC16_Table( 18) = $3393
  CRC16_Table( 19) = $221A
  CRC16_Table( 20) = $56A5
  CRC16_Table( 21) = $472C
  CRC16_Table( 22) = $75B7
  CRC16_Table( 23) = $643E

  CRC16_Table( 24) = $9CC9
  CRC16_Table( 25) = $8D40
  CRC16_Table( 26) = $BFDB
  CRC16_Table( 27) = $AE52
  CRC16_Table( 29) = $DAED
  CRC16_Table( 29) = $CB64
  CRC16_Table( 30) = $F9FF
  CRC16_Table( 31) = $E876

  CRC16_Table( 32) = $2102
  CRC16_Table( 33) = $308B
  CRC16_Table( 34) = $0210
  CRC16_Table( 35) = $1399
  CRC16_Table( 36) = $6726
  CRC16_Table( 37) = $76AF
  CRC16_Table( 38) = $4434
  CRC16_Table( 39) = $55BD

  CRC16_Table( 40) = $AD4A
  CRC16_Table( 41) = $BCC3
  CRC16_Table( 42) = $8E58
  CRC16_Table( 43) = $9FD1
  CRC16_Table( 44) = $EB6E
  CRC16_Table( 45) = $FAE7
  CRC16_Table( 46) = $C87C
  CRC16_Table( 47) = $D9F5
  
  CRC16_Table( 48) = $3183
  CRC16_Table( 49) = $200A
  CRC16_Table( 50) = $1291
  CRC16_Table( 51) = $0318
  CRC16_Table( 52) = $77A7
  CRC16_Table( 53) = $662E
  CRC16_Table( 54) = $54B5
  CRC16_Table( 55) = $453C
  
  CRC16_Table( 56) = $BDCB
  CRC16_Table( 57) = $AC42
  CRC16_Table( 58) = $9ED9
  CRC16_Table( 59) = $8F50
  CRC16_Table( 60) = $FBEF
  CRC16_Table( 61) = $EA66
  CRC16_Table( 62) = $D8FD
  CRC16_Table( 63) = $C974
  
  CRC16_Table( 64) = $4204
  CRC16_Table( 65) = $538D
  CRC16_Table( 66) = $6116
  CRC16_Table( 67) = $709F
  CRC16_Table( 68) = $0420
  CRC16_Table( 69) = $15A9
  CRC16_Table( 70) = $2732
  CRC16_Table( 71) = $36BB
  
  CRC16_Table( 72) = $CE4C
  CRC16_Table( 73) = $DFC5
  CRC16_Table( 74) = $ED5E
  CRC16_Table( 75) = $FCD7
  CRC16_Table( 76) = $8868
  CRC16_Table( 77) = $99E1
  CRC16_Table( 78) = $AB7A
  CRC16_Table( 79) = $BAF3
  
  CRC16_Table( 80) = $5285
  CRC16_Table( 81) = $430C
  CRC16_Table( 82) = $7197
  CRC16_Table( 83) = $601E
  CRC16_Table( 84) = $14A1
  CRC16_Table( 85) = $0528
  CRC16_Table( 86) = $37B3
  CRC16_Table( 87) = $263A
  
  CRC16_Table( 88) = $DECD
  CRC16_Table( 89) = $CF44
  CRC16_Table( 90) = $FDDF
  CRC16_Table( 91) = $EC56
  CRC16_Table( 92) = $98E9
  CRC16_Table( 93) = $8960
  CRC16_Table( 94) = $BBFB
  CRC16_Table( 95) = $AA72
  
  CRC16_Table( 96) = $6306
  CRC16_Table( 97) = $728F
  CRC16_Table( 98) = $4014
  CRC16_Table( 99) = $519D
  CRC16_Table(100) = $2522
  CRC16_Table(101) = $34AB
  CRC16_Table(102) = $0630
  CRC16_Table(103) = $17B9
  
  CRC16_Table(104) = $EF4E
  CRC16_Table(105) = $FEC7
  CRC16_Table(106) = $CC5C
  CRC16_Table(107) = $DDD5
  CRC16_Table(108) = $A96A
  CRC16_Table(109) = $B8E3
  CRC16_Table(110) = $8A78
  CRC16_Table(111) = $9BF1
  
  CRC16_Table(112) = $7387
  CRC16_Table(113) = $620E
  CRC16_Table(114) = $5095
  CRC16_Table(115) = $411C
  CRC16_Table(116) = $35A3
  CRC16_Table(117) = $242A
  CRC16_Table(118) = $16B1
  CRC16_Table(119) = $0738
  
  CRC16_Table(120) = $FFCF
  CRC16_Table(121) = $EE46
  CRC16_Table(122) = $DCDD
  CRC16_Table(123) = $CD54
  CRC16_Table(124) = $B9EB
  CRC16_Table(125) = $A862
  CRC16_Table(126) = $9AF9
  CRC16_Table(127) = $8B70
  
  CRC16_Table(128) = $8408
  CRC16_Table(129) = $9581
  CRC16_Table(130) = $A71A
  CRC16_Table(131) = $B693
  CRC16_Table(132) = $C22C
  CRC16_Table(133) = $D3A5
  CRC16_Table(134) = $E13E
  CRC16_Table(135) = $F0B7
  
  CRC16_Table(136) = $0840
  CRC16_Table(137) = $19C9
  CRC16_Table(138) = $2B52
  CRC16_Table(139) = $3ADB
  CRC16_Table(140) = $4E64
  CRC16_Table(141) = $5FED
  CRC16_Table(142) = $6D76
  CRC16_Table(143) = $7CFF
  
  CRC16_Table(144) = $9489
  CRC16_Table(145) = $8500
  CRC16_Table(146) = $B79B
  CRC16_Table(147) = $A612
  CRC16_Table(148) = $D2AD
  CRC16_Table(149) = $C324
  CRC16_Table(150) = $F1BF
  CRC16_Table(151) = $E036
  
  CRC16_Table(152) = $18C1
  CRC16_Table(153) = $0948
  CRC16_Table(154) = $3BD3
  CRC16_Table(155) = $2A5A
  CRC16_Table(156) = $5EE5
  CRC16_Table(157) = $4F6C
  CRC16_Table(158) = $7DF7
  CRC16_Table(159) = $6C7E
  
  CRC16_Table(160) = $A50A
  CRC16_Table(161) = $B483
  CRC16_Table(162) = $8618
  CRC16_Table(163) = $9791
  CRC16_Table(164) = $E32E
  CRC16_Table(165) = $F2A7
  CRC16_Table(166) = $C03C
  CRC16_Table(167) = $D1B5
  
  CRC16_Table(168) = $2942
  CRC16_Table(169) = $38CB
  CRC16_Table(170) = $0A50
  CRC16_Table(171) = $1BD9
  CRC16_Table(172) = $6F66
  CRC16_Table(173) = $7EEF
  CRC16_Table(174) = $4C74
  CRC16_Table(175) = $5DFD
  
  CRC16_Table(176) = $B58B
  CRC16_Table(177) = $A402
  CRC16_Table(178) = $9699
  CRC16_Table(179) = $8710
  CRC16_Table(180) = $F3AF
  CRC16_Table(181) = $E226
  CRC16_Table(182) = $D0BD
  CRC16_Table(183) = $C134
  
  CRC16_Table(184) = $39C3
  CRC16_Table(185) = $284A
  CRC16_Table(186) = $1AD1
  CRC16_Table(187) = $0B58
  CRC16_Table(188) = $7FE7
  CRC16_Table(189) = $6E6E
  CRC16_Table(190) = $5CF5
  CRC16_Table(191) = $4D7C
  
  CRC16_Table(192) = $C60C
  CRC16_Table(193) = $D785
  CRC16_Table(194) = $E51E
  CRC16_Table(195) = $F497
  CRC16_Table(196) = $8028
  CRC16_Table(197) = $91A1
  CRC16_Table(198) = $A33A
  CRC16_Table(199) = $B2B3
  
  CRC16_Table(200) = $4A44
  CRC16_Table(201) = $5BCD
  CRC16_Table(202) = $6956
  CRC16_Table(203) = $78DF
  CRC16_Table(204) = $0C60
  CRC16_Table(205) = $1DE9
  CRC16_Table(206) = $2F72
  CRC16_Table(207) = $3EFB
  
  CRC16_Table(208) = $D68D
  CRC16_Table(209) = $C704
  CRC16_Table(210) = $F59F
  CRC16_Table(211) = $E416
  CRC16_Table(212) = $90A9
  CRC16_Table(213) = $8120
  CRC16_Table(214) = $B3BB
  CRC16_Table(215) = $A232
  
  CRC16_Table(216) = $5AC5
  CRC16_Table(217) = $4B4C
  CRC16_Table(218) = $79D7
  CRC16_Table(219) = $685E
  CRC16_Table(220) = $1CE1
  CRC16_Table(221) = $0D68
  CRC16_Table(222) = $3FF3
  CRC16_Table(223) = $2E7A
  
  CRC16_Table(224) = $E70E
  CRC16_Table(225) = $F687
  CRC16_Table(226) = $C41C
  CRC16_Table(227) = $D595
  CRC16_Table(228) = $A12A
  CRC16_Table(229) = $B0A3
  CRC16_Table(230) = $8238
  CRC16_Table(231) = $93B1
  
  CRC16_Table(232) = $6B46
  CRC16_Table(233) = $7ACF
  CRC16_Table(234) = $4854
  CRC16_Table(235) = $59DD
  CRC16_Table(236) = $2D62
  CRC16_Table(237) = $3CEB
  CRC16_Table(238) = $0E70
  CRC16_Table(239) = $1FF9
  
  CRC16_Table(240) = $F78F
  CRC16_Table(241) = $E606
  CRC16_Table(242) = $D49D
  CRC16_Table(243) = $C514
  CRC16_Table(244) = $B1AB
  CRC16_Table(245) = $A022
  CRC16_Table(246) = $92B9
  CRC16_Table(247) = $8330
  
  CRC16_Table(248) = $7BC7
  CRC16_Table(249) = $6A4E
  CRC16_Table(250) = $58D5
  CRC16_Table(251) = $495C
  CRC16_Table(252) = $3DE3
  CRC16_Table(253) = $2C6A
  CRC16_Table(254) = $1EF1
  CRC16_Table(255) = $0F78
EndProcedure

Procedure CRC16(StartAddress, Size)
  For i = 0 To Size-1
    CRC16_Value = (CRC16_Value >> 8) ! CRC16_Table(PeekB(StartAddress+i) ! (CRC16_Value & $FF))
  Next
  ProcedureReturn CRC16_Value
EndProcedure

InitCRC16()

test1$ = "M"
test2$ = "T"
test3$ = "THE"
test4$ = "THE,QUICK,BROWN,FOX,0123456789"

answer1 = CRC16(@test1$, Len(test1$))
answer2 = CRC16(@test2$, Len(test2$))
answer3 = CRC16(@test3$, Len(test3$))
answer4 = CRC16(@test4$, Len(test4$))

text$ = "Answers: $"
text$ + Hex(answer1)+" $"
text$ + Hex(answer2)+" $"
text$ + Hex(answer3)+" $"
text$ + Hex(answer4)+" "
text$ + Chr(10)
text$ + "Expected: $99E1 $14A1 $7D8D $7DC5"

MessageRequester("CRC16 Test", text$)
Now, the problem I have is that the output should give the answers $99E1, $14A1, $7D8D and $7DC5 (which it does if it is compiled under C). Under Purebasic I get the answers $99E1, $14A1, $7D8D and an erroneous $841.

I suspect that this has something to do with me not using unsigned short variables since there isn't really any equivalent in PB.

Thanks in advance!

Kind regards,

Francis.
Dr. Dri
Enthusiast
Enthusiast
Posts: 243
Joined: Sat Aug 23, 2003 6:45 pm

Post by Dr. Dri »

i don't know CRC16 but look at this CRC32 code... I think that the table can be computed... instead of taking 512 bytes of memory in your exe file...
http://www.purebasic.fr/english/viewtopic.php?t=18296

however, try this code ;)

Code: Select all

Structure Bytes
  b.b[0]
EndStructure

Structure Words
  w.w[0]
EndStructure
; 
; Macro HiByte(Byte)
;   ((Byte >> 8) & $FF)
; EndMacro
; 
; Macro LoByte(Byte)
;   (Byte & $FF)
; EndMacro

Procedure.w CRC16(*MemoryID.Bytes, Length.l)
  Protected CRC.w, i.l, *Table.Words
  
  *Table = ?CRC16_Table
  
  While i < Length
    CRC = HiByte(CRC) ! *Table\w[*MemoryID\b[i] ! LoByte(CRC) & $FF]
    i + 1
  Wend
  
ProcedureReturn CRC
EndProcedure

DataSection
  CRC16_Table:
  Data.w $0000, $1189, $2312, $329B, $4624, $57AD, $6536, $74BF
  Data.w $8C48, $9DC1, $AF5A, $BED3, $CA6C, $DBE5, $E97E, $F8F7
  Data.w $1081, $0108, $3393, $221A, $56A5, $472C, $75B7, $643E
  Data.w $9CC9, $8D40, $BFDB, $AE52, $DAED, $CB64, $F9FF, $E876
  Data.w $2102, $308B, $0210, $1399, $6726, $76AF, $4434, $55BD
  Data.w $AD4A, $BCC3, $8E58, $9FD1, $EB6E, $FAE7, $C87C, $D9F5
  Data.w $3183, $200A, $1291, $0318, $77A7, $662E, $54B5, $453C
  Data.w $BDCB, $AC42, $9ED9, $8F50, $FBEF, $EA66, $D8FD, $C974
  Data.w $4204, $538D, $6116, $709F, $0420, $15A9, $2732, $36BB
  Data.w $CE4C, $DFC5, $ED5E, $FCD7, $8868, $99E1, $AB7A, $BAF3
  Data.w $5285, $430C, $7197, $601E, $14A1, $0528, $37B3, $263A
  Data.w $DECD, $CF44, $FDDF, $EC56, $98E9, $8960, $BBFB, $AA72
  Data.w $6306, $728F, $4014, $519D, $2522, $34AB, $0630, $17B9
  Data.w $EF4E, $FEC7, $CC5C, $DDD5, $A96A, $B8E3, $8A78, $9BF1
  Data.w $7387, $620E, $5095, $411C, $35A3, $242A, $16B1, $0738
  Data.w $FFCF, $EE46, $DCDD, $CD54, $B9EB, $A862, $9AF9, $8B70
  Data.w $8408, $9581, $A71A, $B693, $C22C, $D3A5, $E13E, $F0B7
  Data.w $0840, $19C9, $2B52, $3ADB, $4E64, $5FED, $6D76, $7CFF
  Data.w $9489, $8500, $B79B, $A612, $D2AD, $C324, $F1BF, $E036
  Data.w $18C1, $0948, $3BD3, $2A5A, $5EE5, $4F6C, $7DF7, $6C7E
  Data.w $A50A, $B483, $8618, $9791, $E32E, $F2A7, $C03C, $D1B5
  Data.w $2942, $38CB, $0A50, $1BD9, $6F66, $7EEF, $4C74, $5DFD
  Data.w $B58B, $A402, $9699, $8710, $F3AF, $E226, $D0BD, $C134
  Data.w $39C3, $284A, $1AD1, $0B58, $7FE7, $6E6E, $5CF5, $4D7C
  Data.w $C60C, $D785, $E51E, $F497, $8028, $91A1, $A33A, $B2B3
  Data.w $4A44, $5BCD, $6956, $78DF, $0C60, $1DE9, $2F72, $3EFB
  Data.w $D68D, $C704, $F59F, $E416, $90A9, $8120, $B3BB, $A232
  Data.w $5AC5, $4B4C, $79D7, $685E, $1CE1, $0D68, $3FF3, $2E7A
  Data.w $E70E, $F687, $C41C, $D595, $A12A, $B0A3, $8238, $93B1
  Data.w $6B46, $7ACF, $4854, $59DD, $2D62, $3CEB, $0E70, $1FF9
  Data.w $F78F, $E606, $D49D, $C514, $B1AB, $A022, $92B9, $8330
  Data.w $7BC7, $6A4E, $58D5, $495C, $3DE3, $2C6A, $1EF1, $0F78
EndDataSection

;test

t1.b = 'M'
t2.b = 'T'
t3.s = "THE"
t4.s = "THE,QUICK,BROWN,FOX,0123456789"

Debug "Answers"
Debug Hex(CRC16(@t1,  1) & $FFFF)
Debug Hex(CRC16(@t2,  1) & $FFFF)
Debug Hex(CRC16(@t3,  3) & $FFFF)
Debug Hex(CRC16(@t4, 30) & $FFFF)

Debug "Expected"
Debug "99E1"
Debug "14A1"
Debug "7D8D"
Debug "7DC5"
Dri ;)
Last edited by Dr. Dri on Thu Aug 24, 2006 11:38 pm, edited 1 time in total.
User avatar
Dreamland Fantasy
Enthusiast
Enthusiast
Posts: 335
Joined: Fri Jun 11, 2004 9:35 pm
Location: Glasgow, UK
Contact:

Post by Dreamland Fantasy »

Nice one! 8)

Thanks! :D

Kind regards,

Francis.
Dr. Dri
Enthusiast
Enthusiast
Posts: 243
Joined: Sat Aug 23, 2003 6:45 pm

Post by Dr. Dri »

no more datasection... i found how to create the CRC16 table...

Code: Select all

EnableExplicit

Structure Bytes
  b.b[0]
EndStructure

#CRC_BufferLength = 4096 ;default PB file buffer size

Global Dim CRC16_Table.w($FF)
Global Dim CRC32_Table.l($FF)

Global CRC16_TableComputed.l
Global CRC32_TableComputed.l

Procedure CRC16_MakeTable()
  Protected i.l, j.l, k.l, crc.w
  
  For i = 0 To 255
    k = i << 1
    crc = 0
    
    For j = 1 To 8
      !SHR dword [p.v_k], 1 ;k >>> 1
      
      If (crc ! k) & $0001
        !SHR dword [p.v_crc], 1 ;crc >>> 1
        crc ! $8408
      Else
        !SHR dword [p.v_crc], 1 ;crc >>> 1
      EndIf
    Next j
    
    CRC16_Table(i) = crc
  Next i
  
  CRC16_TableComputed = #True
EndProcedure 

Procedure CRC32_MakeTable()
  Protected i.l, j.l, crc.l
 
  For i = 0 To $FF
    crc = i
   
    For j = 1 To 8
   
      If crc & 1
        crc = $EDB88320 ! ((crc >> 1) & $7FFFFFFF)
      Else
        crc = (crc >> 1) & $7FFFFFFF
      EndIf
     
    Next j
   
    CRC32_Table(i) = crc
  Next i
 
  CRC32_TableComputed = #True
EndProcedure

Procedure.w CRC16_Update(crc.w, *buffer.Bytes, Length.l)
  Protected i.l
 
  If Not CRC16_TableComputed
    CRC16_MakeTable()
  EndIf
 
  While i < Length
    crc = HiByte(crc) ! CRC16_Table(LoByte(crc) ! *buffer\b[i] & $FF)
    i + 1
  Wend
 
  ProcedureReturn crc
EndProcedure

Procedure.l CRC32_Update(crc.l, *buffer.Bytes, Length.l)
  Protected i.l
 
  If Not CRC32_TableComputed
    CRC32_MakeTable()
  EndIf
 
  While i < Length
    crc = CRC32_Table((crc ! *buffer\b[i]) & $FF) ! ((crc >> 8) & $00FFFFFF)
    i + 1
  Wend
 
  ProcedureReturn crc
EndProcedure

Procedure.w CRC16_Fingerprint(*buffer, Length.l)
  ProcedureReturn CRC16_Update($0000, *buffer, Length)
EndProcedure

Procedure.l CRC32_Fingerprint(*buffer, Length.l)
  ProcedureReturn ~CRC32_Update($FFFFFFFF, *buffer, Length)
EndProcedure

Procedure.w CRC16_FileFingerprint(Filename.s)
  Protected crc.l, File.l, Buffer.l, Offset.q, Length.q
 
  File = ReadFile(#PB_Any, Filename)
  
  If File
    Buffer = AllocateMemory(#CRC_BufferLength)
   
    If Buffer
      crc = $0000
      Length = Lof(File)
     
      While (Length - Offset) > #CRC_BufferLength
        ReadData(File, Buffer, #CRC_BufferLength)
        crc = CRC16_Update(crc, Buffer, #CRC_BufferLength)
        Offset + #CRC_BufferLength
      Wend
     
      If Length > Offset
        Length - Offset
        ReadData(File, Buffer, Length)
        crc = CRC16_Update(crc, Buffer, Length)
      EndIf
     
      FreeMemory(Buffer)
    EndIf
   
    CloseFile(File)
  EndIf
 
  ProcedureReturn crc
EndProcedure

Procedure.l CRC32_FileFingerprint(Filename.s)
  Protected crc.l, File.l, Buffer.l, Offset.q, Length.q
 
  File = ReadFile(#PB_Any, Filename)
  If File
    Buffer = AllocateMemory(#CRC_BufferLength)
   
    If Buffer
      Length = Lof(File)
      crc = $FFFFFFFF
     
      While (Length - Offset) > #CRC_BufferLength
        ReadData(File, Buffer, #CRC_BufferLength)
        crc = CRC32_Update(crc, Buffer, #CRC_BufferLength)
        Offset + #CRC_BufferLength
      Wend
     
      If Length > Offset
        Length - Offset
        ReadData(File, Buffer, Length)
        crc = CRC32_Update(crc, Buffer, Length)
      EndIf
     
      FreeMemory(Buffer)
    EndIf
   
    CloseFile(File)
  EndIf
 
  ProcedureReturn ~crc
EndProcedure
Dri ;)
Last edited by Dr. Dri on Sat Dec 16, 2006 9:56 pm, edited 2 times in total.
User avatar
Dreamland Fantasy
Enthusiast
Enthusiast
Posts: 335
Joined: Fri Jun 11, 2004 9:35 pm
Location: Glasgow, UK
Contact:

Post by Dreamland Fantasy »

Again, nice one!

I'll need to give that a try when I get home.

Kind regards,

Francis.
User avatar
Dreamland Fantasy
Enthusiast
Enthusiast
Posts: 335
Joined: Fri Jun 11, 2004 9:35 pm
Location: Glasgow, UK
Contact:

Post by Dreamland Fantasy »

Hi Dr. Dri,

I'm wondering if you could help me again. :wink:

I have a problem using the CRC16 routine with the following byte sequence:

Code: Select all

$05, $FA, $28, $81, $02, $00, $08, $94, $32
Now, the first byte ( $05 ) is the length of the data fields within this byte sequence. The second byte ( $FA ) is the bitwise logical NOT of the length of the data fields. This is used to confirm that there has been no data corruption in the first two bytes.

The next bit is where I am having problems.

The next five bytes ( $28, $81, $02, $00, $08 ) is our data fields and the last two bytes is the CRC16 checksum value of the data fields which should be $3294.

The problem I have is when I do a CRC16 on the five data field bytes it gives me values different from the expected checksum.

Hopefully that makes sense! :roll:

Thanks in advance!

Kind regards,

Francis.
Dr. Dri
Enthusiast
Enthusiast
Posts: 243
Joined: Sat Aug 23, 2003 6:45 pm

Post by Dr. Dri »

i've found a bug when i tried to test your 5 byte sequence

i replaced crc = HiByte(crc) ! CRC16_Table(LoByte(crc) ! *buffer\b)
by crc = HiByte(crc) ! CRC16_Table(LoByte(crc) ! *buffer\b & $FF)
(array out of bound...)

Once fixed, i made this little code to see your problem but i get the right crc...

Code: Select all

DataSection
  dat:
  Data.b $28, $81, $02, $00, $08
EndDataSection

Debug Hex( CRC16_Fingerprint(?dat, 5) )
Maybe your problem is in your code, i can see that with you

[edit]
is that what you're trying to do ???

Code: Select all

Procedure.l CheckSequence(*Buffer.Bytes)
  Protected Valid.l, Size.b, CRC16.w
  
  Size = *Buffer\b[0]
  
  If Size = ~*Buffer\b[1]
    CRC16 = MakeWord(*Buffer\b[Size & $FF + 3], *Buffer\b[Size & $FF + 2])
    
    If CRC16 = CRC16_Fingerprint(*Buffer + 2, Size & $FF)
      Valid = #True
    EndIf
  EndIf
  
  ProcedureReturn Valid
EndProcedure

DataSection
  dat:
  Data.b $05, $FA, $28, $81, $02, $00, $08, $94, $32
EndDataSection

Debug CheckSequence(?dat)
Dri
User avatar
Dreamland Fantasy
Enthusiast
Enthusiast
Posts: 335
Joined: Fri Jun 11, 2004 9:35 pm
Location: Glasgow, UK
Contact:

Post by Dreamland Fantasy »

Hi Dri,

Thanks ever so much for all of your help. I've eventually managed to get the correct CRC checksum, but as you say the problem is down to the way I was coding my routines.

I ended up writing my own (now working) test code, purely because I can understand it easier than what you done :wink: :

Code: Select all

Define.l *MyBuffer
Define.b PacketLength
Define.w StoredCRC, CalculatedCRC

;- Simulate data packet

*MyBuffer = AllocateMemory(9)

PokeB(*MyBuffer+0, $05)
PokeB(*MyBuffer+1, $FA)
PokeB(*MyBuffer+2, $28)
PokeB(*MyBuffer+3, $81)
PokeB(*MyBuffer+4, $02)
PokeB(*MyBuffer+5, $00)
PokeB(*MyBuffer+6, $08)
PokeB(*MyBuffer+7, $94)
PokeB(*MyBuffer+8, $32)

;- Extract data

PacketLength = PeekB(*MyBuffer)
StoredCRC = PeekW(*MyBuffer + PacketLength + 2)
CalculatedCRC = CRC16_Fingerprint(*MyBuffer+2, PacketLength)

;- Test data integrity

If PacketLength = ~PeekB(*MyBuffer+1)
  Debug "Packet length integrity OK ("+Str(PacketLength)+" bytes)"
  If StoredCRC = CalculatedCRC
    Debug "CRC checksum OK ($"+Hex(CalculatedCRC)+")"
  Else
    Debug "CRC checksum error!"
  EndIf
Else
  Debug "Packet length integrity error!"
EndIf
Kind regards,

Francis.
Dr. Dri
Enthusiast
Enthusiast
Posts: 243
Joined: Sat Aug 23, 2003 6:45 pm

Post by Dr. Dri »

Dreamland Fantasy wrote:I ended up writing my own (now working) test code, purely because I can understand it easier than what you done :wink: :
If there is something you don't understand, i can explain it to you... I didn't put any comment because i'm too lazy so just tell me what you don't understand

Dri :)
User avatar
Dreamland Fantasy
Enthusiast
Enthusiast
Posts: 335
Joined: Fri Jun 11, 2004 9:35 pm
Location: Glasgow, UK
Contact:

Post by Dreamland Fantasy »

Hi Dr Dri,

I've managed to get my head around most of the code that you have done now that I have had a chance to digest it (and refer to the PB documenation).

The only thing I don't quite understand is your use of structures, although to be honest I've never really delved into this topic. It is something that I will need to look into for my current project since it should make handling all of the data a bit easier for me. It's really just a case of me needing to read the manual fully.

Kind regards,

Francis.
Dr. Dri
Enthusiast
Enthusiast
Posts: 243
Joined: Sat Aug 23, 2003 6:45 pm

Post by Dr. Dri »

you're probably talking about the "Bytes" structure. maybe you will understand it if you read this
http://www.purebasic.fr/english/viewtopic.php?t=16435

I use it as a pointer to several bytes.
if i have a pointer *ptr.Bytes pointing to a memory buffer

*ptr.Bytes = myBuffer

then

*ptr\b[2] = 5

is equivalent to

PokeB(myBuffer + 2, 5)

and

a = *ptr\b[19]

is like

a = PeekB(myBuffer + 19)

but this way it is a lot faster ;)

Dri
User avatar
Dreamland Fantasy
Enthusiast
Enthusiast
Posts: 335
Joined: Fri Jun 11, 2004 9:35 pm
Location: Glasgow, UK
Contact:

Post by Dreamland Fantasy »

Ah, I see. That's a much better way of doing it. :D

I'm currently using a lot of peeks and pokes in my program at present, but I'll be changing that soon! ;)

Kind regards,

Francis.
RichardL
Enthusiast
Enthusiast
Posts: 532
Joined: Sat Sep 11, 2004 11:54 am
Location: UK

Post by RichardL »

Here is a routine I wrote 8 years ago in GFA basic, hastily copied into PB... no claims for originality, style or speed... but it seems to work!

Code: Select all


Procedure MMCRC16Memory(*MEMStart,Len.w)                 ;- Calculate 16 bit CRC over specified memory range
  ;
  Protected P.w,k.w,*pointc,MyCRC.l,*MEMEnd
  ;
  *MEMEnd = *MEMStart+Len.w-1
  MyCRC.l = 0                        
  *pointc = *MEMStart
  While *pointc <= *MEMEnd
    P.w =PeekW(*pointc) & $FF          
    For k.w = 1 To 8                  
      If (P.w ! MyCRC.l) & 1 = 1
        MyCRC.l >> 1
        MyCRC.l ! $8408
      Else
        MyCRC.l >> 1
      EndIf
      P.w >> 1
    Next 
    *pointc + 1
  Wend
  ProcedureReturn MyCRC.l
EndProcedure


k$="THE,QUICK,BROWN,FOX,0123456789"

CRC=MMCRC16Memory(@k$,1);Len(k$))
Debug Hex(CRC)

Use at your own risk :D
Post Reply