--- GPS/GPS.pm 2002/04/26 21:53:14 1.3 +++ GPS/GPS.pm 2002/04/28 09:05:10 1.4 @@ -3,25 +3,34 @@ use strict; use warnings; use POSIX (); -use Coro::Socket; +use IO::Socket::INET; our $VERSION = 0.01; + + sub new { my ($class, %arg) = @_; $arg{port} ||= 2947; $arg{host} ||= 'localhost'; - my $sock = new Coro::Socket PeerHost => $arg{host}, PeerPort => $arg{port} + print "$class\n"; + my $m = $class =~ /Raw$/ ? 'Coro::Socket' : 'IO::Socket::INET'; + my $sock = new $m PeerHost => $arg{host}, PeerPort => $arg{port} + or die 'GPSD ($arg{host}:$arg{port}): $!'; print $sock "HELO\n"; <$sock> =~ /GPSD/ or die 'no GPSD'; + if($class =~/Raw$/) { + print $sock "R\n"; + <$sock> =~ /GPSD,R=1/ or die "can't enable raw-mode"; + } bless { fh => $sock, minpoll => $arg{minpoll} || 1, last => 0, - data => {} + data => {}, }, $class; } @@ -30,7 +39,7 @@ print {$self->{fh}} "dpva\n"; - if ($self->{fh}->readline =~ 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.]+)%) { + 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.]+)%) { local $ENV{TZ} = "+0000"; $self->{data} = { time => (POSIX::mktime $6,$5,$4,$2,$1-1,$3-1900,0,0), @@ -48,5 +57,101 @@ $_[0]{data}; } +package GPS::Raw; +our @ISA = qw(GPS); +use strict; +use warnings; +use POSIX qw(modf); +use Coro::Socket; +use Coro::Event; +use Coro; + +sub PI { 3.14159265 } # not used :) + +sub latlon($$) { + my ($t1,$t2) = modf($_[0] / 100); + $t2 = $t2 + $t1*100 / 60; + $t2 *= -1 if $_[1] =~ /[SW]/i; + $t2 +} + +our %cbs = ( 'GPGLL' => sub { my ($res, @a) = @_; + $res->{Plain}{Latitude} = $a[0]; + $res->{lat} = latlon $a[0], $a[1]; + $res->{Plain}{NS} = $a[1]; + $res->{Plain}{Longitude} = $a[2]; + $res->{long} = latlon $a[2], $a[3]; + $res->{Plain}{WE} = $a[3]; + $res->{Plain}{UTC} = $a[4]; + }, + 'PGRMZ' => sub { my ($res, @a) = @_; + $res->{Plain}{Altitude} = $a[0]; + $res->{alt} = $a[0] / 3.2808399; # foot -> meters + }, + 'GPRMC' => sub { my ($res, @a) = @_; + $res->{Plain}{Speed} = $a[6]; + $res->{v} = $a[6] * 1.852; # knoten :) + $res->{Plain}{Course} = $a[7]; + $res->{course} = $a[7]; + }, + 'GPRMB' => sub { my ($res, @a) = @_; + $res->{WP}{origin} = $a[2]; + $res->{WP}{destination} = $a[3]; + $res->{WP}{destination} = $a[4]; + $res->{WP}{desLat} = latlon $a[5], $a[6]; + $res->{WP}{desLong} = latlon $a[7], $a[8]; + $res->{WP}{distance} = $a[9]* 1.852; #seemeilen -> km + $res->{WP}{bearing} = $a[10]; + $res->{WP}{speed} = $a[11] *1852; #knoten->km/h + + }, + ); + + +sub _chksum($) { + my ($line,$cs) = (shift,0); + $line =~ m/\$([^\*]+)\*([0-9A-F]{2})$/ or do { + warn "illegal line \"$line\""; + return 0; + }; + my ($str, $pcs) = ($1, $2); + map {$cs ^= $_} unpack ("C*", $str); + return 1 if $cs == hex($pcs); + warn "illegal checksum. packet=$pcs computed=$cs"; + return 0; +} + +sub get_line($) { + my $sock = $_[0]{fh}; +cserr: + my $l = readline $sock; + $l =~ s/[\015\012\0]*//g; + _chksum($l) or goto cserr; + warn "unknown line \"$l\"" unless $l =~ /^\$([^,]+),([^\*]+)\*[A-F0-9]{2}$/; + my ($cmd, $arg) = ($1,$2); + ($l, $cmd, $arg); +} + +sub daemon($) { + my $self = shift; + async { + my $self = shift; + my $res = $self->{data}; + use Data::Dumper; + $res->{lines} = 0; + while(1) { + my($line, $cmd, $arg) = $self->get_line; + $res->{lines}++; + $res->{Raw}{$cmd} = $arg; + &{$cbs{$cmd}}($res, split /,/, $arg) if exists $cbs{$cmd}; + } + } $self; +} + +sub data { + cede; + $_[0]{data}; +} + 1;