Prev: launching wish from tclsh
Next: tcl/tk on Windows: "This application has requested the Runtime to terminate it in an unusual way" on quit
From: Paul Whitfield on 15 Mar 2006 22:24 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 15 Mar 2006 22:42 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 16 Mar 2006 02:01 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 16 Mar 2006 03:03 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 16 Mar 2006 03:16
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 |