
1. Re: Need help calculating a checksum
rhlilienkamp Jan 11, 2012 12:25 PM (in response to IanWilson)A Google search suggests that a mod by 256 is all you need/

2. Re: Need help calculating a checksum
comment Jan 11, 2012 1:39 PM (in response to IanWilson)Filemaker doesn't provide access to your data in binary form, so it's not quite clear what do you want to use as input to the function and what form should the result take.

3. Re: Need help calculating a checksum
IanWilson Jan 11, 2012 7:46 PM (in response to comment)Hi
I want to process an incoming 15byte datastream, ie 87 FF FF 7F 7F 7F 7F 00 F8 7F 88 3E 00 FF 08, of which the 15th byte is the checksum. My intention is to loop through each byte calculating the checksum and then comparing the resulting final checksum to the 15th byte. If they're identical the data is OK. I'm going to be recording the data using the Troi Serial plugin hopefully, but I don't want to buy the plugin until I know I can calculate the checksum.
Ian

4. Re: Need help calculating a checksum
RonSmithMD Jan 12, 2012 1:50 AM (in response to IanWilson)Can you tell more about the RS232 device that you are interfacing and how you are interfacing?
Ron Smith, MD
Isn't technology just fascinatingly maddening... it makes the process of messing things up so much more streamlined and enjoyable!
=)

5. Re: Need help calculating a checksum
comment Jan 12, 2012 3:33 AM (in response to IanWilson)IanWilson wrote:
I want to process an incoming 15byte datastream, ie 87 FF FF 7F 7F 7F 7F 00 F8 7F 88 3E 00 FF 08, of which the 15th byte is the checksum.
...
I don't want to buy the plugin until I know I can calculate the checksum.
If the plugin returns a text string in the form of "87 FF FF 7F 7F 7F 7F 00 F8 7F 88 3E 00 FF 08" you will be able to calculate/verify the checksum. And if you can point us to the exact algorithm your provider is using, we may be able to help you with the how.

6. Re: Need help calculating a checksum
IanWilson Jan 16, 2012 4:16 AM (in response to comment)That's exactly how the data will be received. The algorithm is an 8bit CRC polynomial x8+x2+x+1. Does this help? I've managed to knock up a bit of C in Xcode which does the job, but it'll have to be called via a shell script from an FM script step and I'm not sure that it'll be fast enough.
Ian

7. Re: Need help calculating a checksum
comment Jan 16, 2012 11:00 AM (in response to IanWilson)IanWilson wrote:
The algorithm is an 8bit CRC polynomial x8+x2+x+1. Does this help?
I am afraid it doesn't mean much to me. I did a short lookaround, but what I found doesn't seem to fit your situation.
There is another thing you should keep in mind. Most of these algorithms were designed to be executed by hardware operating in real time on binary level. It's possible that the equivalent mathematical operation, when performed in decimal, can be much simpler  perhaps even as simple as suggested by Ralph above. This is wellworth investigating, because Filemaker is by no means a numbercruncher.

