CRC16 SML-Transport-Protokoll

23/02/2013 - 03:55 von Michael Schwimmer | Report spam
Hallo,
ich versuche seit ein paar Tagen verzweifelt, die Checksumme einer Smart
Meter SML_Message nach CCITT-CRC16 (DIN EN 62056-46) zu bestimmen
(Elektronischer Haushaltszàhler).

Laut Beschreibung des Protokolls wird die Checksumme folgendermaßen
bestimmt:

Algorithmus: CCITT-CRC16, x16 + x12 + x5 + 1, 0x1021 / 0x8408 / 0x8810.
Die Checksummeberechnung beginnt mit dem ersten Byte der Nachricht und
endet mit dem 3. letzten Byte der gesamten Nachricht (letztes und 2.
letztes Byte = Checksumme).

Als Teil einer Datendatei sieht so eine Nachricht folgendermaßen aus (keine
Zeilenumbrüche):

SML(1B1B1B1B010101017607001000D9ABAA620062007263010176010107001001698E8E0B06454D480104C56BCCB10101632D2E007607001000D9ABAB620062007263070177010B06454D480104C56BCCB10172620165016934877777078181C78203FF0101010104454D480177070100000009FF010101010B06454D480104C56BCCB10177070100010800FF63018201621E52FF560003EE4E600177070100010801FF0101621E52FF560003EE4E600177070100010802FF0101621E52FF56000000000001770701000F0700FF0101621B52FF55000010480177078181C78205FF0101010183026E08F5C99793A18AABADA3FDA2EF8DEB232E44EC73D5E143E6624F8D5C7C6F828E67757E23845E3A0F02D2517FBF18FC010101634148007607001000D9ABAE62006200726302017101634A5A00001B1B1B1B1A017DA3)

Die vom Zàhler übertragenen Daten sind die Hexwerte, beginnend mit
1B1B1B1B01010101

1B1B1B1B010101017607001000D9ABAA620062007263010176010107001001698E8E0B06454D480104C56BCCB10101632D2E007607001000D9ABAB620062007263070177010B06454D480104C56BCCB10172620165016934877777078181C78203FF0101010104454D480177070100000009FF010101010B06454D480104C56BCCB10177070100010800FF63018201621E52FF560003EE4E600177070100010801FF0101621E52FF560003EE4E600177070100010802FF0101621E52FF56000000000001770701000F0700FF0101621B52FF55000010480177078181C78205FF0101010183026E08F5C99793A18AABADA3FDA2EF8DEB232E44EC73D5E143E6624F8D5C7C6F828E67757E23845E3A0F02D2517FBF18FC010101634148007607001000D9ABAE62006200726302017101634A5A00001B1B1B1B1A017DA3

Die Checksumme der gesamten Datennachricht, beginnend mit 1B1B, sollte also
7DA3 sein.

Ich habe jetzt bereits alle möglichen Routinen aus dem Netz getestet, aber
rein gar nichts funktioniert.

Ich könnte zwar eigentlich darauf verzichten, da mein Datenlogger
wahrscheinlich fehlerhafte Nachrichten verwirft und erst gar nicht auf der
SD-Karte speichert, es ist aber wirklich unbefriedigend, wenn es nicht
funzt.

Meine Frage wàre, ob jemand einen funktionierenden Algorithmus dafür hat,
oder sich schon mal mit dem Thema beschàftigt hat und mir irgendwie
weiterhelfen kann.

Viele Grüße
Michael
 

Lesen sie die antworten

#1 Schmidt
23/02/2013 - 05:26 | Warnen spam
Am 23.02.2013 03:55, schrieb Michael Schwimmer:
Hallo,
ich versuche seit ein paar Tagen verzweifelt, die Checksumme einer Smart
Meter SML_Message nach CCITT-CRC16 (DIN EN 62056-46) zu bestimmen
(Elektronischer Haushaltszàhler).

Laut Beschreibung des Protokolls wird die Checksumme folgendermaßen
bestimmt:

Algorithmus: CCITT-CRC16, x16 + x12 + x5 + 1, 0x1021 / 0x8408 / 0x8810.



Nach etwas experimentieren mit dem Init-Poly, dem Init-Wert mit
dem in den CRC gestartet wird (muss bei Dir &HFFFF& sein) -
und einem finalen XOR von &HFFFF& - kam ich dann auf das offenbar
gewünschte Ergebnis von: A37D (Dein 7DA3 ist nur noch ein Problem
von "endian-ness").

