From: Paul Whitfield on
Jeff Waite wrote:
> I'm still having a problem with creating a 16-bit checksum. I've
> tried using cksum, sum, and crc but they all produce values that are
> significantly different than what I need. I suppose they may be
> computing the checksum differently. Below is an example of how I need
> to compute the checksum.
>
> I suspect that I'm going to have to build my own algorithm. Does
> anyone know which TCL commands I can use to do the following:
>
> 1. Sum a series of hex numbers
> 2. Perform a bit flip (binary complement)
>
> FYI, I'm trying to create a checksum for a series of hex numbers. For
> example:
>
> Input:
>
> \x00\x4d\x41\x49\x4e\x00\x00\x00\x00\x26\x00\x04\x05\x0f\x09\x01\x06\xef\xf2\x01\xf2\xf3\x01\xf3\x54\x65\x73\x74\x69\x6e\x67\x20\x31\x32\x33\xef
>
> 1. Sum up all the numbers
>
> Sum = 0AB1
>
> 2. Convert to binary
>
> 0000 1010 1011 0001
>
> 3. Take the complement (bit flip)
>
> 1111 0101 0100 1110
>
> 4. Convert back to hex
>
> F54E
>
> 5. Show low byte first and then high byte
>
> 4EF5
>
> Checksum = 4EF5
>
> Jeff Waite wrote:
>> What is the best way to compute a 16-bit checksum in TCL? I've tried
>> using the cksum() and crc::sum commands but I just receive the error
>> "invalid command name."
>>
>> Here's my code:
>>
>> set data
>> \x00\x4d\x41\x49\x4e\x00\x00\x00\x00\x26\x00\x04\x05\x0f\x09\x01\x06\xef\xf2\x01\xf2\xf3\x01\xf3\x54\x65\x73\x74\x69\x6e\x67\x20\x31\x32\x33\xef
>> LogToScreen "Checksum: cksum"
>> set cks [cksum($data)]
>> LogToScreen $cks
>> LogToScreen "Checksum: crc::sum"
>> set crcsum [crc::sum -format 0x%X $data]
>> LogToScreen $crcsum
>>
>> FYI, I'm trying to create a checksum for a series of hex numbers. For
>> example:
>>
>> Input:
>> \x00\x4d\x41\x49\x4e\x00\x00\x00\x00\x26\x00\x04\x05\x0f\x09\x01\x06\xef\xf2\x01\xf2\xf3\x01\xf3\x54\x65\x73\x74\x69\x6e\x67\x20\x31\x32\x33\xef
>>
>> 1. Sum up all the numbers
>>
>> Sum = 0AB1
>>
>> 2. Convert to binary
>>
>> 0000 1010 1011 0001
>>
>> 3. Take the complement
>>
>> 1111 0101 0100 1110
>>
>> 4. Convert back to hex
>>
>> F54E
>>
>> 5. Show low byte first and then high byte
>>
>> 4EF5
>>
>> Checksum = 4EF5
>

Here is my attempt, the numbers don't work out the
same as your example... but I think what I have done
is correct.

Please note: your problem description was not very precise:
"Sum up all the numbers" is not a complete description,
a better description would be "16 bits sum of each BYTE"

set data
"\x00\x4d\x41\x49\x4e\x00\x00\x00\x00\x26\x00\x04\x05\x0f\x09\x01\x06\xef\xf2\x01\xf2\xf3\x01\xf3\x54\x65\x73\x74\x69\x6e\x67\x20\x31\x32\x33\xef"

proc checksum data {
set sum 0
for { set i 0 } { $i < [ string length $data ] } { incr i } {
binary scan $data "@${i}c" int

incr sum $int
puts "[format "%x, %x" $sum $int ]"
}
puts "[format %x $sum]"
set sum [ expr { ( (~$sum << 8 ) & 0xff00 ) | (( ~$sum >> 8 ) &
0x00ff ) } ]
return $sum
}

puts "Checksum is [ format %x [ checksum $data ] ]"


And the output is

set data
"\x00\x4d\x41\x49\x4e\x00\x00\x00\x00\x26\x00\x04\x05\x0f\x09\x01\x06\xef\xf2\x01\xf2\xf3\x01\xf3\x54\x65\x73\x74\x69\x6e\x67\x20\x31\x32\x33\xef"

proc checksum data {
set sum 0
for { set i 0 } { $i < [ string length $data ] } { incr i } {
binary scan $data "@${i}c" int

incr sum $int
puts "[format "%x, %x" $sum $int ]"
}
puts "[format %x $sum]"
set sum [ expr { ( (~$sum << 8 ) & 0xff00 ) | (( ~$sum >> 8 ) &
0x00ff ) } ]
return $sum
}


