PDA

View Full Version : Creating Checksum in PBP



Tom Gonser
- 1st March 2005, 02:43
I have a need to create a checksum for a NMEA sentence I am creating in PBP. I am sure others have done this, but I have not - has anyone found a way to cycle through variables and compute checksum on a group?

The situation is this:

I have the following variables :

Dec_lat1 var word
Dec_lat2 var word
Dec_latD var word
Dec_long1 var word
Dec_Long2 var word
Dec_longD var word
wpt var word
Cksum var word - 2 characters

--------------------------------------------

I need to construce a '$GPWPL sentence' (waypoint), and to do this need to create a checksum on everything except the '$' and the '*' which comes before the checksum.

Ultimately, I need to output the following to the GPS:

serout2 Apin4, 84,[,10,13,"$GPWPL,",#Dec_lat1,".",#Dec_lat2,",#Dec_latD,"]
serout2 Apin4, 84,[#Dec_long1,".",#Dec_long2,",#Dec_longD,","wpt"*",#Cksum]

It will look to the GPS like:

$GPWPL,119.098,W,47.3456,N,TOMHOME,*34

BUT

Problem is, the only code I can find for this is not compatible with PBP and deals with strings..

Public Function NMEA_Checksum(ByVal sSentence As String) As String
Dim i&, sum&

'The "sentence" is from position 1 (the $) to the "*"
'The checksum calc does NOT include the $ or *

For i = 2 To Len(sSentence) - 1
sum = sum Xor Asc(Mid$(sSentence, i, 1))
Next i

NMEA_Checksum = Right$("0" & Hex$(sum), 2)

'The returned value is a 2 character string containing the check sum value

Thanks,

Tom

mister_e
- 1st March 2005, 05:37
Deal with string is not as easy as in VB in PBP.

2 way to deal with string. Store each character in a Array byte.


Myarray var byte[5]
loop var byte

Myarray[0]="h"
Myarray[1]="e"
Myarray[2]="l"
Myarray[3]="l"
Myarray[4]="o"

for loop = 0 to 4
hserout [Myarray[loop]]
next
here: goto here


using the internal EEPROM


loop var byte
EEPROMData var byte

data @0,"hello"

for loop = 0 to 4
read loop, eepromdata
hserout [eepromdata]
next
here: goto here


there's also another way using DB in assembler but...

Tom Gonser
- 1st March 2005, 14:26
What I am most interested in is (even if I did a big loop to read all the data into an array) How would I create the checksum?

Seems I'd have to read the data character by character - compute the checksum of the character, then add it to the total until I am done?

sum = var byte ' my checksum handler
NMEA_sum = var byte ' my final checksum
myarray = byte(34)

If I have several variables, why not just read them each in turn:

For i = 1 to (number of characters in myarray)
sum=myarray(i)
- do the checksum routine, which I can't seem to translate to PBP
*** In VB: it looks like this
sum = sum Xor Asc(Mid$(sSentence, i, 1))
Next i

*** My attempt at PBP: looks like this
NMEA_sum = (sum ^(character(i))
Next i

*** then the VB:

NMEA_Checksum = Right$("0" & Hex$(sum), 2)

*** my attempd in PBP: No idea --

NMEA_sum=$sum (?????)

THEN:

NMEA_sum is the answer - a summed up value from all the characters in myarray(i)

Of course this does not work..

Help!

Tom Gonser
- 13th March 2005, 16:16
I *think* this routine generates a Checksum that can be used with NMEA/GPS. While I am not using for that exactly, I think the routine works, but I'd be interested in getting another set of eyes on it...

The objective in Checksum is to take each character in a sentence to be transmitted - Between the "$" and the "*" in a NMEA sentence, and XOR each one in sequence, creating a 'rolling XOR' through the sentence... (I think).

Anyway, THIS routine does that, and it generates something that looks like a checksum, and my GPS takes it, BUT.. can anyone help make this better, confirm it works, etc?

waypoint:
' create checksum '************** Checksum
WPT_array[1]="G"
WPT_array[2]="P"
WPT_array[3]="W"
WPT_array[4]="P"
WPT_array[5]="L"
WPT_array[6]=","
WPT_array[7]=Dec_lat1.byte0
WPT_array[8]=Dec_lat1.byte1
WPT_array[9]="."
WPT_array[10]=Dec_lat2.byte0
WPT_array[11]=Dec_lat2.byte1
WPT_array[12]=","
WPT_array[13]=S_byte
WPT_array[14]=","
WPT_array[15]=Dec_long1.byte0
WPT_array[16]=Dec_long1.byte1
WPT_array[17]="."
WPT_array[18]=Dec_lat2.byte0
WPT_array[19]=Dec_lat2.byte1
WPT_array[20]="."
WPT_array[21]=E_byte
WPT_array[22]=","
WPT_array[23]=TracID
WPT_array[24]=","
' Implied * not computed
p=0
cksum = %00000000
for p = 1 to 24
cksum = cksum^(WPT_array[p])
Next P
serout2 AGPSout, 16572,["$GPWPL,",#Dec_lat1,".",#Dec_lat2,",",S_Byte,","]
serout2 AGPSout, 16572,[#Dec_long1,".",#Dec_long2,",",E_Byte,",",#TracID,",*",HEX Cksum,10,13]
wp=%0
Return

Bruce
- 14th March 2005, 00:23
Your VB program is calculating the checksum using every single
ASCII digit. If you want to do this with your PIC, then you'll need
to work with single ASCII digits also. At least when calculating the
checksum.


X VAR BYTE
SUM VAR byte
Dec_lat1 VAR BYTE
Dec_lat2 VAR BYTE
C VAR BYTE [35]

' Load array string with "$GPWPL,119.98,W,47.3456,N,TOMHOME,*"

' Note: Dec_Lat1 & Dec_Lat2 ASCII values are computed in Num_To_ASCII
' sub-routine. This converts individual DIGits from each byte into ASCII.
' Array elements to be converted to ASCII are marked with an x.

C[0]="$" :C[1]="G" :C[2]="P" :C[3]="W" :C[4]="P" :C[5]="L"
C[6]="," :C[7]="x" :C[8]="x" :C[9]="x" :C[10]="." :C[11]="x"
C[12]="x" :C[13]="," :C[14]="W" :C[15]="," :C[16]="4" :C[17]="7"
C[18]="." :C[19]="3" :C[20]="4" :C[21]="5" :C[22]="6" :C[23]=","
C[24]="N" :C[25]="," :C[26]="T" :C[27]="O" :C[28]="M" :C[29]="H"
C[30]="O" :C[31]="M" :C[32]="E" :C[33]="," :C[34]="*"

MAIN:
SUM = 0 ' Clear SUM on entry
GOSUB Num_To_ASCII ' Convert Lat1 & Lat2 to ASCII for calculation
GOSUB CheckSum ' Calculate checksum of array
HSEROUT [STR C\35,HEX SUM,13,10] ' Now show retult
PAUSE 2000
GOTO Main

CheckSum:
' 33 bytes from "G" to "," chopping off "$" & "*"
FOR X = 1 TO 33
SUM = (SUM ^ C[X])
NEXT X
RETURN

Num_To_ASCII:
Dec_lat1 = 119
C[7] = Dec_lat1 DIG 2+"0" ' element c[7] = ASCII 1
C[8] = Dec_lat1 DIG 1+"0" ' element c[8] = ASCII 1
C[9] = Dec_lat1 DIG 0+"0" ' element c[9] = ASCII 9
Dec_lat2 = 98
C[11] = Dec_lat2 DIG 0+"0"
C[12] = Dec_lat2 DIG 1+"0"
RETURN

END

This returns the same checksum values as your VB program.

Just modify the Num_To_ASCII routine to work on whatever byte
(or word) variables you have your longitude/latitude data in. Convert
each digit to ASCII, and stuff them into the appropriate array element
spaces.

The output captured in a terminal program from the above is
$GPWPL,119.89,W,47.3456,N,TOMHOME,*23

A slightly modified version of your VB program outputs the same.


Private Sub Command1_Click()
Dim sText As String
Dim NMEAChecksum As String
Dim i&, sum&

sText = "$GPWPL,119.98,W,47.3456,N,TOMHOME,*"

For i = 2 To Len(sText) - 1
sum = sum Xor Asc(Mid$(sText, i, 1))
Next i

NMEAChecksum = Right$("0" & Hex$(sum), 2)

Debug.Print sText & NMEAChecksum

End Sub

Tom Gonser
- 14th March 2005, 13:05
WOW! That is some good thinking, thanks! I did not know I needed to convert to digits before XORing.

If I read this right, I only need to convert the #s into ASCII, which is why you marked them with X. The variable #s for a WPT sentence are:

dec_lat1
dec_lat2
dec_long1
dec_long2

the "N,S,E,W' are ascii anyway...

I am not sure I follow the structure of the routine tho:

Num_To_ASCII:
Dec_lat1 = 119
C[7] = Dec_lat1 DIG 2+"0" ' element c[7] = ASCII 1
C[8] = Dec_lat1 DIG 1+"0" ' element c[8] = ASCII 1
C[9] = Dec_lat1 DIG 0+"0" ' element c[9] = ASCII 9
Dec_lat2 = 98
C[11] = Dec_lat2 DIG 0+"0"
C[12] = Dec_lat2 DIG 1+"0"
RETURN

I see we are assinging specific digits to an array for computing the cksum from the variable Dec_Lat1.. but I don't know why there is a "+0" after the DIG X portion....

I also assume you are assigning Dec_lat2/Declat1 a specific number because in your example there is no value for these variables. In my case, I have values, so I will be calling them out of my array...

I think I will have to do this for Dec_lat and Dec_long too.

Thanks!

Tom

NavMicroSystems
- 14th March 2005, 14:09
Tom,

I have dealt with NMEA a few times in the past.

The checksum is optional, and you do not really need it
(as long as your wires aren't too long and the environment isn't too "noisy")

What the example does is pretty simple:

-----
Num_To_ASCII:
Dec_lat1 = 119
C[7] = Dec_lat1 DIG 2+"0" ' element c[7] = ASCII 1
-----

DIG2 of Dec_lat1 in this example is decimal 1 (or $01)
the ASCII value for the character "1" is 31, so you need to add 30
(which equals the the decimal value of the ASCII character "0")
to get the ASCII value for this character

You could also use this:
-----
C[7] = Dec_lat1 DIG 2+30 ' element c[7] = ASCII 1
-----

(hope it is not too confusing)

Bruce
- 14th March 2005, 14:58
Just look at any ASCII chart to understand what's happening.

With PBP most people assume sending serial data goes something like this;


X VAR BYTE
X = 123

Main
SEROUT2 0,16468,[DEC X]
PAUSEUS 200
GOTO Main

You would assume you're sending a single byte, but PBP is first converting your three decimal digits in X into three separate ASCII characters, and sending a total of three bytes. "1" then "2" then "3". That's what the DEC modifier does.

So your PC isn't receiving a single byte value of 123. It's receiving three separate bytes. ASCII characters 1 then 2 then 3. This is what it's using to calculate the checksum.

Since your PC checksum program runs a cumulative checksum calculated from each separate ASCII digit, you just need to do the same with your PIC-based cheksum program before sending the final checksum result to the PC.

Try running this with a PIC connected to your PC serial port, and see what displays in a terminal window.


X = 123

Main
HSEROUT [DEC X,13,10]
HSEROUT [X,13,10]
PAUSEUS 2000
GOTO Main

picnaut
- 16th March 2005, 04:49
Hi,

The attached file may be of some help.

Cheers.