computing the checksum

Do you have a question? Post it now! No Registration Necessary.  Now with pictures!

•  Subject
• Author
• Posted on
I need to compute the checksum on a hex message sent to a lab machine
via Device::SerialPort.

This is the C code snippet and instructions in their manual:
Assume the message is held in buf. "buf" is an array of unsigned char.

unsigned char *buf
short int message_size;
unsigned char trailer[2];
trailer[0] = 0;
for (int i = 0; i < message_size; i++)
trailer[0] += buf[i];
trailer[0] |= 0x80; // Turning on high bite ensures this cannot be an
ETX byte
trailer[1] = 0x03; // End of message ETX

Here's what I have in my perl script (note I'm just printing to screen
at this point, not to the device):
#!/usr/bin/perl -w
use strict;
use Term::ANSIColor;
my \$status = chr(02);    # Start of message (STX)
\$status .= chr(hex(30));
\$status .= chr(hex(33));
\$status .= chr(hex(80));
\$status .= chr(hex(86));
\$status .= chr(hex(53));
\$status .= chr(hex(50));
\$status .= chr(hex(20));
\$status .= chr(hex(20));
\$status .= chr(hex(20));
\$status .= chr(hex(73));
my \$check_sum = 0;
my @reroute = unpack("H2"x length(\$status),\$status);
for my \$i (0 .. 10) {
\$check_sum += hex(\$reroute[\$i]);
print \$reroute[\$i];
\$i++;
}
\$check_sum |= hex(0x80);
\$status .= hex(\$check_sum);
\$status .= chr(03);
print color("red"), \$check_sum, color("reset");
print unpack("H*",\$status),"\n";

I know from their example that the checksum byte should be:
\$status .= chr(hex(89));

I do not know any C and am a noobie at perl.

CSG

Re: computing the checksum

On Fri, 29 Oct 2004 10:40:04 -0600, Spin wrote:
> I need to compute the checksum on a hex message sent to a lab machine
> via Device::SerialPort.
>
> This is the C code snippet and instructions in their manual:
> Assume the message is held in buf. "buf" is an array of unsigned char.
>
> unsigned char *buf
> short int message_size;
> unsigned char trailer[2];
> trailer[0] = 0;
> for (int i = 0; i < message_size; i++)
>     trailer[0] += buf[i];
> trailer[0] |= 0x80; // Turning on high bite ensures this cannot be an
> ETX byte
> trailer[1] = 0x03; // End of message ETX
>
> Here's what I have in my perl script (note I'm just printing to screen
> at this point, not to the device):
> #!/usr/bin/perl -w
> use strict;
> use Term::ANSIColor;
> my \$status = chr(02);    # Start of message (STX)
> \$status .= chr(hex(30));
> \$status .= chr(hex(33));
> \$status .= chr(hex(80));
> \$status .= chr(hex(86));
> \$status .= chr(hex(53));
> \$status .= chr(hex(50));
> \$status .= chr(hex(20));
> \$status .= chr(hex(20));
> \$status .= chr(hex(20));
> \$status .= chr(hex(73));
> my \$check_sum = 0;
> my @reroute = unpack("H2"x length(\$status),\$status);
> for my \$i (0 .. 10) {
>     \$check_sum += hex(\$reroute[\$i]);
>     print \$reroute[\$i];
>     \$i++;
> }
> \$check_sum |= hex(0x80);
> \$status .= hex(\$check_sum);
> \$status .= chr(03);
> print color("red"), \$check_sum, color("reset");
> print unpack("H*",\$status),"\n";

my \$buffer = "\x02\x30\x33\x80\x86\x53\x50\x20\x20\x20\x73";
my \$check_sum = unpack("%8C*", \$buffer) | 0x80;
printf "check sum = %x\n", \$check_sum;
\$buffer .= chr(\$check_sum) . chr(3);

> I know from their example that the checksum byte should be:
> \$status .= chr(hex(89));