puts "Checksum is [ format %x [ checksum $data ] ]"


Regards

Paul
From: Paul Whitfield on
Jeff Waite wrote:
> I'm still having a problem with creating a 16-bit checksum. I've
> tried using cksum, sum, and crc but they all produce values that are
> significantly different than what I need. I suppose they may be
> computing the checksum differently. Below is an example of how I need
> to compute the checksum.
>
> I suspect that I'm going to have to build my own algorithm. Does
> anyone know which TCL commands I can use to do the following:
>
> 1. Sum a series of hex numbers
> 2. Perform a bit flip (binary complement)
>
> FYI, I'm trying to create a checksum for a series of hex numbers. For
> example:
>
> Input:
>
>
\x00\x4d\x41\x49\x4e\x00\x00\x00\x00\x26\x00\x04\x05\x0f\x09\x01\x06\xef\xf2\x01\xf2\xf3\x01\xf3\x54\x65\x73\x74\x69\x6e\x67\x20\x31\x32\x33\xef
>
> 1. Sum up all the numbers
>
> Sum = 0AB1
>
> 2. Convert to binary
>
> 0000 1010 1011 0001
>
> 3. Take the complement (bit flip)
>
> 1111 0101 0100 1110
>
> 4. Convert back to hex
>
> F54E
>
> 5. Show low byte first and then high byte
>
> 4EF5
>
> Checksum = 4EF5
>

Here is my attempt, the numbers don't work out the
same as your example... but I think what I have done
is correct.

Please note: your problem description was not very precise:
"Sum up all the numbers" is not a complete description,
a better description would be

"Add the value of each 8-bit value to a 16 bit sum"

set data
"\x00\x4d\x41\x49\x4e\x00\x00\x00\x00\x26\x00\x04\x05\x0f\x09\x01\x06\xef\xf2\x01\xf2\xf3\x01\xf3\x54\x65\x73\x74\x69\x6e\x67\x20\x31\x32\x33\xef"

proc checksum data {
set sum 0
for { set i 0 } { $i < [ string length $data ] } { incr i } {
binary scan $data "@${i}c" int

incr sum $int
puts "[format "%x, %x" $sum $int ]"
}
puts "[format %x $sum]"
set sum [ expr { ( (~$sum << 8 ) & 0xff00 ) | (( ~$sum >> 8 ) &
0x00ff ) } ]
return $sum
}

puts "Checksum is [ format %x [ checksum $data ] ]"


And the output is

0, 0
4d, 4d
8e, 41
d7, 49
125, 4e
125, 0
125, 0
125, 0
125, 0
14b, 26
14b, 0
14f, 4
154, 5
163, f
16c, 9
16d, 1
173, 6
162, ffffffef
154, fffffff2
155, 1
147, fffffff2
13a, fffffff3
13b, 1
12e, fffffff3
182, 54
1e7, 65
25a, 73
2ce, 74
337, 69
3a5, 6e
40c, 67
42c, 20
45d, 31
48f, 32
4c2, 33
4b1, ffffffef
4b1
Checksum is 4efb


Regards

Paul

From: Gerald W. Lester on
Jeff Waite wrote:
> I'm still having a problem with creating a 16-bit checksum. I've
> tried using cksum, sum, and crc but they all produce values that are
> significantly different than what I need. I suppose they may be
> computing the checksum differently.

Yes they each have their documented algorithms -- and none of them match the
one you (rather imprecisely describe below).

> Below is an example of how I need
> to compute the checksum.
>
> I suspect that I'm going to have to build my own algorithm. Does
> anyone know which TCL commands I can use to do the following:

Sure: expr, binary scan, foreach, string range, format, set, and maybe proc
and return.

>
> 1. Sum a series of hex numbers
> 2. Perform a bit flip (binary complement)
>
> FYI, I'm trying to create a checksum for a series of hex numbers. For
> example:
>
> Input:
>
> \x00\x4d\x41\x49\x4e\x00\x00\x00\x00\x26\x00\x04\x05\x0f\x09\x01\x06\xef\xf2\x01\xf2\xf3\x01\xf3\x54\x65\x73\x74\x69\x6e\x67\x20\x31\x32\x33\xef
>
> 1. Sum up all the numbers
>
> Sum = 0AB1
>
> 2. Convert to binary
>
> 0000 1010 1011 0001
>
> 3. Take the complement (bit flip)
>
> 1111 0101 0100 1110
>
> 4. Convert back to hex
>
> F54E
>
> 5. Show low byte first and then high byte
>
> 4EF5
>
> Checksum = 4EF5
>

