#!/usr/bin/perl -w # NMEA parser # Waider / September 7, 2000 # Need a map? # http://www.mapquest.com/cgi-bin/ia_find?link=btwn/twn-map_latlong_degrees_form # grab all the input fields, especially the hidden ones. # set latdeg latmin latsec lngdeg lngmin lngsec appropriately # set "Find Map" to "Get Map" # call ia_find # look for http://sitemap.mapquest.com/mqmapgend?MQMapGenRequest, # that's your map. # 65th character in URL seems to control the magnification: # *->9->1->l->q->d->g->0->5->h # cont. region city street # You can also try: # #http://www.mapblast.com/gif? # # Location of Icon # Lat Long Icon # Icon: # 1 - circle with dot # 2 - circle with dot, nontransparent # 3 - small red circle # 4 - big red circle # 5 - cross #&IC=53.1913:-6.0801:8: # # Centre of map # Lat Long Scale # Smaller number = closer zoom. seems to zoom up pretty well. #&CT=53.1913:-6.0801:200000 # # @ scale = 5000, ( 0.0020 N =~ 130 pixels, 0.0060 W =~ 228 pixels ) # Width/Height of map #&W=456 #&H=259 # # Required # &FAM=mymapblast while (<>) { next if !s/^\$//; # discard header next if !s/\r\n$//; # discard trailer # do the checksum thing if ( s/\*([0-9A-F][0-9A-F])$// ) { my ( $csum ) = eval( "0x$1" ); for my $c ( split( // )) { $csum ^= ord( $c ); } if ( $csum ) { next; # invalid checksum } } # Break it up into fields my @fields = split( /,/ ); # Parse type of data shift @fields; # discard source/command # Woop. Check for proprietary sentence: if ( m/^P(...)(.*?),/ ) { if ( $1 eq 'GRM' ) { # GARMIN PROPRIETARY GARMIN: { # E - estimated error if ( $2 eq 'E' ) { if ( $fields[ 0 ] =~ /[0-9.]/) { # verify that we have data print "Estimated error: "; printf( "HPE: %f %s VPE: %f %s Spherical: %f %s\n", @fields); } } # Z - altitude. Always in feet. if ( $2 eq 'Z' ) { if ( $fields[ 0 ] =~ /[0-9.]/) { printf( "Altitude (%s): %d %s\n", $fields[ -1 ] == 2 ? "user" : "GPS", $fields[ 0 ], $fields[ 1 ] ); } } last GARMIN; } } else { # don't know what to do! AIE! print "command $2 from $1\n"; } } else { s/^(..)(.+?),//; my ( $source, $datatype ) = ( $1, $2 ); # print "command $datatype from "; if ( $source eq 'GP' ) { # print "GPS receiver\n"; } elsif ( $source eq 'LC' ) { # print "Loran-C receiver\n"; } elsif ( $source eq 'OM' ) { # print "Omega Navigation receiver\n"; } elsif ($source eq 'II' ) { # print "Integrated Instrumentation\n"; } else { print "$source ???\n"; } COMMAND: { # BOD Bearing, Origin to Destination # GGA GPS Fix Data if ( $datatype eq 'GGA' ) { print "--\n"; my ( $time, $lat, $latd, $long, $longd, $qual, $nsat, $hdil, $alt, $altu, $geo, $geou, $lastdgps, $dgpsid, @leftovers ) = @fields; # Is this good data? if ( $qual && $#fields == 11 ) { # field count drops sometimes. printf( "%02d:%02d:%02d ", substr( $time, 0, 2), substr( $time, 2, 2 ), substr( $time, 4, 2 )); printf( "%s%02d.%02d%02d %s%03d.%02d%02d ", $latd eq 'N' ? " " : "-", # N/S indicator substr( $lat, 0, 2 ), substr( $lat, 2, 2 ) * 100/60, substr( $lat, 4 ) * 100/60, $latd eq 'W' ? " " : "-", # E/W indicator substr( $long, 0, 3 ), substr( $long, 3, 2 ) * 100/60, substr( $long, 5 ) * 100/60 ); printf( "alt: %s%s (WGS84 + %s%s)) ", $alt, $altu, $geo, $geou ); printf( "(%d sats) ", $nsat ); print "\n"; } else { print "Something up: F $#fields\n" if $#fields != 11; } } elsif ( $datatype eq 'GLL' ) { print "Geographic Position, Latitude and Longitude\n"; # N/S val, N/S, E/W val, E/W, A => valid } elsif ( $datatype eq 'GSA' ) { print "GPS DOP and active satellites\n"; # A/M - auto/manual # 2/3 - 2D/3D fix # 12 spaces for satellite PRNs # PDOP (dilution of precision) # HDOP # VDOP } elsif ( $datatype eq 'GSV' ) { print "Satellites in view\n"; # Number of sentences for full data # Sentence N of the above # Number of sats in view # Sat PRN # Elev # Azimuth # Signal strength # Repate for up to 4 sats per sentence, 3 GSV sentences per packet } elsif ( $datatype eq 'RMB' ) { print "Recommended Minimum Navigation Information\n"; # A/V okay/warning # cross track error, nautical miles # directon to steer # origin waypoint ID # destination waypoint ID # dest lat DDMM.MM,N/S # dest long DDMM.MM E/W # Range to dest, nautical # true bearing to dest # velocity towards dest # A/V arrival alarm } elsif ( $datatype eq 'RMC' ) { print "Recommended minimum specific GPS/Transit data\n"; # time HHMMSS UTC # A/V # LAT N/S # LONG E/W # Speed, Knots # Course Made Good, True # Date of fix DDMMYY # Magnetic Variation dist, dir } elsif ( $datatype eq 'RTE' ) { print "Waypoints in active route\n"; # Sentences of data # sentence num # c omplete, w first listed start of current leg # route identifier # Waypoint IDs } elsif ( $datatype eq 'BOD' ) { print "Origin to destination bearing\n"; # Bearing, T (true) from STart to Dest # Bearing, M (magnetic) # Dest # Start } else { print "ERROR! Unhandled data $datatype\n"; } } } }