8. Re: Need help calculating a checksum
thosliot Jan 17, 2012 3:34 AM (in response to IanWilson)Ian
I believe the following 3 custom functions will enable you to achieve what you want:
The first CF converts a hex string to a binary string:
HexAsBinary ( hexString ) =
Let ([
n = Position ( "0123456789ABCDEF" ; Left ( hexString ; 1 ) ; 1 ; 1 )  1 ;
b = Choose ( n ; "0000" ; "0001" ; "0010" ; "0011" ; "0100" ; "0101" ; "0110" ; "0111" ; "1000" ; "1001" ; "1010" ; "1011" ; "1100" ; "1101" ; "1110" ; "1111" )
] ;
Case (
IsEmpty ( hexString ) ; "" ; // end recursion
n < 0 ; Evaluate ( "." ) ; // invalid argument
b & HexAsBinary ( Replace ( hexString ; 1 ; 1 ; "" ) )
)
)
The second CF does a bitwise XOR and is called in the final CF:
BitXOR ( bitString1 ; bitString2 ) =
Let ([
b1 = bitString1 ;
b2 = bitString2 ;
l1 = Length ( b1 ) ;
l2 = Length ( b2 )
] ;
Case (
Filter ( b1 ; "01" ) ≠ b1 or Filter ( b2 ; "01" ) ≠ b2 ; Evaluate ( "." ) ; // invalid argument
not ( l1 or l2 ) ; b1 & b2 ; // end recursion
l1 ≠ l2 ; // arguments of unequal length
Left ( b1 ; l1  l2 ) & Left ( b2 ; l2  l1 ) & bitXOR ( Replace ( b1 ; l1 > l2 ; l1  l2 ; "" ) ; Replace ( b2 ; l2 > l1 ; l2  l1 ; "" ) ) ;
bitXOR ( Left ( b1 ; Length ( b1 )  1 ) ; Left ( b2 ; Length ( b2 )  1 ) ) & xor ( Right ( b1 ; 1 ) ; Right ( b2 ; 1 ) )
)
)
Finally, CRCcheck takes two binary string arguments (the checksummed string and the divisor) and returns either True (1) or False (0):
CRCcheck ( bitString ; bitDivisor ) =
Let ([
l = Length ( bitDivisor ) ;
bin = Left ( bitString ; l ) ;
rs = Case (
Left ( bin ; 1 ) ≠ "1" ; bitString ;
Replace ( bitString ; 1 ; l ; bitXOR ( bin ; bitDivisor ) )
)
] ;
Case (
Filter ( bitString ; "01" ) ≠ bitString or Filter ( bitDivisor ; "01" ) ≠ bitDivisor ; Evaluate ( "." ) ; // invalid argument
IsEmpty ( bitString ) ; True ; // checksum OK
Left ( rs ; 1 ) = "1" ; False ; // checksum fails
CRCcheck ( Replace ( rs ; 1 ; 1 ;"" ) ; bitDivisor )
)
)
So, the calc you need is:
CRCcheck ( HexAsBinary ( Substitute ( inputString ; " " ; "" ) ) ; "100000111" )
(removing the various tests for invalid arguments will speed things up somewhat)
cheers
Tom
PS It seems that my carefully laid out CFs have been somewhat munged by Jive
Message was edited by: Tom Elliott

9. Re: Need help calculating a checksum
IanWilson Jan 17, 2012 5:20 AM (in response to thosliot)Tom: How fantastic ... it just works brilliantly! Many, many thanks. Can I ask one more favour, please? Your functions will verify the incoming string's checksum, however in reply I have to send out a ninebyte reply: eight bytes of data and a checksum byte. Is it possible to modify your functions to take an eightbyte string parameter and return a CRC checksum?
Regards
Ian

