ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/GPS/GPS.pm
Revision: 1.4
Committed: Sun Apr 28 09:05:10 2002 UTC (22 years ago) by stefan
Branch: MAIN
CVS Tags: HEAD
Changes since 1.3: +109 -4 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 stefan 1.1 package GPS;
2    
3     use strict;
4     use warnings;
5     use POSIX ();
6 stefan 1.4 use IO::Socket::INET;
7 stefan 1.1
8     our $VERSION = 0.01;
9    
10 stefan 1.4
11    
12 stefan 1.1 sub new {
13     my ($class, %arg) = @_;
14     $arg{port} ||= 2947;
15     $arg{host} ||= 'localhost';
16    
17 stefan 1.4 print "$class\n";
18     my $m = $class =~ /Raw$/ ? 'Coro::Socket' : 'IO::Socket::INET';
19     my $sock = new $m PeerHost => $arg{host}, PeerPort => $arg{port}
20    
21 stefan 1.1 or die 'GPSD ($arg{host}:$arg{port}): $!';
22     print $sock "HELO\n";
23     <$sock> =~ /GPSD/ or die 'no GPSD';
24 stefan 1.4 if($class =~/Raw$/) {
25     print $sock "R\n";
26     <$sock> =~ /GPSD,R=1/ or die "can't enable raw-mode";
27     }
28 stefan 1.1
29     bless {
30     fh => $sock,
31     minpoll => $arg{minpoll} || 1,
32     last => 0,
33 stefan 1.4 data => {},
34 stefan 1.1 }, $class;
35     }
36    
37     sub poll {
38     my $self = shift;
39    
40     print {$self->{fh}} "dpva\n";
41    
42 stefan 1.4 if (readline ($self->{fh}) =~ m%GPSD,D=(\d\d)/(\d\d)/(\d\d\d\d) (\d\d):(\d\d):(\d\d),P=([\-0-9.]+) ([\-0-9.]+),V=([0-9.]+),A=([\-0-9.]+)%) {
43 stefan 1.1 local $ENV{TZ} = "+0000";
44     $self->{data} = {
45     time => (POSIX::mktime $6,$5,$4,$2,$1-1,$3-1900,0,0),
46     lat => $7,
47     long => $8,
48     v => $9,
49     alt => $10,
50     };
51     $self->{last} = time;
52     }
53     }
54    
55     sub data {
56     $_[0]->poll if time - $_[0]{last} >= $_[0]{minpoll};
57 stefan 1.4 $_[0]{data};
58     }
59    
60     package GPS::Raw;
61     our @ISA = qw(GPS);
62     use strict;
63     use warnings;
64     use POSIX qw(modf);
65     use Coro::Socket;
66     use Coro::Event;
67     use Coro;
68    
69     sub PI { 3.14159265 } # not used :)
70    
71     sub latlon($$) {
72     my ($t1,$t2) = modf($_[0] / 100);
73     $t2 = $t2 + $t1*100 / 60;
74     $t2 *= -1 if $_[1] =~ /[SW]/i;
75     $t2
76     }
77    
78     our %cbs = ( 'GPGLL' => sub { my ($res, @a) = @_;
79     $res->{Plain}{Latitude} = $a[0];
80     $res->{lat} = latlon $a[0], $a[1];
81     $res->{Plain}{NS} = $a[1];
82     $res->{Plain}{Longitude} = $a[2];
83     $res->{long} = latlon $a[2], $a[3];
84     $res->{Plain}{WE} = $a[3];
85     $res->{Plain}{UTC} = $a[4];
86     },
87     'PGRMZ' => sub { my ($res, @a) = @_;
88     $res->{Plain}{Altitude} = $a[0];
89     $res->{alt} = $a[0] / 3.2808399; # foot -> meters
90     },
91     'GPRMC' => sub { my ($res, @a) = @_;
92     $res->{Plain}{Speed} = $a[6];
93     $res->{v} = $a[6] * 1.852; # knoten :)
94     $res->{Plain}{Course} = $a[7];
95     $res->{course} = $a[7];
96     },
97     'GPRMB' => sub { my ($res, @a) = @_;
98     $res->{WP}{origin} = $a[2];
99     $res->{WP}{destination} = $a[3];
100     $res->{WP}{destination} = $a[4];
101     $res->{WP}{desLat} = latlon $a[5], $a[6];
102     $res->{WP}{desLong} = latlon $a[7], $a[8];
103     $res->{WP}{distance} = $a[9]* 1.852; #seemeilen -> km
104     $res->{WP}{bearing} = $a[10];
105     $res->{WP}{speed} = $a[11] *1852; #knoten->km/h
106    
107     },
108     );
109    
110    
111     sub _chksum($) {
112     my ($line,$cs) = (shift,0);
113     $line =~ m/\$([^\*]+)\*([0-9A-F]{2})$/ or do {
114     warn "illegal line \"$line\"";
115     return 0;
116     };
117     my ($str, $pcs) = ($1, $2);
118     map {$cs ^= $_} unpack ("C*", $str);
119     return 1 if $cs == hex($pcs);
120     warn "illegal checksum. packet=$pcs computed=$cs";
121     return 0;
122     }
123    
124     sub get_line($) {
125     my $sock = $_[0]{fh};
126     cserr:
127     my $l = readline $sock;
128     $l =~ s/[\015\012\0]*//g;
129     _chksum($l) or goto cserr;
130     warn "unknown line \"$l\"" unless $l =~ /^\$([^,]+),([^\*]+)\*[A-F0-9]{2}$/;
131     my ($cmd, $arg) = ($1,$2);
132     ($l, $cmd, $arg);
133     }
134    
135     sub daemon($) {
136     my $self = shift;
137     async {
138     my $self = shift;
139     my $res = $self->{data};
140     use Data::Dumper;
141     $res->{lines} = 0;
142     while(1) {
143     my($line, $cmd, $arg) = $self->get_line;
144     $res->{lines}++;
145     $res->{Raw}{$cmd} = $arg;
146     &{$cbs{$cmd}}($res, split /,/, $arg) if exists $cbs{$cmd};
147     }
148     } $self;
149     }
150    
151     sub data {
152     cede;
153 stefan 1.1 $_[0]{data};
154     }
155    
156     1;
157