1 2 Previous Next 16 Replies Latest reply on Jan 19, 2012 11:39 AM by timwhisenant

    Need help calculating a checksum

    IanWilson

      I'd really like some help in creating a custom function to create an 8-bit polynomial CRC checksum. Is there anyone who can point me in the right direction?

       

      Ian

        • 1. Re: Need help calculating a checksum
          rhlilienkamp

          A Google search suggests that a mod by 256 is all you need/

          • 2. Re: Need help calculating a checksum
            comment

            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

              Hi

              I want to process an incoming 15-byte 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 plug-in hopefully, but I don't want to buy the plug-in until I know I can calculate the checksum.

               

              Ian

              • 4. Re: Need help calculating a checksum
                RonSmithMD

                Can you tell more about the RS232 device that you are interfacing and how you are interfacing?

                 

                Ron Smith, MD

                ron@ronsmithmd.com

                 

                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

                  IanWilson wrote:

                   

                  I want to process an incoming 15-byte 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 plug-in 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

                    That's exactly how the data will be received. The algorithm is an 8-bit 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

                      IanWilson wrote:

                       

                      The algorithm is an 8-bit CRC polynomial x8+x2+x+1. Does this help?

                       

                      I am afraid it doesn't mean much to me. I did a short look-around, 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 well-worth investigating, because Filemaker is by no means a number-cruncher.

                      • 8. Re: Need help calculating a checksum
                        thosliot

                        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

                          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 nine-byte reply: eight bytes of data and a checksum byte. Is it possible to modify your functions to take an eight-byte string parameter and return a CRC checksum?

                           

                          Regards

                           

                          Ian

                          • 10. Re: Need help calculating a checksum
                            thosliot

                            Ian

                             

                            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

                            1 of 1 people found this helpful
                            • 11. Re: Need help calculating a checksum
                              comment

                              This 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
                              )
                              
                              1 of 1 people found this helpful
                              • 12. Re: Need help calculating a checksum
                                IanWilson

                                Tom: Once again I have to thank-you 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

                                  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

                                    Thank-you 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

                                    1 2 Previous Next