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, 2 months ago) by stefan
Branch: MAIN
CVS Tags: HEAD
Changes since 1.3: +109 -4 lines
Log Message:
*** empty log message ***

File Contents

# Content
1 package GPS;
2
3 use strict;
4 use warnings;
5 use POSIX ();
6 use IO::Socket::INET;
7
8 our $VERSION = 0.01;
9
10
11
12 sub new {
13 my ($class, %arg) = @_;
14 $arg{port} ||= 2947;
15 $arg{host} ||= 'localhost';
16
17 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 or die 'GPSD ($arg{host}:$arg{port}): $!';
22 print $sock "HELO\n";
23 <$sock> =~ /GPSD/ or die 'no GPSD';
24 if($class =~/Raw$/) {
25 print $sock "R\n";
26 <$sock> =~ /GPSD,R=1/ or die "can't enable raw-mode";
27 }
28
29 bless {
30 fh => $sock,
31 minpoll => $arg{minpoll} || 1,
32 last => 0,
33 data => {},
34 }, $class;
35 }
36
37 sub poll {
38 my $self = shift;
39
40 print {$self->{fh}} "dpva\n";
41
42 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 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 $_[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 $_[0]{data};
154 }
155
156 1;
157