CRC-16
Algorithm creator(s)
n/a
PB author(s)
Marc Sven Schulte, Mark Pruitt
Description
Very fast algorithm that creates a 16-bit checksum.
Note
Marc Sven Schulte's assembly implentation and Mark Pruitt's PB version are included.
Source
https://forum.powerbasic.com/forum/user-to-user-discussions/source-code/24576-crc-16-routines?t=23940
See also
n/a
Source Code
Download source code file crc16.bas (Right-click -> "Save as ...")
'#####################################################################################
'CRC16, by Marc Sven Schulte, 19th October 2003.
FUNCTION CRC16(BYVAL Address AS DWORD, _
BYVAL Length AS LONG, BYVAL Seed AS WORD) AS WORD
#REGISTER NONE
! MOV BX, Seed
! MOV ESI, Length
! CMP ESI, 0
! JZ QuitLoop
! MOV EDI, Address
! XOR EAX, EAX
NextByte:
! MOV AL, BL
! XOR AL, [EDI]
! MOV CX, CrcTable[2*EAX]
! SHR BX, 8
! XOR BX, CX
! INC EDI
! DEC ESI
! JNZ NextByte
QuitLoop:
! MOV FUNCTION, BX
EXIT FUNCTION
CrcTable:
! DW &H00000, &H0C0C1, &H0C181, &H00140, &H0C301, &H003C0, &H00280, &H0C241
! DW &H0C601, &H006C0, &H00780, &H0C741, &H00500, &H0C5C1, &H0C481, &H00440
! DW &H0CC01, &H00CC0, &H00D80, &H0CD41, &H00F00, &H0CFC1, &H0CE81, &H00E40
! DW &H00A00, &H0CAC1, &H0CB81, &H00B40, &H0C901, &H009C0, &H00880, &H0C841
! DW &H0D801, &H018C0, &H01980, &H0D941, &H01B00, &H0DBC1, &H0DA81, &H01A40
! DW &H01E00, &H0DEC1, &H0DF81, &H01F40, &H0DD01, &H01DC0, &H01C80, &H0DC41
! DW &H01400, &H0D4C1, &H0D581, &H01540, &H0D701, &H017C0, &H01680, &H0D641
! DW &H0D201, &H012C0, &H01380, &H0D341, &H01100, &H0D1C1, &H0D081, &H01040
! DW &H0F001, &H030C0, &H03180, &H0F141, &H03300, &H0F3C1, &H0F281, &H03240
! DW &H03600, &H0F6C1, &H0F781, &H03740, &H0F501, &H035C0, &H03480, &H0F441
! DW &H03C00, &H0FCC1, &H0FD81, &H03D40, &H0FF01, &H03FC0, &H03E80, &H0FE41
! DW &H0FA01, &H03AC0, &H03B80, &H0FB41, &H03900, &H0F9C1, &H0F881, &H03840
! DW &H02800, &H0E8C1, &H0E981, &H02940, &H0EB01, &H02BC0, &H02A80, &H0EA41
! DW &H0EE01, &H02EC0, &H02F80, &H0EF41, &H02D00, &H0EDC1, &H0EC81, &H02C40
! DW &H0E401, &H024C0, &H02580, &H0E541, &H02700, &H0E7C1, &H0E681, &H02640
! DW &H02200, &H0E2C1, &H0E381, &H02340, &H0E101, &H021C0, &H02080, &H0E041
! DW &H0A001, &H060C0, &H06180, &H0A141, &H06300, &H0A3C1, &H0A281, &H06240
! DW &H06600, &H0A6C1, &H0A781, &H06740, &H0A501, &H065C0, &H06480, &H0A441
! DW &H06C00, &H0ACC1, &H0AD81, &H06D40, &H0AF01, &H06FC0, &H06E80, &H0AE41
! DW &H0AA01, &H06AC0, &H06B80, &H0AB41, &H06900, &H0A9C1, &H0A881, &H06840
! DW &H07800, &H0B8C1, &H0B981, &H07940, &H0BB01, &H07BC0, &H07A80, &H0BA41
! DW &H0BE01, &H07EC0, &H07F80, &H0BF41, &H07D00, &H0BDC1, &H0BC81, &H07C40
! DW &H0B401, &H074C0, &H07580, &H0B541, &H07700, &H0B7C1, &H0B681, &H07640
! DW &H07200, &H0B2C1, &H0B381, &H07340, &H0B101, &H071C0, &H07080, &H0B041
! DW &H05000, &H090C1, &H09181, &H05140, &H09301, &H053C0, &H05280, &H09241
! DW &H09601, &H056C0, &H05780, &H09741, &H05500, &H095C1, &H09481, &H05440
! DW &H09C01, &H05CC0, &H05D80, &H09D41, &H05F00, &H09FC1, &H09E81, &H05E40
! DW &H05A00, &H09AC1, &H09B81, &H05B40, &H09901, &H059C0, &H05880, &H09841
! DW &H08801, &H048C0, &H04980, &H08941, &H04B00, &H08BC1, &H08A81, &H04A40
! DW &H04E00, &H08EC1, &H08F81, &H04F40, &H08D01, &H04DC0, &H04C80, &H08C41
! DW &H04400, &H084C1, &H08581, &H04540, &H08701, &H047C0, &H04680, &H08641
! DW &H08201, &H042C0, &H04380, &H08341, &H04100, &H081C1, &H08081, &H04040
END FUNCTION
FUNCTION PBMAIN() AS LONG
DIM buffer AS STRING, crc AS DWORD
buffer = "1234567890"
crc = CRC16(STRPTR(buffer), LEN(buffer), crc)
MSGBOX "CRC16: " & HEX$(crc, 4) & " (should be: C57A)"
END FUNCTION
'#####################################################################################
'**********************************************************************************************************************
' I needed these CRC-16 routines to calculate the CRC for each byte of data in a string, accumulate the value in
' CrcReg??, and then use the final value of CrcReg?? to calculte a final Block Check Character (two; one byte each).
' These may be useful to someone. Should be easy to modify. Kev Peel and Tom Hanlin (and possibly others) may
' remember helping me in translating some of these from C. Thanks again. Feel free to use/modify this code.
'
' - CRC-16 Routines
' - Create a unique CRC-16 lookup table by changing the values of c%(0) through c%(7)
' - Calculate CRC value by passing data one byte at a time to CalculateCRC16 as databyte? until all bytes are passed
' Can be used to calculate CRC16 for your transmit string, or to calculate the CRC16 of a received string
' Last two bytes of received string (for my purposes) are the Most Significant Byte and then Least Significant
' Byte of of the final Block Check Character - can be omitted if you don't need them.
' - Final BCC (Block Check Character) composed of two one byte pieces of data, BCC1?, and BCC2?
' Convert these to byte sized bit patterns with MKBYT$ before appending to end of string
'
'
'
'
'**********************************************************************************************************************
'create a 256 element look up table based on a unique mask/rule set
FUNCTION MakeLookUpTable () AS LONG
GLOBAL CrcReg??
GLOBAL table?? ()
LOCAL c% ()
LOCAL d$
LOCAL i&, j&, mask&
REDIM table??(0 TO 255)
REDIM c%(0 TO 7) 'these hex values create a unique look up table, change values to change the table
c%(0) = &h1001
c%(1) = &h2002
c%(2) = &h4004
c%(3) = &h8118
c%(4) = &h1221
c%(5) = &h2482
c%(6) = &h48A4
c%(7) = &h3AB8
FOR i& = 0 TO 255
table??(i&) = 0
mask& = &h0001
FOR j& = 0 TO 7
IF(i& AND mask&) THEN table??(i&) = table??(i&) XOR c%(j&)
SHIFT LEFT mask&, 1
NEXT j&
d$ = HEX$(table??(i&))
NEXT i&
FUNCTION = 0
END FUNCTION
'*************************************************************************************************************
FUNCTION ResetCRC () AS LONG
CrcReg?? = 0 'reset CrcReg?? before calculating new string
END FUNCTION
'*************************************************************************************************************
' calculate the CRC-16; call this routine until all bytes of data have been passed to it, then call GetBCC1BisyncByte
FUNCTION CalculateCrc16 (databyte?) AS LONG
LOCAL s??, CrcCopy??
CrcCopy?? = CrcReg?? 'make a copy because SHIFT changes the value of CrcReg??
s?? = 0
SHIFT RIGHT CrcCopy??, 8
s?? = (databyte? AND &h00ff) XOR (CrcCopy?? AND &h00ff) 'databye? is one byte of data extracted from data string
SHIFT LEFT CrcReg??, 8
CrcReg?? = (CrcReg?? XOR table??(s??))
END FUNCTION
'********************************************************************************************************************
'get first block check character (MSB(yte))
FUNCTION GetBCC1BisyncByte () AS LONG
STATIC BCC1?
LOCAL a$, CRC??
CRC?? = CrcReg?? 'make a copy of the value of CrcReg??
SHIFT RIGHT CRC??, 8
BCC1? = NOT (CRC?? AND 255)
CALL GetBCC2BisyncByte (BCC1?)
END FUNCTION
'******************************************************************************************************************************
'get second block check character (LSB(yte))
FUNCTION GetBCC2BisyncByte (BCC1?) AS LONG
STATIC BCC2?
BCC2? = NOT(CrcReg?? AND 255)
blockcheck$ = MKBYT$(BCC1?) + MKBYT$(BCC2?) 'blockcheck$ is a global variable declared elsewhere
END FUNCTION
' ********************************************************************************************************************
------------------
' Mark Pruitt
' markspruitt@yahoo.com
'#####################################################################################