FUNCTION_BLOCK "CrcGen" TITLE = 'CRC_GEN' { S7_Optimized_Access := 'FALSE' } AUTHOR : hugo FAMILY : LOGIC NAME : CRCGEN VERSION : 2.0 // //CRC_GEN generates a CRC checksum from a block of data and returns the checksum in a DWORD to be connected to the data for transmission. //the CRC Polynom is specified with the config variable PN and the length of the Polynom is specified by PL //A Polynom x4 + X + 1 is represented by 0011 with length 4, the highest order bit is not specified at all.. //The input data is an array of byte of any size, the function is called by CRC_GEN(ADR(array),SIZEOF(array), ....). // //uses: REVERSE (FC310) // REFLECT (FC426) VAR_INPUT PT : Pointer; _PT { S7_HMI_Accessible := 'False'; S7_HMI_Visible := 'False'} AT PT : Struct DBNr { S7_HMI_Accessible := 'False'; S7_HMI_Visible := 'False'} : Word; Adr { S7_HMI_Accessible := 'False'; S7_HMI_Visible := 'False'} : DWord; END_STRUCT; SIZE : Int; PL : Int; PN : DWord; INIT : DWord; REV_IN : Bool; REV_OUT : Bool; XOR_OUT : DWord; END_VAR VAR_OUTPUT CRC_GEN : DWord; _CRC_GEN { S7_HMI_Accessible := 'False'; S7_HMI_Visible := 'False'} AT CRC_GEN : Array[0..31] of Bool; END_VAR VAR_TEMP pos : Int; shift : Int; dx : Byte; _dx AT dx : Array[0..7] of Bool; bits : Int; rTEST_DB : Int; Adr : Int; DB_LENGTH : Word; WRITE_PROT : Bool; END_VAR BEGIN (*################################################################################################# Copyright (c) Fondium Singen GmbH ### Änderungshistorie ### Datum: Version: Bearbeiter: Beschreibung: 04.03.2021 0.0 St. Maier Neuerstellung #################################################################################################*) (*################################################################################################# Beschreibung: Die Funktion generiert eine CRC-Checksumme aus einen beliebig großen Array of Byte. Beim Aufruf wird der Funktion ein Pointer auf das zu bearbeitende Array und dessen Größe in Bytes übergeben. Das Polynom kann ein beliebiges POLYNOM bis maximal 32 Bit Länge sein. Ein Polynom X³ + X² + 1 wird mit 101 dargestellt (1*X³ + 1*X² + 0*X¹ + 1* X⁰). Das höchstwertige Bit, in diesem Fall 1*X³ wird dabei im Polynom nicht angegeben den es ist immer eins. Es können Polynome bis X³² (CRC 32) verarbeitet werden. Durch den Wert INIT kann dem CR eine Startwert übergeben werden, üblich sind hier 0000 und FFFF. Der zu verwendende Startwert ist der in der Literatur übliche „Direct Initial Value“. Der Eingan XOR_OUT legt fest mit welcher Bitfolge die Checksumme am Ende mit XOR verknüpft wird. Die Eingänge REV_IN und REV_OUT legen die Bitfolge der Daten Fest. Wenn REV_IN = TRUE wird jedes Byte mit LSB beginnend verarbeitet, REV_IN = FALSE wird jeweils mit MSB begonnen. REV_OUT=TRUE dreht entsprechend die Bitfolge der Checksumme um. Der Bautein benötigt eine Mindestlänge der zu verarbeitenden Daten von 4 Bytes, und ist nach oben nur durch die maximale Array Größe begrenzt. Die weiter unten folgende CRC Tabelle gibt nähere Auskunft über gebräuchliche CRC's und deren Setup Daten für CrcGen. Aufgrund der Vielzahl von möglichen und auch gebräuchlichen CRC's ist es uns nicht möglich eine vollständige Liste aufzuführen. Für weitergehende Recherchen ist die Webseite http://regregex.bbcmicro.net/crc-catalogue.htm zu empfehlen. Online Berechnungen zum testen sind mit folgendem Java Tool möglich: http://zorc.breitbandkatze.de/crc.html #################################################################################################*) (* Datenbaustein Testen *) #rTEST_DB := TEST_DB(DB_NUMBER := #_PT.DBNr , DB_LENGTH => #DB_LENGTH , WRITE_PROT => #WRITE_PROT ); // Ende wenn Test-DB <> 0 = Fehler IF #rTEST_DB <> 0 THEN RETURN; END_IF; // Ende wenn DB zu klein IF WORD_TO_INT(#DB_LENGTH) / 1 < #SIZE THEN RETURN; END_IF; #Adr := DWORD_TO_INT(SHR(IN := SHL(IN := #_PT.Adr, N := 8), N := 11)); // align polygon #shift := 32 - #PL; #PN := SHL(IN := #PN, N := #shift); (* load first 4 bytes into register minimum message size is 4 bytes for smaller messages fill with 0#s at the beginning*) FOR #pos := 0 TO 3 DO IF #REV_IN THEN #CRC_GEN := SHL(IN := #CRC_GEN, N := 8) OR "Reverse"(WORD_TO_BLOCK_DB(#_PT.DBNr).DB(#Adr + #pos)); ELSE #CRC_GEN := SHL(IN := #CRC_GEN, N := 8) OR WORD_TO_BLOCK_DB(#_PT.DBNr).DB(#Adr + #pos); END_IF; END_FOR; #pos := 4; // XOR with #INIT value #CRC_GEN := #CRC_GEN XOR SHL(IN := #INIT, N := #shift); // calculate CRC FOR each byte WHILE #pos < #SIZE DO IF #REV_IN THEN #dx := "Reverse"(WORD_TO_BLOCK_DB(#_PT.DBNr).DB(#Adr + #pos)); ELSE #dx := WORD_TO_BLOCK_DB(#_PT.DBNr).DB(#Adr + #pos); END_IF; #pos := #pos + 1; // crc calculation FOR one byte FOR #bits := 0 TO 7 DO IF #_CRC_GEN[7] THEN #CRC_GEN := (SHL(IN := #CRC_GEN, N := 1) OR BOOL_TO_DWORD(#_dx[7])) XOR #PN; ELSE #CRC_GEN := SHL(IN := #CRC_GEN, N := 1) OR BOOL_TO_DWORD(#_dx[7]); END_IF; #dx := SHL(IN := #dx, N := 1); END_FOR; END_WHILE; // all bytes are processed, need TO finish the registers 32 bits FOR #bits := 0 TO 31 DO IF #_CRC_GEN[7] THEN #CRC_GEN := (SHL(IN := #CRC_GEN, N := 1) OR BOOL_TO_DWORD(#_dx[7])) XOR #PN; ELSE #CRC_GEN := SHL(IN := #CRC_GEN, N := 1) OR BOOL_TO_DWORD(#_dx[7]); END_IF; END_FOR; // final XOR #CRC_GEN := SHR(IN := #CRC_GEN, N := #shift) XOR #XOR_OUT; // "Reverse" the crc_out put IF necessary IF #REV_OUT THEN #CRC_GEN := "Reflect"(I_D := #CRC_GEN, I_L := #PL); END_IF; (* typical crc polynoms CRC-4-ITU x4 + x + 1 (ITU G.704, p. 12) 0x3 or 0xC (0x9) CRC-5-ITU x5 + x4 + x2 + 1 (ITU G.704, p. 9) 0x15 or 0x15 (0x0B) Bluetooth CRC-5-USB x5 + x2 + 1 (use: USB token packets) 0x05 or 0x14 (0x9) CRC-6-ITU x6 + x + 1 (ITU G.704, p. 3) 0x03 or 0x30 (0x21) CRC-7 x7 + x3 + 1 (use: telecom systems, MMC) 0x09 or 0x48 (0x11) CRC-8-ATM x8 + x2 + x + 1 (use: ATM HEC) 0x07 or 0xE0 (0xC1) CRC-8-CCITT x8 + x7 + x3 + x2 + 1 (use: 1-Wire bus) 0x8D or 0xB1 (0x63) CRC-8-Dallas/Maxim x8 + x5 + x4 + 1 (use: 1-Wire bus) 0x31 or 0x8C (0x19) CRC-8 x8 + x7 + x6 + x4 + x2 + 1 0xD5 or 0xAB (0x57) CRC-8-SAE J1850 x8 + x4 + x3 + x2 + 1 0x1D or 0xB8 CRC-10 x10 + x9 + x5 + x4 + x + 1 0x233 or 0x331 (0x263) CRC-12 x12 + x11 + x3 + x2 + x + 1 (use: telecom systems) 0x80F or 0xF01 (0xE03) CRC-15-CAN x15 + x14 + x10 + x8 + x7 + x4 + x3 + 1 0x4599 or 0x4CD1 (0x19A3) CRC-16-Fletcher Not a CRC; see Fletcher's checksum Used in Adler-32 A & B CRCs CRC-16-CCITT x16 + x12 + x5 + 1 (XMODEM,X.25, V.41, Bluetooth, PPP, IrDA; known as "CRC-CCITT") 0x1021 or 0x8408 (0x0811) CRC-16-IBM x16 + x15 + x2 + 1 (USB, many others; also known as "CRC-16") 0x8005 or 0xA001 (0x4003) CRC-24-Radix-64 x24 + x23 + x18 + x17 + x14 + x11 + x10 + x7 + x6 + x5 + x4 + x3 + x + 1 0x864CFB or 0xDF3261 (0xBE64C3) CRC-32-Adler Not a CRC; see Adler-32 See Adler-32 CRC-32-MPEG2 x32 + x26 + x23 + x22 + x16 + x12 + x11 + x10 + x8 + x7 + x5 + x4 + x2 + x + 1 0x04C11DB7 or 0xEDB88320 (0xDB710641) Also used in IEEE 802.3 CRC-32-IEEE 802.3 x32 + x26 + x23 + x22 + x16 + x12 + x11 + x10 + x8 + x7 + x5 + x4 + x2 + x + 1 (V.42) 0x04C11DB7 or 0xEDB88320 (0xDB710641) CRC-32C (Castagnoli) x32 + x28 + x27 + x26 + x25 + x23 + x22 + x20 + x19 + x18 + x14 + x13 + x11 + x10 + x9 + x8 + x6 + 1 0x1EDC6F41 or 0x82F63B78 (0x05EC76F1) CRC-64-ISO x64 + x4 + x3 + x + 1 (use: ISO 3309) 0x000000000000001B or 0xD800000000000000 (0xB000000000000001) CRC-64-ECMA-182 x64 + x62 + x57 + x55 + x54 + x53 + x52 + x47 + x46 + x45 + x40 + x39 + x38 + x37 + x35 + x33 + x32 + x31 + x29 + x27 + x24 + x23 + x22 + x21 + x19 + x17 + x13 + x12 + x10 + x9 + x7 + x4 + x + 1 (as described in ECMA-182 p.63) 0x42F0E1EBA9EA3693 or 0xC96C5795D7870F42 (0x92D8AF2BAF0E1E85) *) END_FUNCTION_BLOCK