Hier der Code für verschiedene CRCs (und sorry für eventuelle
Zeilenumbrüche - hab den Code jetzt nicht extra NG-fàhig formatiert):

'*** Zunàchst der Test-Code in einer Form:

Option Explicit

Private Sub Form_Load()
Dim B() As Byte, sHex As String, i As Long
'6Bit CRCs with Poly-Value: &H6B&
' ReDim B(0)
' B(0) = 24: Debug.Print Crc6(B)
' B(0) = 20: Debug.Print Crc6(B)

'and a bunch of tests for different CRCs (16 and 32Bit)
'...for comparison, check the following results on:
'http://www.lammertbies.nl/comm/info...ation.html
'B = StrConv("123456789", vbFromUnicode)

sHex =
"1B1B1B1B010101017607001000D9ABAA620062007263010176010107001001698E8E0B06454D480104C56BCCB10101632D2E007607001000D9ABAB620062007263070177010B06454D480104C56BCCB10172620165016934877777078181C78203FF0101010104454D480177070100000009FF010101010B06454D480104C56BCCB10177070100010800FF63018201621E52FF560003EE4E600177070100010801FF0101621E52FF560003EE4E600177070100010802FF0101621E52FF56000000000001770701000F0700FF0101621B52FF55000010480177078181C78205FF0101010183026E08F5C99793A18AABADA3FDA2EF8DEB232E44EC73D5E143E6624F8D5C7C6F828E67757E23845E3A0F02D2517FBF18FC010101634148007607001000D9ABAE62006200726302017101634A5A00001B1B1B1B1A01"
ReDim B(0 To Len(sHex) \ 2 - 1)
For i = 1 To Len(sHex) Step 2
B((i - 1) \ 2) = CByte("&H" & Mid$(sHex, i, 2))
Next i

Debug.Print "CRC16 mit Poly: &H1021&, Init: &HFFFF&, FinalXOR: &HFFFF&"
Debug.Print "Wichtig: die optionalen 16Bit-Inits immer als Long, mit
abschließendem & angeben"
Debug.Print "Crc16(&H1021&, &HFFFF&, &HFFFF&)", Hex(Crc16(B, &H1021&,
&HFFFF&, &HFFFF&))
Debug.Print

Debug.Print "Zum Vergleich, die versch. Algos mit ihren Default-Werten:"
Debug.Print "Crc16(Default):", Hex(Crc16(B))
Debug.Print "Crc16_ModBus:", , Hex(Crc16_ModBus(B))
Debug.Print "Crc16_USB:", , Hex(Crc16_USB(B))
Debug.Print "Crc16_CCITT:", , Hex(Crc16_CCITT(B))
Debug.Print "Crc16_CCITT_Kermit:", Hex(Crc16_CCITT_Kermit(B))
Debug.Print "Crc16_CCITT_XModem:", Hex(Crc16_CCITT_XModem(B))

Debug.Print "Crc32:", , Hex(Crc32(B))
End Sub


'*** Und das hier in ein Modul
Option Explicit

Public Function Crc6(B() As Byte) As Long
Dim i As Long, crc As Long: Static crcTab(0 To 255) As Long
If crcTab(1) = 0 Then CreateLookupTable crcTab, 6, True, &H6B&

crc = 63
For i = LBound(B) To UBound(B)
crc = crcTab((crc Xor B(i)) And &HFF&) Xor (crc \ 256)
Next i
Crc6 = crc Xor 63
End Function

Public Function Crc16(B() As Byte, Optional ByVal Poly& = &H8005&, _
Optional ByVal Init& = 0, _
Optional ByVal FinalXOR& = 0) As Long
Dim i As Long, crc As Long: Static crcTab(0 To 255) As Long
If crcTab(1) = 0 Then CreateLookupTable crcTab, 16, True, Poly

crc = Init
For i = LBound(B) To UBound(B)
crc = crcTab((crc Xor B(i)) And &HFF&) Xor (crc \ 256)
Next i
Crc16 = crc Xor FinalXOR
End Function

Public Function Crc16_ModBus(B() As Byte) As Long
Dim i As Long, crc As Long: Static crcTab(0 To 255) As Long
If crcTab(1) = 0 Then CreateLookupTable crcTab, 16, True, &H8005&

crc = &HFFFF&
For i = LBound(B) To UBound(B)
crc = crcTab((crc Xor B(i)) And &HFF&) Xor (crc \ 256)
Next i
Crc16_ModBus = crc
End Function