10. Re: Need help calculating a checksum
thosliot Jan 18, 2012 2:43 AM (in response to IanWilson)1 of 1 people found this helpfulIan
It seems to me that the logic for creating a CRC checksum is considerably simpler if, rather than using simply the data string, additional zeros are first added at the end  the number of zeros being the length (in binary) of the required checksum.
The following CF takes two binary string arguments (the data with additional zeros as above and the divisor) and will (I think) return the required checksum byte as a binary string:
CRCcheckSum ( bitString ; bitDivisor ) =
Let ([
l = Length ( bitDivisor ) ;
p1 = Position ( bitString ; "1" ; 1 ; 1 )
] ;
Case (
p1 = 0 or Length ( bitString )  p1 < l  1 ; Right ( bitString ; l  1 ) ; // end recursion
CRCcheckSum ( Replace ( bitString ; p1 ; l ; bitXOR ( Middle ( bitString ; p1 ; l ) ; bitDivisor ) ) ; bitDivisor )
)
)
I assume you want the checksum in hex notation, in which case the following CF may be useful:
BinaryAsHex ( bitString ) =
Let ([
r4 = Right ( "0000" & bitString ; 4 ) ;
n = 8 * Left ( r4 ; 1 ) + 4 * Middle ( r4 ; 2 ; 1 ) + 2 * Middle ( r4 ; 3 ; 1 ) + Right ( r4 ; 1 ) ;
c = Middle ( "0123456789ABCDEF" ; n + 1 ; 1 )
] ;
Case (
Filter ( bitString ; "01" ) ≠ bitString ; Evaluate ( "." ) ; // invalid argument
IsEmpty ( bitString ) ; "" ; // end recursion
BinaryAsHex ( Left ( bitString ; Length ( bitString )  4 ) ) & c
)
)
Assuming you are using the same divisor as before, the calc you need for the checksum (in hex) is either:
BinaryAsHex ( CRCcheckSum ( HexAsBinary ( hexDataString & "00" ) ; "100000111" ) )
or
BinaryAsHex ( CRCcheckSum ( HexAsBinary ( hexDataString ) & "00000000" ) ; "100000111" ) )
The latter form is more generally useful, since in general the number of zeros added at the end of the (binary) data should be one less than the length of the (binary) divisor; the following will return the required string of zeros:
Substitute ( Left ( 10 ^ 400 1 ; Length ( bitDivisor )  1 ) ; "9" ; "0" )
===============
BTW I have a couple of improvements to the previous CFs:
Firstly, in BitXOR the calc for dealing with arguments of unequal length is unnecessarily complicated; the line that reads:
Left ( b1 ; l1  l2 ) & Left ( b2 ; l2  l1 ) & bitXOR ( Replace ( b1 ; l1 > l2 ; l1  l2 ; "" ) ; Replace ( b2 ; l2 > l1 ; l2  l1 ; "" ) ) ;
can be simplified to:
Left ( b1 ; l1  l2 ) & Left ( b2 ; l2  l1 ) & bitXOR ( Replace ( b1 ; 1 ; l1  l2 ; "" ) ; Replace ( b2 ; 1 ; l2  l1 ; "" ) ) ;
Secondly, I have optimised CRCcheck to skip all leading zeros in one pass (rather than one zero per pass); the new version is:
CRCcheck ( bitString ; bitDivisor ) =
Let ([
l = Length ( bitDivisor ) ;
p1 = Position ( bitString & "1" ; "1" ; 1 ; 1 ) ;
bs = Replace ( bitString ; 1 ; p1  1 ; "" ) ;
rs = Replace ( bs ; 1 ; l ; bitXOR ( Left ( bs ; l ) ; bitDivisor ) )
] ;
Case (
Filter ( bitString ; "01" ) ≠ bitString or Filter ( bitDivisor ; "01" ) ≠ bitDivisor ; Evaluate ( "." ) ; // invalid argument
Length ( bs ) < l ; IsEmpty ( bs ) ; // end recursion; OK iff remainder is all zeros
CRCcheck ( Replace ( rs ; 1 ; 1 ; "" ) ; bitDivisor )
)
)
cheers
Tom

11. Re: Need help calculating a checksum
comment Jan 18, 2012 7:11 AM (in response to thosliot)1 of 1 people found this helpfulThis is interesting. IMHO, the BitXOR() function could be implemented using a simpler approach:
BitXOR ( n ; m ) =
Let ( [ LSB = Right ( n ; 1 ) xor Right ( m ; 1 ) ; lenN = Length ( n ) ; lenM = Length ( m ) ] ; Case ( Max ( lenN ; lenM ) > 1 ; BitXOR ( Left ( n ; lenN  1 ) ; Left ( m ; lenM  1 ) ) ) & LSB )

12. Re: Need help calculating a checksum
IanWilson Jan 18, 2012 9:32 PM (in response to thosliot)Tom: Once again I have to thankyou very, very much.
After making the changes to the previous functions, I noticed there was an error in the line
BinaryAsHex ( CRCcheckSum ( HexAsBinary ( hexDataString ) & "00000000" ) ; "100000111" ) )
(One extra closing bracket) but after correcting it the function worked flawlessly. This is exactly what I need to continue development of my solution.
You're a genius!
Ian

13. Re: Need help calculating a checksum
thosliot Jan 19, 2012 12:01 AM (in response to comment)On 18 Jan 2012, at 15:10, comment wrote
This is interesting. IMHO, the BitXOR() function could be implemented using a simpler approach:
Yes, that's much neater

14. Re: Need help calculating a checksum
IanWilson Jan 19, 2012 1:11 AM (in response to comment)Thankyou for your suggestion. I've replaced Tom's function with yours. The solutions are so much neater than my attempts to convert a C script. I do wish FileMaker would index its repeating fields starting with 0 rather than 1 .... after all they are arrays. Life would be so much simpler when you're trying to convert C and PHP functions into FileMaker!
Ian