Serial protocol Checksum calculation - Page 1
Forum section: electronics / beginners

author: Precious Roy
author_rank: Contributor
timestamp: October 19, 2016, 07:08:05 am
content: Hello,I am working on reading out a scale via a serial connection, my English is not to good and i dont understand the explanation they give in the datasheet.i was wondering can any of you explain how to do the checksum in simple English.Code:/*??????????????????????????????????????????????????????????????|STX|Status|Net Weight|Gross Weight|Peak Weight|ETX|Check|EOT|??????????????????????????????????????????????????????????????1 | 2 | 3 | 4 | 5 | 6 | 7 | 81 = Start of transmission, 1 Byte2 = Status of scale, 1 Byte3 = Net weight of the scale, 6 Bytes4 = Gross weight of scale, 6 Bytes5 = Peak weight of scale, 6 bits6 = End of text, 1 byte7 = Checksum is the ASCII encoding of the two hexadecimal digits, 2 byte8 = End of transmission, 1byteChecksum = 2 ASCII control characters calculated considering the characters between STX and ETX excluded.The control value is obtained by executing the operation of XOR (or exclusive) of the 8-bit ASCII codes ofthe characters considered. The result is a character that is expressed in hexadecimal with 2 digits that cantake values from "O" to "9" and "A" to "F".*/I got my explanation form a different data sheet that i can not find on the web, but i do not understand ether of them.Datasheethttp://www.prisma.co.il/upload/DAT400DeviceNetmanual0.7(1).pdfPage 20

author: hamster_nz
author_rank: Super Contributor
timestamp: October 19, 2016, 07:17:14 am
content: How would you like to see the reply? In code? Do you have any test messages you can share?It seems pretty simple - XOR the byte values of all the characters between STX and ETX characters, and output that as two hexidecimal digits.and output that as two hexidecimal digits.STX is ASCII code 2, ETX is code 3 and EOT is code 4.

author: Precious Roy
author_rank: Contributor
timestamp: October 19, 2016, 07:23:26 am
content: yes thats what i was thinking but the checksum is 2 bytes and the amount of bytes between STX and ETX is 1+6+6+6 = 19 witch is not divisible by 2.so that means i am not understanding what they want me to do.Edit:it does not mater how i get it, i can post the code i have at the moment but it is really simple. i do not have a sample of the output, but if you really need it i can write some code to get it.Code:/*??????????????????????????????????????????????????????????????|STX|Status|Net Weight|Gross Weight|Peak Weight|ETX|Check|EOT|??????????????????????????????????????????????????????????????1 | 2 | 3 | 4 | 5 | 6 | 7 | 81 = Start of transmission, 1 Byte2 = Status of scale, 1 Byte3 = Net weight of the scale, 6 Bytes4 = Gross weight of scale, 6 Bytes5 = Peak weight of scale, 6 bits6 = End of text, 1 byte7 = Checksum is the ASCII encoding of the two hexadecimal digits, 2 byte8 = End of transmission, 1byteChecksum = 2 ASCII control characters calculated considering the characters between STX and ETX excluded.The control value is obtained by executing the operation of XOR (or exclusive) of the 8-bit ASCII codes ofthe characters considered. The result is a character that is expressed in hexadecimal with 2 digits that cantake values from "O" to "9" and "A" to "F".*/enum ScaleStatus{STABLE= 'S',// Stable weightMOVING= 'M',// Moving weightOVER= 'O', // Over capacityUNKOWN = 'E'// Can not be detected};const byte STX = 0;//1const byte Status = 1;//1const byte Net = 2;//6const byte Gross = 8;//6const byte Peak = 14;//6const byte ETX = 20;//1const byte Checksum = 21; //2const byte EOT = 23;//1void ProcessTimeString(char* ScaleString){if (ScaleString != '\0' && ScaleString[EOT + 1] == '\0') //should be 24 chars{//checksum//statusm_Status = (ScaleStatus)ScaleString;char tmp; // 6 last char is end of string, 5 because i am ignoring the 100liko digit//netmemset(tmp, '0/', 6);memcpy(tmp, ScaleString + Net + 1, 5);m_Weight = atoi(tmp);//grossmemset(tmp, '0/', 6);memcpy(tmp, ScaleString + Gross + 1, 5);m_GrossWeight = atoi(tmp);//peakmemset(tmp, '0/', 6);memcpy(tmp, ScaleString + Peak + 1, 5);m_PeakWeight = atoi(tmp);}}

author: Rerouter
author_rank: Super Contributor
timestamp: October 19, 2016, 07:34:09 am
content: I would imagine you have to pad 1 value, so AA becomes 00AA or AA00 if its uneven

author: Precious Roy
author_rank: Contributor
timestamp: October 19, 2016, 07:37:11 am
content: I guess but now the question is (it does not mention it so does that mean i need to test it out ?) do i begin with the padding or end with it ?

author: Rerouter
author_rank: Super Contributor
timestamp: October 19, 2016, 07:46:32 am
content: could you post some example strings?what value each byte contains in a valid message, it should not be hard to work back from there.

author: hamster_nz
author_rank: Super Contributor
timestamp: October 19, 2016, 08:25:03 am
content: My take on a sample message, and code to verify... note that STX, ETX and EOT are single character constants!Code:#include <stdio.h>#include <string.h>#define STX "\002"#define ETX "\003"#define EOT "\004"static const char test_data = STX "2333333444444555555" ETX "32" EOT;static const char to_hex = "0123456789ABCDEF";static int verify_message(const char *message){unsigned char checksum = 0;char digit1, digit2;int i;/* Validate length */if(strlen(message) != 24) return 0;/* Validate STX */if(message != 2) return 0;/* Validate ETX */if(message != 3) return 0;/* Validate EOT */if(message != 4) return 0;/* Calculate the checksum (note STX and ETX are not included) */for(i = 1; i < 20; i++)checksum ^= message;/* Split into digits */digit1 = to_hex[checksum / 16];digit2 = to_hex[checksum & 0xF];printf("Calculated checksum is %c%c\n", digit1,digit2);/* Verify the digits */if(test_data != digit1) return 0;if(test_data != digit2) return 0;return 1;}int main (void){if(verify_message(test_data))printf("Verification passes\n");elseprintf("Verification FAILED\n");return 0;}

author: Precious Roy
author_rank: Contributor
timestamp: October 19, 2016, 08:53:57 am
content: so i got a sample message in binary form,2,83,48,48,48,48,48,48,48,48,52,54,57,56,48,48,52,55,48,48,3,53,51,4,- S 0 0 0 0 0 0 0 0 4 6 9 8 0 0 4 7 0 0 - check -it was rather hard to get in string because of the missing charactersEdit: hamster_nz i will test your code but first study up on what you ar doing :}Edit 2: i had to change some formatting stuff but it works like a charm thanks you so much but could i ask you to elaborate on this partCode:digit1 = to_hex[checksum / 16];digit2 = to_hex[checksum & 0x0F];ar you getting the low and high part of the byte as in H 0000|0000 L

