SML-Prüfsummenberechnung: Ich verzweifle an CRC

  • Hallo zusammen,


    falls hier noch Aufklärungsbedarf sein sollte: bin gestern auch über dieses ecklige Problem gestoplert, und denke, ich habe jetzt nach einigem Lesen die Verwirrung verstanden.


    Mein Denkfehler war: der Algorithmus arbeitet zwar mit Bytes, aber da das erste Bit auf dem Draht das LSB ist, müssen alle Bits im Byte gespiegelt werden. Ausserdem wird am Ende nochmal das ganze Ergebnis invertiert und ein Endianess-Tausch vorgenommen.


    Punkt 1) 1021 vs. 8408 (NB: gespiegeltes 16-Bit-Wort)
    Wenn die Datenbits von Bit 7 nach Bit 0 von rechts kommend nach links in das Register geschoben werden, muss das Ergebnis am Ende noch bitweise gespiegelt werden (0x0001 -> 0x8000, 0x1234 -> 0x2c48). Das läuft dann unter dem Stichwort "reflektiert".
    Alternativ: Die Bits von 0 nach 7 von links kommend nach rechts in das CRC-Register schieben und das Polynomwort 0x8408 verwenden.


    Punkt 2) Startwert ist 0xffff, am Ende werden aber alle Bits nochmal invertiert, und Low- und High-Byte vertauscht.
    Alternativ kann auch (umständlicher) mit Startwert 0x0 gearbeitet und die Invertierung am Schluss gespart werden, dann muss aber jedes einzelne Bit nochmal invertiert werden. Das entspricht dann quasi dem logischen Pegel auf dem Draht, der ja auch invertiert ist. Der Low/High-Byte-Tausch ist vermutlich eher ein historischer Implementierungsfehler, der dann quasi per Standard festgeschrieben wurde.


    Hoffe, das hilft...


    Ciao
    Michael

  • Hi,


    auch wenn der Thread schon alt ist, vieleicht hilft es jemand. Da ich auch lange gesucht habe.
    war auch am Verzweifeln. Hier ein Java Code der ohne Tabelle auskommt.
    Auserdem sucht er effektiv nach Start und Ende


    5,06 kWp, DN:35°, -27°SSO, Inbetriebnahme: 02.05.2016 ; PVGIS 4 Classic: 902kWh/kWp
    PVGIS-CM-SAF: 1010kWh/kWp

  • Ich struggle auch gerade an dem CRC Punkt ... Versuche das gerade in nodejs umzusetzen.


    Ich versuche eine bestehende SML-Nachricht zu verifizieren:


    Code
    1b1b1b1b01010101760700190b4cbead6200620072630101760101070019063f3f8f0b0901454d48000041f045010163662d00760700190b4cbeae620062007263070177010b0901454d48000041f045070100620affff72620165063f2f357777078181c78203ff0101010104454d480177070100000009ff010101010b0901454d48000041f0450177070100010800ff6400018201621e52ff560009247a550177070100010801ff0101621e52ff560009247a550177070100010802ff0101621e52ff5600000000000177070100100700ff0101621b52ff55000016030177078181c78205ff0172620165063f2f3501018302e77ef33ea97bb6bba9bfa4fbd8b9f2ede51207b15acf6b98a237c21ca4982ee3ce18efe8438f1deba9d5c40eb68ae8f201010163574a00760700190b4cbeb16200620072630201710163d658000000001b1b1b1b1a03e566


    Ich komme hier mit allen möglichen CRC-Rechern (z.B. auch https://www.lammertbies.nl/comm/info/crc-calculation.html) immer auf andere Werte ...


    Ich komm nicht weiter ... Auch die ips oben haben leider nur bedingt geholfen.
    irgendjemand noch eine Idee?


    Bzw kann einer von Euch der es implementiert hat mal prüfen ob die CRC in der Nachricht überhaupt korrekt ist ?! Wie ist Sie denn wenn Ihr Sie berechnet?


    Auch http://zorc.breitbandkatze.de/crc.html 8und da kann man vieles am Algorithmus rumspielen) liefert andere Werte ... so langsam glaube ich ja das die Checksumme von meinen eHz anders generiert wird.

  • Bitte lies meine Msg von vor zwei Jahren bitte nochmal durch.
    Ansonsten: CRC-16-CCITT nach DIN EN 62056-46; Startwert 0xffff, am Ende aber alle Bits invertieren und Low- und High-Byte vertauschen.


    Ansonsten per Tabelle, hier als Lua-Fragment:

  • Ich komm' nicht weiter.. Ich hab' mich auch durch alles durchgefressen, was man so finden kann. Wichtig: Ich brauch' einen Algorithmus ohne Tabelle.


    1. Im Prinzip ist mir die Nummer mit den reflektierten Bits klar - dennoch: die libsml macht nicht's davon. Gut, die ist 6 Jahre alt..


    2. Was mich irritiert: Auch die Algoritmen hier _invertieren_ abschließend die Bits - meinem Verständnis nach müssen sie aber _gespiegelt/reflektiert_ werden. Ist aber auch egal, weil beides nicht geht...


    Der CRC-Code stammt aus der libsml; die Reflektierungen habe ich nach Lammert Bies gemacht - wenn auch anders umgesetzt.


    CRC-Start: 0xFFFF
    Polynom: 0x1021



    Jedes Byte, dass über die Serielle kommt, wird einzeln der Prüfsumme "hinzugefügt" - Also im Prinzip wie folgt:


    Code
    crc = 0xFFFF;
    calccrc16(crc, newByte);
    ...
    calccrc16(crc, newByte);
    ...
    calccrc16(crc, newByte);


    und schließlich:


    Code
    finalCrc = getCrc16(crc);


    Ich finde die Lösung nicht...


    Btw: Ich habe einen ED300L. Ich zieh mir nur die paar Verbrauchswerte raus und über einfache Plausibiltätschecks funktioniert das auch ganz gut - aber mir wär's lieber, wenn ich das ganze SML-Paket verifizieren könnte. Das hat vor allem beim Start enorme Vorteile...

  • Hallo Leute,


    ich weis nicht, ob es noch von Interesse ist, aber ich wollte auch die Checksumme und bin lange Zeit gescheitert. Die Lösung habe ich hier gefunden:


    https://de.comp.lang.vbclassic…6-sml-transport-protokoll


    Nachdem ich nicht so gut VisualBasic umgehen kann, habe ich alles Überflüssige entfernt und nach C portiert . Nach ein paar Versuchen ist Folgendes herausgekommen:


    static const WORD crctable[256] =

    {

    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

    };


    // ----------------------------------------------------------------------------

    // CRC mit Tabelle berechnen

    int BerCrc(int *Crc, int Wert) {

    BYTE Index;


    Wert &= 0xff;

    Index = ((*Crc) ^ Wert) & 0xff;

    *Crc = ((*Crc) >> 8) ^ crctable[Index];

    *Crc &= 0xffff;

    return 0;

    }



    // ----------------------------------------------------------------------------

    // CRC eines Blocks bilden

    WORD CheckCrc(BYTE Puf[], int Len) {

    int Crc = 0xffff;

    int K;


    for(K = 0; K < (Len - 2); K++) {

    BerCrc(&Crc, Puf[K]);

    }

    Crc ^= 0xffff;

    return Crc;

    }


    Wer die Tabelle berechnen will, das geht so:


    // ----------------------------------------------------------------------------

    // ein Byte Bitreihenfolge tauschen

    BYTE ReflectByte(BYTE Wert) {

    int K;

    BYTE Temp = 0;


    for(K = 0; K < 8; K++) {

    Temp <<= 1;

    if(Wert & (1 << K))

    Temp |= 0x01;

    }

    return Temp;

    }



    // ----------------------------------------------------------------------------

    // ein Word Bitreihenfolge tauschen

    WORD ReflectWord(WORD Wert) {

    int K;

    WORD Temp = 0;


    for(K = 0; K < 16; K++) {

    Temp <<= 1;

    if(Wert & (1 << K))

    Temp |= 0x0001;

    }

    return Temp;

    }



    // ----------------------------------------------------------------------------

    // Crc16-Tabelle erzeugen

    WORD GenCrc16(int Wert) {

    int K, Index;


    Index = Wert;

    Wert = ReflectByte(Wert);

    Wert <<= 8;

    for(K = 0; K < BitCount; K++) {

    if(Wert & 0x8000) {

    Wert = (Wert << 1) ^ CrcPoly;

    } else {

    Wert <<=1;

    }

    }

    Wert = ReflectWord(Wert);

    return Wert & 0xffff;

    }


    Bei mir funktioniert das, ich hoffe, ich habe nichts vergessen und es hilft euch weiter.


    Bis denn