File Coverage

blib/lib/GPS/NMEA/Handler.pm
Criterion Covered Total %
statement 83 88 94.3
branch 20 40 50.0
condition n/a
subroutine 16 16 100.0
pod 0 11 0.0
total 119 155 76.7


line stmt bran cond sub pod time code
1             # Copyright (c) 1999-2000 João Pedro Gonçalves .
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              
5             package GPS::NMEA::Handler;
6              
7 2     2   12 use strict;
  2         3  
  2         68  
8 2     2   9 use vars qw($VERSION);
  2         2  
  2         161  
9              
10             $VERSION = sprintf("%d.%02d", q$Revision: 1.4 $ =~ /(\d+)\.(\d+)/);
11              
12 2     2   9 use POSIX qw(:termios_h);
  2         3  
  2         20  
13 2     2   2080 use FileHandle;
  2         4969  
  2         10  
14 2     2   656 use Carp;
  2         2  
  2         2985  
15              
16             #$|++;
17              
18             #$GPRMB,A,0.66,L,003,004,4917.24,N,12309.57,W,001.3,052.5,000.5,V*0B
19             #
20              
21             # $GPRMB,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>,<9>,<10>,<11>,<12>,<13>*hh
22             # 1) Data status, A=OK, V=warning
23             # 2) Cross-track error (nautical miles, 9.9 max)
24             # 3) L=steer left to correct, R=steer right to correct
25             # 4) Origin waypoint ID
26             # 5) Destination waypoint ID
27             # 6) Destination waypoint latitude
28             # 7) Destination waypoint latitude hemisphere
29             # 8) Destination waypoint longitude
30             # 9) Destination waypoint longitude hemisphere
31             # 10) Range to destination, nautical miles
32             # 11) True bearing to destination
33             # 12) Velocity towards destination, knots
34             # 13) Arrival alarm, A=Arrived, V=Not arrived
35              
36             sub GPRMB {
37             # RMB - Data when waypoint destination is active
38 1     1 0 4 my $self = shift;
39 1 50       8 $self->{NMEADATA} = {} unless ref($self->{NMEADATA});
40 1         3 my $d = $self->{NMEADATA};
41              
42             (undef,
43             $$d{data_valid},
44             $$d{cross_track_error_naut_miles},
45             $$d{steer_L_or_R},
46             $$d{origin_waypoint},
47             $$d{dest_waypoint},
48             $$d{dest_waypoint_lat},
49             $$d{dest_lat_NS},
50             $$d{dest_waypoint_lon},
51             $$d{dest_lon_EW},
52             $$d{range_dest},
53             $$d{bearing_dest},
54             $$d{velocity_dest_knots},
55             $$d{arrival_alarm}
56 1         22 ) = split(',',shift);
57 1         4 1;
58             }
59              
60              
61             #$GPGGA,033850,4748.811,N,12219.564,W,1,04,2.2,202.8,M,-18.3,M,,*7F
62             #
63              
64             # GPS-35:
65             # $GPGGA,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>,<9>,M,<10>,M,<11>,<12>*hh
66             # 1) UTC time of position fix, hhmmss format
67             # 2) Latitude, ddmm.mmmm format (leading zeroes will be transmitted)
68             # 3) Latitude hemisphere, N or S
69             # 4) Longitude, dddmm.mmmm format (leading zeros will be transmitted)
70             # 5) Longitude hemisphere, E or W
71             # 6) GPS quality indication, 0=no fix, 1=non-DGPS fix, 2=DGPS fix
72             # 7) Number of sats in use, 00 to 12
73             # 8) Horizontal Dilution of Precision 1.0 to 99.9
74             # 9) Antenna height above/below mean sea level, -9999.9 to 99999.9 meters
75             # 10) Geoidal height, -999.9 to 9999.9 meters
76             # 11) DGPS data age, number of seconds since last valid RTCM transmission (null if non-DGPS)
77             # 12) DGPS reference station ID, 0000 to 1023 (leading zeros will be sent, null if non-DGPS)
78              
79             sub GPGGA {
80             # Global Positioning System Fix Data
81              
82 1     1 0 6 my $self = shift;
83 1 50       9 $self->{NMEADATA} = {} unless ref($self->{NMEADATA});
84              
85 1         3 my $d = $self->{NMEADATA};
86             (undef,
87             $$d{time_utc},
88             $$d{lat_ddmm},
89             $$d{lat_NS},
90             $$d{lon_ddmm},
91             $$d{lon_EW},
92             $$d{fixq012},
93             $$d{num_sat_tracked},
94             $$d{hdop},
95             $$d{alt_meters},
96             $$d{alt_meters_units},
97             $$d{height_above_wgs84},
98             $$d{height_units},
99             $$d{sec_since_last_dgps_update},
100             $$d{dgps_station_id}
101 1         27 ) = split(',',shift);
102 1         19 $$d{time_utc} =~ s/(\d\d)(\d\d)(\d\d)/$1:$2:$3/g;
103 1         5 1;
104             }
105              
106             #$GPGSA,A,2,01,,,,23,,,,,,,,2.2,2.2,*1D
107             #
108              
109             # GPS-35:
110             # $GPGSA,<1>,<2>,<3>,<3>,<3>,<3>,<3>,<3>,<3>,<3>,<3>,<3>,<3>,<3>,<4>,<5>,<6>*hh
111             # 1) Mode, M=Manual, A=Automatic
112             # 2) Fix type, 1=no fix, 2=2D, 3=3D
113             # 3) PRN number, 01 to 32, of satellites used in solution (leading zeroes sent)
114             # 4) Position dilution of precision, 1.0 to 99.9
115             # 5) Horizontal dilution of precision, 1.0 to 99.9
116             # 6) Vertical dilution of precision, 1.0 to 99.9
117              
118             sub GPGSA {
119             # GPS DOP and active satellites
120 1     1 0 2 my $self = shift;
121 1 50       7 $self->{NMEADATA} = {} unless ref($self->{NMEADATA});
122              
123 1         3 my $d = $self->{NMEADATA};
124              
125             (undef,
126             $$d{auto_man_D},
127             $$d{dimen},
128             $$d{prn01a},
129             $$d{prn02a},
130             $$d{prn03a},
131             $$d{prn04a},
132             $$d{prn05a},
133             $$d{prn06a},
134             $$d{prn07a},
135             $$d{prn08a},
136             $$d{prn09a},
137             $$d{prn10a},
138             $$d{prn11a},
139             $$d{prn12a},
140             $$d{pdop},
141             $$d{hdop},
142             $$d{vdop}
143 1         19 ) = split(',',shift);
144 1         4 1;
145             }
146              
147             #$GPGSV,2,1,08,01,12,187,41,03,50,285,48,17,50,097,45,21,58,246,48*70
148             # multiple lines!
149             #
150              
151             # GPS-35:
152             # $GPGSV,<1>,<2>,<3>,<4>,<5>,<6>,<7>,...<4>,<5>,<6>,<7>*hh
153             # 1) Total number of GSV sentences to be transmitted
154             # 2) Number of current GSV sentence
155             # 3) Total number of satellites in view, 00 to 12 (leading zeros sent)
156             # 4) Satellite PRN number, 01 to 32 (leading zeros sent)
157             # 5) Satellite elevation, 00 to 90 degrees (leading zeros sent)
158             # 6) Satellite azimuth, 000 to 359 degrees, true (leading zeros sent)
159             # 7) Signal to Noise ratio (C/No) 00 to 99 dB, null when not tracking (leading zeros sent)
160             sub GPGSV {
161             # Satellites in view
162              
163 3     3 0 27 my $self = shift;
164 3 50       18 $self->{NMEADATA} = {} unless ref($self->{NMEADATA});
165 3         6 my $d = $self->{NMEADATA};
166              
167 3         27 my @data = split(',',shift);
168 3         8 my $sentence = $data[2];
169              
170 3 100       25 if ($sentence == 1) {
    100          
    50          
171             (undef,
172             $$d{num_sentences},
173             $$d{sentence},
174             $$d{num_sat_vis},
175             $$d{prn01},
176             $$d{elev_deg1},
177             $$d{az_deg1},
178             $$d{sig_str1},
179             $$d{prn02},
180             $$d{elev_deg2},
181             $$d{az_deg2},
182             $$d{sig_str2},
183             $$d{prn03},
184             $$d{elev_deg3},
185             $$d{az_deg3},
186             $$d{sig_str3},
187             $$d{prn04},
188             $$d{elev_deg4},
189             $$d{az_deg4},
190             $$d{sig_str4}
191 1         42 ) = @data;
192              
193             } elsif ($sentence == 2) {
194             (undef,
195             $$d{num_sentences},
196             $$d{sentence},
197             $$d{num_sat_vis},
198             $$d{prn05},
199             $$d{elev_deg5},
200             $$d{az_deg5},
201             $$d{sig_str5},
202             $$d{prn06},
203             $$d{elev_deg6},
204             $$d{az_deg6},
205             $$d{sig_str6},
206             $$d{prn07},
207             $$d{elev_deg7},
208             $$d{az_deg7},
209             $$d{sig_str7},
210             $$d{prn08},
211             $$d{elev_deg8},
212             $$d{az_deg8},
213             $$d{sig_str8}
214 1         19 ) = @data;
215              
216             } elsif ($sentence == 3) {
217             (undef,
218             $$d{num_sentences},
219             $$d{sentence},
220             $$d{num_sat_vis},
221             $$d{prn09},
222             $$d{elev_deg9},
223             $$d{az_deg9},
224             $$d{sig_str9},
225             $$d{prn10},
226             $$d{elev_deg10},
227             $$d{az_deg10},
228             $$d{sig_str10},
229             $$d{prn11},
230             $$d{elev_deg11},
231             $$d{az_deg11},
232             $$d{sig_str11},
233             $$d{prn12},
234             $$d{elev_deg12},
235             $$d{az_deg12},
236             $$d{sig_str12}
237 1         19 ) = @data;
238             }
239 3         16 1;
240             }
241              
242              
243             #$PGRME,45.8,M,,M,156.8,M*33
244             #
245              
246             # GPS-35:
247             # $PGRME,<1>,M,<2>,M,<3>,M*hh
248             # 1) Estimated horizontal position error (HPE), 0.0 to 9999.9 meters
249             # 2) Estimated vertical position error (VPE), 0.0 to 9999.9 meters
250             # 3) Estimated position error (EPE), 0.0 to 9999.9 meters
251             sub PGRME {
252             # Estimated horiz, vertical, spherical error in meters
253 1     1 0 2 my $self = shift;
254 1 50       77 $self->{NMEADATA} = {} unless ref($self->{NMEADATA});
255 1         4 my $d = $self->{NMEADATA};
256              
257             (undef,
258             $$d{hpe},
259             $$d{hpe_units},
260             $$d{vpe},
261             $$d{vpe_units},
262             $$d{overall_error},
263             $$d{overall_error_units}
264 1         13 ) = split(",",shift);
265 1         5 1;
266             }
267              
268             #$GPGLL,4748.811,N,12219.564,W,033850,A*3C
269             #
270              
271             # $GPGLL,<1>,<2>,<3>,<4>,<5>,
272             # 1) Latitude, ddmm.mm format
273             # 2) Latitude hemisphere, N or S
274             # 3) Longitude, dddmm.mm format
275             # 4) Longitude hemisphere, E or W
276             # 5) UTC time of position fix, hhmmss format
277             # 6) Data valid, A=Valid
278             sub GPGLL {
279             # Geographic position, Latitude and Longitude
280 1     1 0 4 my $self = shift;
281 1 50       8 $self->{NMEADATA} = {} unless ref($self->{NMEADATA});
282 1         4 my $d = $self->{NMEADATA};
283              
284             (undef,
285             $$d{lat_ddmm_low},
286             $$d{lat_NS},
287             $$d{lon_ddmm_low},
288             $$d{lon_EW},
289             $$d{time_utc},
290             $$d{data_valid}
291 1         13 ) = split(",",shift);
292              
293 1         5 1;
294             }
295              
296              
297              
298             #$PGRMZ,665,f,2*1F
299             #
300             # $PGRMZ,<1>,f,<2>,M*dd
301             # 1) Altitude in feet
302             # 2) Position fix, 2=user altitude, 3=GPS altitude
303             #
304             sub PGRMZ {
305             # Altitude & units, 2 = user altitude 3 = GPS altitude
306 1     1 0 4 my $self = shift;
307 1 50       8 $self->{NMEADATA} = {} unless ref($self->{NMEADATA});
308 1         3 my $d = $self->{NMEADATA};
309              
310             (undef,
311             $$d{alt},
312             $$d{alt_units},
313             $$d{alt_mode}
314 1         11 ) = split(",",shift);
315 1         5 1;
316             }
317              
318              
319             #$PGRMM,WGS 84*06
320             #
321              
322             sub PGRMM {
323             # Currently active horizontal datum
324 1     1 0 2 my $self = shift;
325 1 50       7 $self->{NMEADATA} = {} unless ref($self->{NMEADATA});
326 1         2 my $d = $self->{NMEADATA};
327              
328             (undef,
329             $$d{datum},
330 1         7 ) = split(",",shift);
331 1         5 1;
332             }
333              
334             #$GPBOD,045.,T,023.,M,DEST,START*47
335             #
336              
337             # $GPBOD,<1>,T,<2>,M,<3>,<4>*dd
338             # 1) Bearing from "start" to "dest", true
339             # 2) Bearing from "start" to "dest", magnetic
340             # 3) Destination waypoint ID
341             # 4) Origin waypoint ID
342              
343             sub GPBOD {
344             # Bearing - origin to destination waypoint
345 1     1 0 4 my $self = shift;
346 1 50       9 $self->{NMEADATA} = {} unless ref($self->{NMEADATA});
347 1         4 my $d = $self->{NMEADATA};
348              
349             (undef,
350             $$d{bearing_start_to_dest_true},
351             $$d{junk31},
352             $$d{bearing_start_to_dest_mag},
353             $$d{junk32},
354             $$d{dest_waypoint},
355             $$d{origin_waypoint}
356 1         16 ) = split(",",shift);
357              
358 1         5 1;
359             }
360              
361              
362             #$GPRTE,2,1,c,0,W3IWI,DRIVWY,32CEDR,32-29,32BKLD,32-I95,32-US1*69
363             # multiple lines!
364              
365             # $GPRTE,<1>,<2>,<3>,<4>,<5>,<5>,<5>...<5>*dd
366             # 1) Number of GPRTE sentences
367             # 2) Number of this sentence
368             # 3) c=complete list of waypoints in this route, w=first listed waypoint is start of current leg
369             # 4) Route identifier (0-?)
370             # 5) Waypoint identifier
371             sub GPRTE {
372             # Waypoints in active route
373 1     1 0 3 my $self = shift;
374 1 50       8 $self->{NMEADATA} = {} unless ref($self->{NMEADATA});
375 1         4 my $d = $self->{NMEADATA};
376              
377 1         5 my @data = split(',',shift);
378 1         3 my $sentence = $data[2];
379              
380 1 50       7 if ($sentence == 1) {
    0          
    0          
381             (undef,
382             $$d{num_sentences},
383             undef,
384             $$d{c_w},
385             $$d{route_num},
386 1         5 @{$d->{waypoint1}}
  1         7  
387             ) = @data;
388 1 50       6 undef $d->{waypoint2} if ref($d->{waypoint2});
389 1 50       6 undef $d->{waypoint3} if ref($d->{waypoint3});
390             } elsif ($sentence == 2) {
391             (undef,
392             $$d{num_sentences},
393             undef,
394             $$d{c_w},
395             $$d{route_num},
396 0         0 @{$d->{waypoint2}}
  0         0  
397             ) = @data;
398 0 0       0 undef $d->{waypoint3} if ref($d->{waypoint3});
399             } elsif ($sentence == 2) {
400             (undef,
401             $$d{num_sentences},
402             undef,
403             $$d{c_w},
404             $$d{route_num},
405 0         0 @{$d->{waypoint3}}
  0         0  
406             ) = @data;
407             }
408              
409              
410 1         5 1;
411             }
412              
413              
414             #$GPRMC,033850,A,4748.811,N,12219.564,W,000.0,150.3,160596,019.6,E*64
415             #
416              
417             # GPS-35:
418             # $GPRMC,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>,<9>,<10>,<11>*hh
419             # 1) UTC time of position fix, hhmmss format
420             # 2) Status, A=Valid position, V=NAV receiver warning
421             # 3) Latitude, ddmm.mmmm format (leading zeros sent)
422             # 4) Latitude hemisphere, N or S
423             # 5) Longitude, dddmm.mmmm format (leading zeros sent)
424             # 6) Longitude hemisphere, E or W
425             # 7) Speed over ground, 0.0 to 999.9 knots
426             # 8) Course over ground, 000.0 to 359.9 degrees, true (leading zeros sent)
427             # 9) UTC date of position fix, ddmmyy format
428             # 10) Magnetic variation, 000.0 to 180.0 degrees (leading zeros sent)
429             # 11) Magnetic variation direction, E or W (westerly variation adds to true course)
430              
431             sub GPRMC {
432             # RMC - Recommended minimum specific GPS/Transit data
433 2     2 0 4 my $self = shift;
434 2 100       18 $self->{NMEADATA} = {} unless ref($self->{NMEADATA});
435 2         6 my $d = $self->{NMEADATA};
436              
437             (undef,
438             $$d{time_utc},
439             $$d{data_valid},
440             $$d{lat_ddmm},
441             $$d{lat_NS},
442             $$d{lon_ddmm},
443             $$d{lon_EW},
444             $$d{speed_over_ground},
445             $$d{course_made_good},
446             $$d{ddmmyy},
447             $$d{mag_var},
448             $$d{mag_var_EW}
449 2         31 ) = split(",",shift);
450              
451 2         37 $d->{time_utc} =~ s/(\d\d)(\d\d)(\d\d)/$1:$2:$3/g;
452 2         52 1;
453             }
454              
455             1;
456              
457              
458             __END__