A direct translation of the C version disagrees.  It says the checksum
should be 0xE1.

my \$buffer = (
chr(2) . chr(0x30) . chr(0x33) . chr(0x80) . chr(0x86) . chr(0x53) .
chr(0x50) . chr(0x20) . chr(0x20) . chr(0x20) . chr(0x73)
);

my \$check_sum = 0;
for (0..length \$buffer) {
\$check_sum += ord(substr(\$buffer, \$_, 1));
}

\$check_sum &= 0xFF; # remove all but least significant byte
\$check_sum |= 0x80; # turn on high bit to avoid ETX

printf "check sum = %x\n", \$check_sum;

\$buffer .= chr(\$check_sum) . chr(3);

The shorter example also calculates 0xE1 as your checksum.

--
Rocco Caputo - http://poe.perl.org /

Re: computing the checksum

Rocco Caputo wrote:
>   my \$check_sum = 0;
>   for (0..length \$buffer) {
>     \$check_sum += ord(substr(\$buffer, \$_, 1));
>   }
>
>   \$check_sum &= 0xFF; # remove all but least significant byte
>   \$check_sum |= 0x80; # turn on high bit to avoid ETX
>
>   printf "check sum = %x\n", \$check_sum;
>
>   \$buffer .= chr(\$check_sum) . chr(3);
>
</ Begin unrestrained gratitude>
Thank you soooooooooooooo much! It works!
</ End above>

They never said in the manual where to begin the checksum, but I had a
hunch that it began at byte 5, not at the start. I was right, and your
code calculated the checksum to be 89, same as theirs.

This hex stuff is a little dizzying sometimes...

Thanks again,
Caleb

Re: computing the checksum

> I need to compute the checksum on a hex message sent to a lab machine
> via Device::SerialPort.
>
> This is the C code snippet and instructions in their manual:
> Assume the message is held in buf. "buf" is an array of unsigned char.
>
> unsigned char *buf
> short int message_size;
> unsigned char trailer[2];
> trailer[0] = 0;
> for (int i = 0; i < message_size; i++)
>     trailer[0] += buf[i];
> trailer[0] |= 0x80; // Turning on high bite ensures this cannot be an
> ETX byte
> trailer[1] = 0x03; // End of message ETX
>
> Here's what I have in my perl script (note I'm just printing to screen
> at this point, not to the device):
> #!/usr/bin/perl -w
> use strict;
> use Term::ANSIColor;
> my \$status = chr(02);    # Start of message (STX)
> \$status .= chr(hex(30));
> \$status .= chr(hex(33));
> \$status .= chr(hex(80));
> \$status .= chr(hex(86));
> \$status .= chr(hex(53));
> \$status .= chr(hex(50));
> \$status .= chr(hex(20));
> \$status .= chr(hex(20));
> \$status .= chr(hex(20));
> \$status .= chr(hex(73));

This could be better written

my \$status = "\x02\x30\x33\x80\x86\x53\x50\x20\x20\x20\x73";

> my \$check_sum = 0;
> my @reroute = unpack("H2"x length(\$status),\$status);
> for my \$i (0 .. 10) {
>     \$check_sum += hex(\$reroute[\$i]);

Why are you doing this? Better would be

for (split //, \$status) {
\$check_sum += ord;
}

However, the C program seems to be relying on the fact that + for a char
will wrap around, so you want

\$check_sum %= 256;

as well.

>     print \$reroute[\$i];
>     \$i++;
> }
> \$check_sum |= hex(0x80);

\$check_sum |= 0x80;

> \$status .= hex(\$check_sum);

\$status .= chr(\$check_sum) . chr(03);

> \$status .= chr(03);
> print color("red"), \$check_sum, color("reset");
> print unpack("H*",\$status),"\n";
>
> I know from their example that the checksum byte should be:
> \$status .= chr(hex(89));

print "Corrext cksum" if \$check_sum == 0x89;