Public Function Crc16_USB(B() As Byte) As Long
Dim i As Long, crc As Long: Static crcTab(0 To 255) As Long
If crcTab(1) = 0 Then CreateLookupTable crcTab, 16, True, &H8005&

crc = &HFFFF&
For i = LBound(B) To UBound(B)
crc = crcTab((crc Xor B(i)) And &HFF&) Xor (crc \ 256)
Next i
Crc16_USB = crc Xor &HFFFF&
End Function

Public Function Crc16_CCITT(B() As Byte) As Long
Dim i As Long, crc As Long: Static crcTab(0 To 255) As Long
If crcTab(1) = 0 Then CreateLookupTable crcTab, 16, False, &H1021&

crc = &HFFFF&
For i = LBound(B) To UBound(B)
crc = (crcTab(((crc \ 256) Xor B(i)) And &HFF&) Xor (crc * 256))
And &HFFFF&
Next i
Crc16_CCITT = crc
End Function

Public Function Crc16_CCITT_XModem(B() As Byte) As Long
Dim i As Long, crc As Long: Static crcTab(0 To 255) As Long
If crcTab(1) = 0 Then CreateLookupTable crcTab, 16, False, &H1021&

crc = 0
For i = LBound(B) To UBound(B)
crc = (crcTab(((crc \ 256) Xor B(i)) And &HFF&) Xor (crc * 256))
And &HFFFF&
Next i
Crc16_CCITT_XModem = crc
End Function

Public Function Crc16_CCITT_Kermit(B() As Byte) As Long
Dim i As Long, crc As Long: Static crcTab(0 To 255) As Long
If crcTab(1) = 0 Then CreateLookupTable crcTab, 16, True, &H1021&

crc = 0
For i = LBound(B) To UBound(B)
crc = crcTab((crc Xor B(i)) And &HFF&) Xor (crc \ 256)
Next i
Crc16_CCITT_Kermit = crc \ 256 + 256 * (crc And &HFF&) 'Byte-Swap
End Function

Public Function Crc32(B() As Byte) As Long
Dim i As Long, crc As Long: Static crcTab(0 To 255) As Long
If crcTab(1) = 0 Then CreateLookupTable crcTab, 32, True, &H4C11DB7

crc = &HFFFFFFFF
For i = LBound(B) To UBound(B)
crc = crcTab((crc Xor B(i)) And &HFF&) Xor (((crc And &HFFFFFF00)
\ &H100) And &HFFFFFF)
Next i
Crc32 = crc Xor &HFFFFFFFF
End Function

'-- Helper-Functions for Lookup-Table-Generation
-

Private Sub CreateLookupTable(crcTab() As Long, ByVal BitLen As Long,
ByVal Reflected As Boolean, ByVal Poly As Long)
Dim r As Long, i As Long, v As Long, BM As Long
If BitLen = 32 Then BM = &H80000000 Else BM = 2 ^ (BitLen - 1)

For v = 0 To UBound(crcTab)
r = v
If Reflected Then r = Reflect(v, IIf(BitLen < 8, BitLen, 8))
If BitLen > 8 Then r = SHL(r, BitLen - 8)

For i = 0 To IIf(BitLen < 8, BitLen, 8) - 1
If r And BM Then
r = SHL(r, 1) Xor Poly
Else
r = SHL(r, 1)
End If
Next

If Reflected Then r = Reflect(r, BitLen)

If BitLen = 32 Then
crcTab(v) = r
Else
crcTab(v) = r And CLng(2 ^ BitLen - 1)
End If
Next v
End Sub

Private Function Reflect(ByVal v As Long, ByVal Bits As Long) As Long
Dim i As Long, M As Long
Reflect = v
For i = 0 To Bits - 1
If (Bits - i - 1) = 31 Then M = &H80000000 Else M = 2 ^ (Bits - i - 1)
Reflect = IIf(v And 1, Reflect Or M, Reflect And Not M)
v = SHR(v, 1)
Next i
End Function

Private Function SHL(ByVal Value As Long, ByVal Bits As Long) As Long
Dim M As Long
If Bits = 0 Then SHL = Value: Exit Function
M = 2 ^ (31 - Bits)
SHL = (Value And (M - 1)) * 2 ^ Bits Or IIf(Value And M, &H80000000, 0)
End Function

Private Static Function SHR(ByVal Value As Long, ByVal Bits As Long) As Long
If Value > 0 Then SHR = Value \ 2 ^ Bits: Exit Function
SHR = ((Value And Not &H80000000) \ 2 ^ Bits) Or 2 ^ (31 - Bits)
End Function

Olaf

Ähnliche fragen