Checksum calculation - SOLVED

Hi All!

Firstly sorry for my bad English, I'm Hungarian.
I already spend 4days to solve my "porblem" without any luck :slight_smile:

I would like to calc checksum of string array, or byte array, I do not how to start.
I have one example what I need, but I can't solve it,

What I get on serial port is
:7001000C80076 <- The last 2 character is the checksum (76)
( 0x3a, 0x37, 0x30, 0x30, 0x31, 0x30, 0x30, 0x30, 0x43, 0x38, 0x30, 0x30, 0x37, 0x36 )

Always start byte is "0x55" then start the string first character "7" see below:

So add the checksum first -> 0x55 (then->) – 0x7 – 0x0 – 0x10 – 0x0 – 0xC8 – 0x0 = 0x76 which is correct.

If I put this to array:
byte test[] = {0x3a, 0x37, 0x30, 0x30, 0x31, 0x30, 0x30, 0x30, 0x43, 0x38, 0x30, 0x30};

I left the last 2 bytes "0x37, 0x36" --which is 0x76-- then I wrote the code, but always computing the arrays byte to byte.. :frowning:

I think I need to computing 2bytes to 2 bytes, but not sure(?)

Thanks in advance who spend a little time to help me out!

Does this diagram help?


If you convert the ASCII code values in test[] into values[] then the checksum is 0x55 - sum of all the values[].

Where did you get the format from (first byte = 0x55, then ':' etc)? Is it something you designed, or is it from a specification you have to follow? If it's from a specification please provide a link to it.

[Edit: I'm not suggesting you try to generate the declaration of byte values with preset values as shown in the diagram. That was just a diagram to show what conversion needs to take place.]

This looks like an Intel-Hex Frame; so, there should be an even of digits/charcaters. Why you have 13 and NOT 14. Rechcek and post a correct frame.

To get a CHKSUM, you add all the bytes of the received Intel-Hex frame except the first colon ( : ) and the last one 0x76), discard the carries, invert the rest bitwise, and then add 1. the result must be equal to the last byte of the frame.

Here is it ....then scroll up, almost top of the page

With short code eg: :7001000C80076 - last character chk:"76" it works with 55-7-00-10--ect, but when I go for long code
eg: ":70C01004D505054203435302F31303020485132333335414134474FB5"
So:
55-7-0C-01---etc-- and the last character "4F", I didn't get the "B5" checksum. :thinking:

looks like you need to exclusive-or
the last column is the accumulated XOR. result is 0x76

  0  0x3a :  3a
  1  0x37 7  0d
  2  0x30 0  3d
  3  0x30 0  0d
  4  0x31 1  3c
  5  0x30 0  0c
  6  0x30 0  3c
  7  0x30 0  0c
  8  0x43 C  4f
  9  0x38 8  77
 10  0x30 0  47
 11  0x30 0  77
 12  0x37 7  40
 13  0x36 6  76
#include <stdio.h>
#include <stdint.h>

uint8_t arr0 [] = { 70, 0x010, 0x00, 0xC8, 0x00, 0x76 };
uint8_t arr [] = {
    0x3a, 0x37, 0x30, 0x30,
    0x31, 0x30, 0x30, 0x30,
    0x43, 0x38, 0x30, 0x30,
    0x37, 0x36
};



int
main ()
{
    int sum = 0;
    for (int n = 0; n < sizeof(arr); n++)  {
        printf (" %2d  0x%02x %c  %02x\n", n, arr [n], arr [n], sum ^= arr [n]);
    }
    return 0;
}

I did

1 Like

That was my first thought. I don't know Intel Hex by heart, and it's been a while since I had to write code to read it. So I checked and there doesn't seem to be a record type with a 7 in it

byte checksum = 0x55;
byte message[] = { 0x7, 0xff, 0x0f, 0x00 };
for (int i =0; i < sizeof(message); i++)
   checksum -= message[i];

the code from VE.Direct Protocol is somewhat unusual in 2 ways.

first it starts with an initial value of 0x55
the 2nd is that instead of summing its subtracting.

because its suibtracting, the intial byte in the sequence, 0x55, which happens to be the initial value of the chksum needs to be discarded if the initial sum were zero, because it would be subtracted instead of added

and as typical, because the last byte is the chksum, the resulting "sum" including the last byte is zero if everything checks

This is what is all about Intel-Hex formatted frame/file: (The example is from a transmission file of an 8086 Trainer.)

How can I handle this?
Need to convert it to put in array..(?)

I did convert string to hex, like this:

:70C01004D505054203435302F31303020485132333335414134474F
To:

byte message[] = {
0x3A, 0x37, 0x30, 0x43, 0x30, 0x31, 0x30, 0x30, 0x34, 0x44, 0x35, 0x30,
0x35, 0x30, 0x35, 0x34, 0x32, 0x30, 0x33, 0x34, 0x33, 0x35, 0x33, 0x30,
0x32, 0x46, 0x33, 0x31, 0x33, 0x30, 0x33, 0x30, 0x32, 0x30, 0x34, 0x38,
0x35, 0x31, 0x33, 0x32, 0x33, 0x33, 0x33, 0x33, 0x33, 0x35, 0x34, 0x31,
0x34, 0x31, 0x33, 0x34, 0x34, 0x37, 0x34, 0x46
};

and the code was:

