1# Copyright (c) 1999-2000 Jo�o Pedro Gon�alves <joaop@sl.pt>.
2#All rights reserved. This program is free software;
3#you can redistribute it and/or modify it under the same terms as Perl itself.
4
5package GPS::NMEA;
6
7use GPS::Base ();
8use GPS::Serial ();
9use GPS::NMEA::Handler ();
10
11use strict;
12use Carp;
13use vars qw($VERSION @ISA);
14
15require Exporter;
16
17@ISA = qw(GPS::Base GPS::Serial GPS::NMEA::Handler);
18
19$VERSION = 1.12;
20
21use FileHandle;
22
23sub new {
24    my $class = shift;
25    my %param = @_;
26    $param{'Protocol'} ||= 'NMEA';
27
28    my $self = $class->SUPER::common_new(%param);
29    bless $self, $class;
30
31    $self;
32}
33
34sub parse {
35    my $self = shift;
36    my $line = $self->_readline; #from GPS::Serial
37    while () {
38	my $short_cmd = $self->parse_line($line);
39	return $short_cmd if defined $short_cmd;
40    }
41}
42
43sub parse_line {
44    my($self, $line) = @_;
45    my ($csum,$cmd,$short_cmd);
46
47    #remove trailing chars
48    chomp($line);$line =~ s/\r//g;
49
50    #Test checksum
51    if ($line =~  s/\*(\w\w)$//) {
52	$csum = $1;
53	#XXX del? return $self->parse(@_) unless $csum eq $self->checksum($line);
54	return undef unless $csum eq $self->checksum($line);
55    }
56
57    $cmd = (split ',',$line)[0];
58    ($short_cmd = $cmd) =~ s/^\$//;
59
60    print "COMMAND: $short_cmd ($line)\n" if $self->verbose;
61    if ($self->can($short_cmd)) {
62	$self->$short_cmd($line);
63    } elsif ($self->verbose) {
64	print "Can't handle $short_cmd\n";
65    }
66    $short_cmd;
67}
68
69
70sub get_position {
71    #($latsign,$lat,$lonsign,$lon)
72    my $self = shift;
73
74    until ($self->parse eq 'GPRMC') {
75	1;
76    }
77    ;				#Recommended minimum specific
78    my $d = $self->{NMEADATA};
79    return ($d->{lat_NS},
80	    $self->parse_ddmm_coords($d->{lat_ddmm}),
81	    $d->{lon_EW},
82	    $self->parse_ddmm_coords($d->{lon_ddmm}));
83}
84
85sub get_altitude {
86    my $self = shift;
87    until ($self->parse eq 'PGRMZ') {
88	1;
89    }
90    ;				#Altitude
91    my $d = $self->{NMEADATA};
92    return ($d->{alt}/0.3048);	#Metric
93}
94
95sub parse_ddmm_coords {
96    my $self = shift;
97    $_ = shift;
98    my $deg;
99    my ($dm,$sec) = split(/\./);
100
101    if (length($dm) == 4) {	#Lat (ddmm)
102	$deg = substr($dm,0,2,'');
103    } elsif (length($dm) == 5) { #Lon (dddmm)
104	$deg = substr($dm,0,3,'');
105
106    } else {
107	carp "Invalid coords\n";
108    }
109
110    $deg = sprintf("%d",$deg);
111    return "$deg.$dm$sec";
112}
113
114
115
116sub nmea_data_dump {
117    #dumps data received
118    my $self = shift;
119    my $d = $self->{NMEADATA};
120    print map {"$_ => $$d{$_}\n"} sort keys %{$self->{NMEADATA}};
121}
122
123# Calculate the checksum
124#
125sub checksum {
126    my ($self,$line) = @_;
127    my $csum = 0;
128    $csum ^= unpack("C",(substr($line,$_,1))) for(1..length($line)-1);
129
130    print "Checksum: $csum\n" if $self->verbose;
131    return (sprintf("%2.2X",$csum));
132}
133
134
135
1361;
137__END__
138
139=head1 NAME
140
141GPS::NMEA - Perl interface to GPS equipment using the NMEA Protocol
142
143=head1 SYNOPSIS
144
145  use GPS::NMEA;
146  $gps = new GPS::NMEA(  'Port'      => '/dev/ttyS0',
147	  		 'Baud'      => 9600,
148                );
149
150
151=head1 DESCRIPTION
152
153GPS::NMEA allows the connection and use of of a GPS receiver in perl scripts.
154
155Note that latitudes and longitudes are in DMM format.
156
157=over
158
159=head1 GETTING STARTED
160
161
162=head1 KNOWN LIMITATIONS
163
164
165=head1 BUGS
166
167
168=head1 EXAMPLES
169
170Get the position periodically:
171
172    #!/usr/bin/perl
173    use GPS::NMEA;
174
175    my $gps = GPS::NMEA->new(Port => '/dev/cuaa0', # or COM5: or /dev/ttyS0
176    			     Baud => 4800);
177    while(1) {
178        my($ns,$lat,$ew,$lon) = $gps->get_position;
179        print "($ns,$lat,$ew,$lon)\n";
180    }
181
182Get the internal NMEA dump:
183
184    #!/usr/bin/perl
185    use GPS::NMEA;
186    use Data::Dumper;
187
188    my $gps = GPS::NMEA->new(Port => '/dev/cuaa0', # or COM5: or /dev/ttyS0
189    			     Baud => 4800);
190    while(1) {
191        $gps->parse;
192
193	# Dump internal NMEA data:
194        $gps->nmea_data_dump;
195
196        # Alternative to look at the internal NMEA data:
197        require Data::Dumper;
198        print Data::Dumper->new([$gps->{NMEADATA}],[])->Indent(1)->Useqq(1)->Dump;
199    }
200    __END__
201
202=head1 AUTHOR
203
204Joao Pedro B Gon�alves , joaop@iscsp.utl.pt
205
206=head1 SEE ALSO
207
208=cut
209