author: hamster_nz
author_rank: Super Contributor
timestamp: October 19, 2016, 10:20:10 am
content: Quote from: Precious Roy on October 19, 2016, 08:53:57 amYes, there is a little trap in that checksum has to be "unsigned char" or bad things may happen.For example, if checksum is "signed char" and 0x80 (-128 decimal), then checksum/16 = -8, or 0xF8, and then it will try to access to_hex[-8], causing bad things.Maybe I should have written it as follows to avoid those bad things...Code:digit1 = to_hex[(checksum / 16)&0xF];digit2 = to_hex[checksum & 0x0F];You could do the same transform programmatically to avoid the lookup table:Code:/* Split out the digits */digit1 = (checksum / 16)&0xF;digit2 = checksum & 0x0F;/* Convert digits to ASCII characters */digit1 += (digit1 > 9) ? 'A'-10 : '0';digit2 += (digit2 > 9) ? 'A'-10 : '0';But that is just fugly.Using the lookup table shows the intent better, but it does introduce that possibility of maybe looking outside of the lookup table that should be guarded against.Also, the lookup table removes the assumption that you are working in a character set where the digits and letters are sequential and leaves less magic to explain to those not familiar with ASCII codes.

author: amyk
author_rank: Super Contributor
timestamp: October 19, 2016, 11:06:30 am
content: Quote from: Precious Roy on October 19, 2016, 07:08:05 amThis is the key point, the checksum itself is a single byte but then gets converted into ASCII text format. So XOR together the 19 bytes, interpret the two checksum bytes as text representation of a hex byte, and then compare the resulting values.

author: Precious Roy
author_rank: Contributor
timestamp: October 19, 2016, 12:46:43 pm
content: hamster_nz Thanks for al your help, together with amyk everything is clear, i am just left wondering why it is written down so confusing 20 more words and everything would of been fine

author: bson
author_rank: Unknown
timestamp: October 19, 2016, 06:36:08 pm
content: I too would think I misunderstood if I saw a suggestion to use xor to perform checksumming.