byte checksum = 0x55;
for (int i = 1; i < sizeof(message); i++) {
    checksum -= message[i];
}

"for (int i = 1.." <--because i dont want to use the 1st byte ":" so, start with "7" -> 55-7...

Do you have to send these messages?
Do you have to receive these messages?
How to handle it would be different depending on which one you want to do, or if you want to do both.

I would like to send same structure:
:70C01004D505054203435302F31303020485132333335414134474FB5\n

I would like to change some byte's, calc chk, then send it
I can send the HEX with Serial.write aswell, and I checked with "LogicAnalyser" on TX port, and if I remember correctly, the result are same

One way to do it would be to read along the string pulling out 2 chars at a time.
For the first two chars ":7" replace with "07".
Convert each pair into a byte, e.g. "07" -> byte value = 0x07, "0C" -> byte value 0x0C, etc
Starting with byte checkSum = 0x55, then subtract each of the byte values from the char pairs from checkSum.
Finally convert checkSum into 2 hex chars and add it to the end of the string.
If that's not enough detail, say so, and I may have time to write some example code later today.

I wrote some example code to do what you want to do. This code is not the most efficient, or elegant, but it works (at least with the two examples you provided).

String example1 = ":7001000C800";
String example2 = ":70C01004D505054203435302F31303020485132333335414134474F";

void setup() {
  Serial.begin(115200);
  addCheckSum(example1);
  addCheckSum(example2);
}

void addCheckSum(String &data) {
  Serial.println("before = \"" + data + "\"");
  int length = data.length();
  if (length % 2) {
    // Error if odd number of chars in data
    Serial.println("Error odd number of chars");
    return;
  }
  byte checkSum = 0x55;
  for (int i = 0; i < length; i += 2) {
    String charPair = data.substring(i + 0, i + 2);
    if (i == 0) charPair.setCharAt(0, '0'); // Replace ':' with '0'
    checkSum -= twoCharHexStringToByte(charPair);
  }
  data += byteToTwoCharHexString(checkSum);
  Serial.println("after  = \"" + data + "\"");
}

byte twoCharHexStringToByte(String &charPair) {
  byte retVal = 0;
  charPair.toUpperCase();
  for (int i = 0; i < 2; i++) {
    retVal <<= 4;
    char currentChar = charPair.charAt(i);
    if ((currentChar >= '0') && (currentChar <= '9')) retVal += currentChar - '0';
    else if ((currentChar >= 'A') && (currentChar <= 'F')) retVal += currentChar - ('A' - 10);
    else {
      Serial.println("Error invalid char");
      return 0;
    }
  }
  return retVal;
}

String byteToTwoCharHexString(byte value) {
  String retVal = String(value, HEX);
  retVal.toUpperCase();
  if (retVal.length() == 1) retVal = "0" + retVal;
  return retVal;
}

void loop() {
}

The output on the serial monitor is

before = ":7001000C800"
after  = ":7001000C80076"
before = ":70C01004D505054203435302F31303020485132333335414134474F"
after  = ":70C01004D505054203435302F31303020485132333335414134474FB5"

1 Like

I have computed checksum for the data bytes (0x07, ..., 0x4F) of the above. My sketch shows: 0x64 and NOT 0xB5. Am I doing anything wrong?

byte after[]  =
{
  0x07, 0x0C, 0x01, 0x00, 0x4D, 0x50, 0x50, 0x54, 0x20,
  0x34, 0x35, 0x30, 0x2F, 0x31, 0x30, 0x30, 0x20, 0x20,
  0x48, 0x51, 0x32, 0x33, 0x33, 0x35, 0x41, 0x41, 0x34,
  0x47, 0x4F
}; //B5"

void setup() 
{
  Serial.begin(9600);
  int sum = 0;
  for(int i = 0; i < sizeof after; i++)
  {
    sum += after[i]; 
  }
  
  byte result = (byte)sum;
  result = ~result;
  result++;
  Serial.print("Checksum: "); Serial.println(result);  //shows: 0x64
}

void loop() {}

Yes, the 'rules' are.
a) Initialise sum to 0x55
b) Subtract the values from sum.

starting with the 2nd byte, the 0x7

The Intel-Hex frame of post #9 was generated by lod186.exe application that accompanied with MIDAS-86 Microprocessor Trainer (Fig-1) and I have applied those rules applied for the creation of CHKSUM there.
image
Figure-1:

It could e that you are applying different rules for the creation of CHKSUM of an Intel-Hex formatted frame.

Both are correct!

big WOW!
You are the MASTER! Thank you very much! :pray:
I learn a LOT!
I did not use any checksum and communication before, I gonna look after the code and learn everything what you used in code!

First what I found, I think..: In byte array, why did not work.. The calculation of array used 1byte to 1byte, not 2bytes to 2bytes like HEX data.

0x3A, 0x37, 0x30, 0x43, 0x30, 0x31, 0x30, 0x30...

0x3A = :
0x37 = 7
0x30 = 0
0x43 = C
0x30 = 0
0x31 = 1
Then my calc 55-7-0-C-0-1 which is wrong. Need to put together 2 bytes to get 0x55 - 0x07 - 0x0C - 0x01 :thinking:

1 Like

This thread has nothing to do with Intel-Hex other than you and I thinking (incorrectly) that the format looked like Intel-Hex

1 Like