Try:
proc checksum {str} {
binary scan $str c* byteList
set sum 0
foreach bye $byteList {
set sum [expr {($sum + $bye & 0xff}) & 0xffff}]
}
set sumStr [format {%4.4x} [expr {~$sum & 0xffff}]]
return [string range $sumStr 2 3][string range $sumStr 0 1]
}

BTW, this is a rather strange algorithm would you care to share what/where
it is being used (just to satisfy my curiosity)?

--
+--------------------------------+---------------------------------------+
| Gerald W. Lester |
|"The man who fights for his ideals is the man who is alive." - Cervantes|
+------------------------------------------------------------------------+
From: Paul Whitfield on
Gerald W. Lester wrote:
> Jeff Waite wrote:
>> I'm still having a problem with creating a 16-bit checksum. I've
>> tried using cksum, sum, and crc but they all produce values that are
>> significantly different than what I need. I suppose they may be
>> computing the checksum differently.
>
> Yes they each have their documented algorithms -- and none of them match
> the one you (rather imprecisely describe below).
>
>> Below is an example of how I need
>> to compute the checksum.
>>
>> I suspect that I'm going to have to build my own algorithm. Does
>> anyone know which TCL commands I can use to do the following:
>
> Sure: expr, binary scan, foreach, string range, format, set, and maybe
> proc and return.

<SNIP> Worked example removed </SNIP>

> BTW, this is a rather strange algorithm would you care to share
> what/where it is being used (just to satisfy my curiosity)?

Examples where I have seen this "type" of checksum include:

* motorola S-record file, that is an ASCII file format that is used for
storing binary file.
* simple communication protocols that use a simple "check sum" like
this. Often in embedded processors with limited processing power/resources.

The bad thing about such algorithms is that they are not that
good at detecting anything other than a single bit error.

Regards

Paul
From: Paul Whitfield on
Gerald W. Lester wrote:
> Jeff Waite wrote:
>> I'm still having a problem with creating a 16-bit checksum. I've
>> tried using cksum, sum, and crc but they all produce values that are
>> significantly different than what I need. I suppose they may be
>> computing the checksum differently.
>
> Yes they each have their documented algorithms -- and none of them match
> the one you (rather imprecisely describe below).
>
>> Below is an example of how I need
>> to compute the checksum.
>>
>> I suspect that I'm going to have to build my own algorithm. Does
>> anyone know which TCL commands I can use to do the following:
>
> Sure: expr, binary scan, foreach, string range, format, set, and maybe
> proc and return.
>
>>
>> 1. Sum a series of hex numbers
>> 2. Perform a bit flip (binary complement)
>>
>> FYI, I'm trying to create a checksum for a series of hex numbers. For
>> example:
>>
>> Input:
>>
>> \x00\x4d\x41\x49\x4e\x00\x00\x00\x00\x26\x00\x04\x05\x0f\x09\x01\x06\xef\xf2\x01\xf2\xf3\x01\xf3\x54\x65\x73\x74\x69\x6e\x67\x20\x31\x32\x33\xef
>>
>>
>> 1. Sum up all the numbers
>>
>> Sum = 0AB1
>>
>> 2. Convert to binary
>>
>> 0000 1010 1011 0001
>>
>> 3. Take the complement (bit flip)
>>
>> 1111 0101 0100 1110
>>
>> 4. Convert back to hex
>>
>> F54E
>>
>> 5. Show low byte first and then high byte
>>
>> 4EF5
>>
>> Checksum = 4EF5
>>
>
> Try:
> proc checksum {str} {
> binary scan $str c* byteList
> set sum 0
> foreach bye $byteList {
> set sum [expr {($sum + $bye & 0xff}) & 0xffff}]
> }
> set sumStr [format {%4.4x} [expr {~$sum & 0xffff}]]
> return [string range $sumStr 2 3][string range $sumStr 0 1]
> }
>
> BTW, this is a rather strange algorithm would you care to share
> what/where it is being used (just to satisfy my curiosity)?

There is a typo in this example, the bracing in the expr are wrong
and it does not give the correct result.. BUT

....it made me see the mistake in my earlier attempt, I needed to
force the bytes to be unsigned by masking with 0xff:

Here is a fixed version of my code that give the correct result,
using a better scan format cribbed from Gerald ...

proc checksum data {
set sum 0
binary scan $data "c*" bytes
foreach int $bytes {
set sum [ expr { $sum + ( $int & 0xff ) } ]
}
set sum [ expr { ( (~$sum << 8 ) & 0xff00 ) | (( ~$sum >> 8 ) &
0x00ff) } ]
return $sum
}

Hope that helps

Paul