Freitag, 28. Oktober 2011

Berechnen der NMEA Checksumme / Computing the NMEA checksum

Die National Marine Electronics Association (NMEA) zeichnet u.a. für den digitalen Datenaustausch bei GPS Geräten verantwortlich. Egal ob wir ein solches Gerät auf einem Schiff, im Auto, am Fahrrad oder beim Wandern benutzen. Die zum Einsatz kommenden Datensätze entspringen (mit kleinen individuellen Herstellervarianten) den NMEA Definitionen.

Da jedwede Art der Datenübertragung qualitativen Schwankungen des Übertragungsmediums unterliegt, beinhaltet die Definition der Datensätze eine Checksumme die zur Verifikation des korrekten Empfanges herangezogen wird.

Der u.a. Beispielcode zeigt, wie einfach die Überprüfung der Checksumme eines solchen Datensatzes in VFP realisiert werden kann.

INFO: Der als Basis dienende Datenbereich des jeweiligen Datensatzes beginnt grundsätzlich hinter dem $ Zeichen und endet am * dem sich dann die Checksumme des Datenbereichs anschliesst.

$GPXTE,A,A,0.67,L,N*6F

* // NMEA Checksumme berechnen
CLEAR 

* // Quelle der Musterstrings: http://www.gpsinformation.org/dale/nmea.htm
LOCAL laString( 1 , 19 )
laString(  1 ) = [$GPGGA,162045,5058.809,N,00647.103,E,1,03,2.5,63.1,M,47.2,M,,*79]
laString(  2 ) = [$GPGSA,A,3,04,05,,09,12,,,24,,,,,2.5,1.3,2.1*39]
laString(  3 ) = [$GPGSV,2,1,08,01,40,083,46,02,17,308,41,12,07,344,39,14,22,228,45*75]
laString(  4 ) = [$GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A]
laString(  5 ) = [$GPGLL,4916.45,N,12311.12,W,225444,A,*1D]
laString(  6 ) = [$GPVTG,054.7,T,034.4,M,005.5,N,010.2,K*48]
laString(  7 ) = [$GPWPL,4807.038,N,01131.000,E,WPTNME*5C]
laString(  8 ) = [$GPAAM,A,A,0.10,N,WPTNME*32]
laString(  9 ) = [$GPAPB,A,A,0.10,R,N,V,V,011,M,DEST,011,M,011,M*3C]
laString( 10 ) = [$GPBOD,045.,T,023.,M,DEST,START*01]
laString( 11 ) = [$GPBWC,225444,4917.24,N,12309.57,W,051.9,T,031.6,M,001.3,N,004*29]
laString( 12 ) = [$GPRMB,A,0.66,L,003,004,4917.24,N,12309.57,W,001.3,052.5,000.5,V*20]
laString( 13 ) = [$GPRTE,2,1,c,0,W3IWI,DRIVWY,32CEDR,32-29,32BKLD,32-I95,32-US1,BW-32,BW-198*69]
laString( 14 ) = [$GPXTE,A,A,0.67,L,N*6F]
laString( 15 ) = [$HCHDG,101.1,,,7.1,W*3C]
laString( 16 ) = [$GPZDA,201530.00,04,07,2002,00,00*60]
laString( 17 ) = [$GPMSK,318.0,A,100,M,2*45]
laString( 18 ) = [$GPMSS,55,27,318.0,100,*66]
laString( 19 ) = [$PGRME,15.0,M,45.0,M,25.0,M*1C]
FOR liflag = 1 TO ALEN( laString )
    ? laString( liFlag )
    ? GetNMEACheckSum( laString( liFlag ) )
ENDFOR

FUNCTION GetNMEACheckSum as String
LPARAMETERS vNMEAString as String

    LOCAL lcString as String, liCheck as Integer, i as Integer

    IF    AT( [$] , vNMEAString ) > 0 ;
    AND    AT( [*] , vNMEAString ) > 0
        lcString    = STREXTRACT( vNMEAString , [$] , [*] , 1 )
    ELSE 
        lcString = vNMEAString
    ENDIF 
    STORE 0 TO liCheck , i

    FOR i = 1 TO LEN( lcString )

        liCheck = BITXOR( liCheck , ASC( SUBSTR( lcString , i , 1 ) ) )

    ENDFOR 

    RETURN RIGHT(TRANSFORM( liCheck , [@0] ) , 2 )
    
ENDFUNC 

Die Generierung der Prüfziffer beruht auf einer XOR Verknüpfung des aktuellen XOR Ergebnisses mit dem nächsten Byte des Datenbereichs. Die erste Verknüpfung erfolgt auf Basis des Wertes 0 mit dem 1. Byte.
Das Endergebnis wird ins Hexadezimalformat gewandelt wodurch eine Wertigkeit von 0-255 (00-FF) gewährleistet ist.

Was ist nun dieses 'XOR'?

XOR Vergleiche sind die einfachste Methode, auf Bits basierende Prüfungen zu realisieren. Mit Hilfe eines Prüfbits kann der Status eines als Grundlage herangezogenen Bits jederzeit korrigiert werden.
Die Idee dahinter ist, wenn zwei Werte (Bits) miteinander verglichen werden, dann sind sie entweder gleich (Prüfbit = 0) oder ungleich (Prüfbit = 1). Aufgrund dieser Logik kann nun eines der beiden Bits auf Basis des anderen sowie des Prüfbits wieder hergestellt werden.

Die entsprechende Funktion innerhalb von Visual Foxpro lautet BITXOR()

Die verwendeten Musterdatensätze stammen von hier:
http://www.gpsinformation.org/dale/nmea.htm

Keine Kommentare:

Kommentar veröffentlichen