NAME: CRC16
CREATOR: ?
PB AUTHOR: Marc Sven Schulte
DESCRIPTION: Very fast algorithm that creates a 16-bit checksum. Marc Sven Schulte's assembly implentation and Mark Pruitt's PB version are included.
SOURCE: http://www.powerbasic.com/support/forums/Forum7/HTML/001999.html
Viewing source from crc16.bas   7989 bytes   Last modified Wed, 20 September 2006

'#####################################################################################
'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

'#####################################################################################

Back to The Archives