2016-04-28 14 views
0

Ich verbinde mich mit einem Gerät über eine serielle Schnittstelle. Das Gerät fügt ein CRC16-Tag an das Ende des Datenpakets im Big-Endian-Modus an. In der Software-Seite ist der CRC-Code zu überprüfen, so etwas wie diese:CRC16 modbus Berechnung gibt falschen Wert für lange Datenpakete zurück

bool Protocol::checkCRC(const QByteArray &buf) { 
    if(buf.size()<3){ 
     return false; 
    } 
    int len = buf.size()-2; // Exclude CRC token 
    quint16 crc = 0xFFFF; 
    quint16 claim = static_cast<uchar>(buf.at(buf.size()-1)); 
    claim*=0x100; 
    claim+=static_cast<uchar>(buf.at(buf.size()-2)); 

    for (int pos = 0; pos < len; pos++) 
    { 
     crc ^= (quint16)buf[pos];   // XOR byte into LSB of crc 
     for (int i = 8; i != 0; i--) { // Loop over each bit 
      if ((crc & 0x0001) != 0) { // If the LSB is set 
       crc >>= 1;    // Shift right and XOR 0xA001 
       crc ^= 0xA001; 
      } 
      else       // Else LSB is not set 
       crc >>= 1;    // Just shift right 
     } 
    } 
    return crc==claim; 
} 

ich den Code aus this question kopiert.

Es funktioniert gut für kleine Pakete. Zum Beispiel folgendes Datenpaket wird in CRC16 Check mit dieser Funktion übergeben:

0x04, 0x10, 0x00, 0x3d, 0xc1 

CRC Angegeben ist 0xC13D und Funktion berechnet 0xC13D auch. Aber für große Datenpakete (in meinem Fall 53 Bytes) nicht die Funktion korrekt CRC berechnen:

0x34, 0x02, 0x02, 0x08, 0x14, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x10, 0x0a, 0xdf, 0x07, 0x0a, 0x39, 
0x1b, 0x02, 0x02, 0x79, 0x61, 0xbf, 0x34, 0xdd, 
0x0b, 0x83, 0x0f, 0x10, 0x03, 0x1b, 0x11, 0x02, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0xfc, 0x98 

Berichtet CRC 0x98FC ist aber berechneter Wert 0xDFC4.

Antwort

2

Ich weiß nicht, was der QByteArray Typ ist, aber ich wette, dass es ein Array von unterzeichnet Zeichen ist. Wenn das High-Bit eines Bytes eine Eins ist, wird das Vorzeichen-Bit daher erweitert, wenn es in eine Ganzzahl konvertiert wird, die alle unter crc ^= (quint16)buf[pos]; in Ihren CRC exklusiv-or'ed werden. So, wenn Sie an die 0xdf, crc wurde wurde mit 0xffdf anstelle der vorgesehenen 0xdf.

Das Problem ist also nicht die Länge, sondern die Wahrscheinlichkeit, ein Byte mit dem hohen Bit gesetzt zu haben.

Sie müssen vorzeichenlose Bytes bereitstellen oder die Konvertierung korrigieren oder eine & 0xff für das resultierende Byte ausführen, bevor Sie den CRC ausschließen.

+0

von Qt-Quellen: 'typedef unsigned short quint16' trotz der Tatsache,' QByteArray' hält 'char's sollte es funktionieren. Das Problem war 'quint16' Umwandlung in' crc^= (quint16) buf [pos] 'das sollte' quint8' sein. –

+0

Ah, richtig, in der Tat spielt die Signedness von quint16 keine Rolle, da der Schaden bereits eine ist Das Zeichen mit Vorzeichen wird in einen größeren Typ konvertiert. Das '(quint8)' macht es unsigniert, bevor es in einen größeren Typ konvertiert wird. –