Search code examples
c++qtchecksumqbytearray

How can you calculate a checksum from hex values stored in a QByteArray


I feel this is a stupid question but i cant get this to work so please bear with me. I want to calculate a simple checksum to check if the data i received over serial and stored in a QByteArray is not corrupt(or is correct).

the packet format of the data i am receiving is like this: // Packet format: // //|CHAR1<1>|CHAR2<1>|CLASS<1>|ID<1>|LENGTH<2>|PAYLOAD|CK_A<1>|CK_B<1>|

// <--------------------- 4 ---------------------------->|

// <--------------------------------------- 6 ----------------------------->|

// <--------------------------------------- 6 + length -------------------------------->|

//<---------------------------------------------------------8+length------------------------------------------->|

There are two check sums CK_A and CK_B. Each is a single byte long.The checksum Algorithm is the 8-Bit Fletcher Algorithm:

CK_A = 0;
CK_B = 0;
for(i=0,i<n,i++){
  CK_A = CK_A + Buffer[i];
  CK_B = CK_B + CK_A;
}

I am having trouble with adding up the hex values stored in the QByteArray. This is the code I have written.It ads up the values but they are not correct and the code is messy.

for(int I = 4; I < length + 4; I+=2){

        tempHex[0] = serialData[I];
        tempHex[1] = serialData[I + 1];
        tempDec=tempHex.toInt();

        CheckSum_A_int = (CheckSum_A_int + tempDec);
        CheckSum_A_int &= 0xFF;
        CheckSum_B_int = (CheckSum_B_int + CheckSum_A_int);
        CheckSum_A_int &= 0xFF;


        CK_A = CheckSum_A_int;
        CK_B = CheckSum_B_int;

        CK_A = CK_A.toLatin1().toHex();
        CK_B = CK_B.toLatin1().toHex();
}

Does anybody know the correct or better way to do this. Or can someone please explain to me how hex values is a QByteArray can be added up? This is a sample of the data : "b56201241400009b4209d25e02009be0f8ffcc020407140d0000bd33". CK_A should be "bd" and CK_B shoud be "33".

Thanks a lot for your patience. Regards


Solution

  • According to ublox datasheet your checksum calculation starts at wrong offset and stops too early and you add two data bytes per loop instead of one. The following example calculates the right checksum A and B based on your example data.

    #include <QByteArray>
    #include <iostream>
    
    int main(int argc, char *argv[])
    {
        // Unused function parameters
        (void)argc;
        (void)argv;
    
        uint16_t csum_a = 0;
        uint16_t csum_b = 0;
        QByteArray ba;
    
        // Example Receive message
        uint8_t data[] = {
            0xb5, 0x62,              // Preamble
            0x01, 0x24,              // CLASS + ID
            0x14, 0x00,              // Length (Little Endian)
            0x00, 0x9b, 0x42, 0x09,  // Payload
            0xd2, 0x5e, 0x02, 0x00,  // Payload
            0x9b, 0xe0, 0xf8, 0xff,  // Payload
            0xcc, 0x02, 0x04, 0x07,  // Payload
            0x14, 0x0d, 0x00, 0x00,  // Payload
            0xbd,                    // Checksum A
            0x33                     // Checksum B
        };
    
        // Add receive message to QByteArray
        for (int i = 0; i < static_cast<int>(sizeof(data)); i++)
        {
            ba.append(static_cast<int8_t>(data[i]));
        }
        std::cout << "QByteArray size: " << ba.size() << std::endl;
    
        // Extract length from receive message
        // According to ublox datasheet, it's little endian.
        uint16_t length = static_cast<uint16_t>(ba[4]) | static_cast<uint16_t>((ba[5]) << 8);
        std::cout << "Message length: " << length << std::endl;
    
        // Calculate checksum according to ublox datasheet.
        // The checksum is calculated over the Message, starting and including
        // the CLASS field, up until, but excluding, the Checksum Field.
        for (uint16_t offset = 2; offset < (length + 6); offset++)
        {
            csum_a = (csum_a + ba[offset]) & 0x00ff;
            csum_b = (csum_b + csum_a) & 0x00ff;
        }
    
        std::cout << "Checksum A: " << std::hex << "0x" << csum_a << std::endl;
        std::cout << "Checksum B: " << std::hex << "0x" << csum_b << std::endl;
    
        return 0;
    }