#!/usr/bin/perl -w # # by Winfried Beer, 2002 # use IO::Handle; use POSIX; use Fcntl; $PI=3.14159265358979323846; if (unpack("V",pack("L",1))==1) { $little_endian=1; }else{ $little_endian=0; } $device='/dev/cua1'; $debug=0; $recbuf=""; # global buffer for serial device $oldpid=0; # global for decode_packet @PA=(); # global for decode_packet (Protocol Arrray), specifies available protocols and data formats @PA=("P000", "L001", "A010", "A100", "D108", "A201", "D202", "D108", "D210", "A301", "D310", "D301", "A500", "D501", "A600", "D600", "A700", "D700", "A800", "D800", "A900", "A902", "A903"); # default for: etrex vista $PA_idx=-1; # global for decode_packet (index of @PA with current application protocol) $PA_wpt_type=""; $PA_rte_hdr_type=""; $PA_rte_point_type=""; $PA_rte_link_type=""; $PA_trk_point_type=""; $PA_trk_hdr_type=""; $PA_prx_wpt_type=""; $PA_almanac_type=""; $PA_date_time_type=""; $PA_position_type=""; $PA_pvt_data_type=""; @month_names=("JAN","FEB","MAR","APR","MAY","JUN","JUL","AUG","SEP","OCT","NOV","DEC"); if ($#ARGV==-1) { push @ARGV, "-h" }; for ($i=0; $i<=$#ARGV; $i++) { if ($ARGV[$i] eq "-h") { print STDERR "\ngarman [-h] [-d] [-p port] [-i] [-t] [-d?]\n"; print STDERR " (by Winfried Beer, July 2002, v0.1)\n\n"; print STDERR "Flags:\n"; print STDERR " -h help\n"; print STDERR " -d enable debug mode\n"; print STDERR " -p port serial i/o-device\n"; print STDERR " -i identify connected GPS\n"; print STDERR " -d???? download: rte=route, trk=track, wpt=waypoint, "; print STDERR "alm=almanac, prx=proximity waypoints, time=date&time\n "; print STDERR "posn=position\n "; print STDERR " -abort abort transfer\n "; print STDERR " -pvt_on, -pvt_off PVT mode on/off\n "; print STDERR " -pwr_off,-pwr_off_prompt switch off gps device\n "; print STDERR " -sleep wait some seconds\n "; exit; }elsif ($ARGV[$i] eq "-p") { $device=$ARGV[$i+1]; }elsif ($ARGV[$i] eq "-d") { $debug=1; } } # --- open serial port and set serial parameters sysopen (PORT, $device, O_RDWR|O_NDELAY|O_NOCTTY, 0700) or die "Cannot read from $device"; # -- set serial parameters # $termios_t = "cccs"; # ioctl (PORT, &TCGETA, $termios); # @ary = unpack($termios_t,$termios); $termios=POSIX::Termios->new; $termios->getattr(fileno(PORT)); $termios->setcflag((&POSIX::CSIZE & &POSIX::CS8) | &POSIX::CREAD | &POSIX::CLOCAL); $termios->setiflag(0); $termios->setlflag(0); $termios->setoflag(0); $termios->setospeed(&POSIX::B9600); $termios->setispeed(&POSIX::B9600); $termios->setattr(fileno(PORT)); $argcnt=0; MAINLOOP: while ($argcnt<=$#ARGV) { #($nfound,$timeleft)=select(undef, undef, undef, 0.5); # wait 0.5 seconds # --- get next useful argument and send command to GPS device $prot=""; $noop=1; while ($argcnt<=$#ARGV && $noop==1) { $noop=0; $prot=""; if ($ARGV[$argcnt] eq "-i") { # A000 Product Data Protocol (includes A001) $cmd=make_packet(254, chr(254).chr(0)); send_packet_ack(PORT, $cmd); decode_packet($cmd); sleep(1); }elsif ($ARGV[$argcnt] eq "-dwpt") { # A1xx Waypoint Transfer Protocol $cmd=make_packet(10, chr(7).chr(0)); # ==Cmnd_Transfer_Wpt send_packet_ack(PORT, $cmd); decode_packet($cmd); sleep(1); }elsif ($ARGV[$argcnt] eq "-drte") { # A2xx Route Transfer Protocol $cmd=make_packet(10, chr(4).chr(0)); # ==Cmnd_Transfer_Rte send_packet_ack(PORT, $cmd); decode_packet($cmd); sleep(1); }elsif ($ARGV[$argcnt] eq "-dtrk") { # A3xx Track Log Transfer Protocol $cmd=make_packet(10, chr(6).chr(0)); # ==Cmnd_Transfer_Trk send_packet_ack(PORT, $cmd); decode_packet($cmd); sleep(1); }elsif ($ARGV[$argcnt] eq "-dprx") { # A4xx Proximity Waypoint Transfer Protocol $cmd=make_packet(10, chr(3).chr(0)); # ==Cmnd_Transfer_Prx send_packet_ack(PORT, $cmd); decode_packet($cmd); sleep(1); }elsif ($ARGV[$argcnt] eq "-dalm") { # A5xx Almanac Transfer Protocol $cmd=make_packet(10, chr(1).chr(0)); # ==Cmnd_Transfer_Alm send_packet_ack(PORT, $cmd); decode_packet($cmd); sleep(1); }elsif ($ARGV[$argcnt] eq "-dtime") { # A6xx Date and Time Initialization Protocol $cmd=make_packet(10, chr(5).chr(0)); # ==Cmnd_Transfer_Time send_packet_ack(PORT, $cmd); decode_packet($cmd); sleep(1); }elsif ($ARGV[$argcnt] eq "-dposn") { # A7xx Position Initialization Protocol $cmd=make_packet(10, chr(2).chr(0)); # ==Cmnd_Transfer_Posn send_packet_ack(PORT, $cmd); decode_packet($cmd); sleep(1); }elsif ($ARGV[$argcnt] eq "-pvt_on") { # A8xx PVT Data Protocol (start) $cmd=make_packet(10, chr(49).chr(0)); # ==Cmnd_Start_Pvt_Data send_packet_ack(PORT, $cmd); decode_packet($cmd); sleep(1); }elsif ($ARGV[$argcnt] eq "-pvt_off") { # A8xx PVT Data Protocol (stop) $cmd=make_packet(10, chr(50).chr(0)); # ==Cmnd_Stop_Pvt_Data send_packet_ack(PORT, $cmd); decode_packet($cmd); sleep(1); }elsif ($ARGV[$argcnt] eq "-abort") { $cmd=make_packet(10, chr(0).chr(0)); # ==Cmnd_Abort_Transfer send_packet_ack(PORT, $cmd); decode_packet($cmd); }elsif ($ARGV[$argcnt] eq "-pwr_off") { $cmd=make_packet(10, chr(8).chr(0)); # ==Cmnd_Turn_Off_Pwr send_packet_ack(PORT, $cmd); decode_packet($cmd); }elsif ($ARGV[$argcnt] eq "-pwr_off_prompt") { $cmd=make_packet(10, chr(11).chr(0)); send_packet_ack(PORT, $cmd); decode_packet($cmd); }elsif ($ARGV[$argcnt] eq "-sleep") { $argcnt++; $noop=1; sleep($ARGV[$argcnt]); $argcnt++; }elsif ($ARGV[$argcnt] eq "-h" || $ARGV[$argcnt] eq "-d") { $argcnt++; $noop=1; }elsif ($ARGV[$argcnt] eq "-p") { $argcnt++; $argcnt++; $noop=1; }else{ print STDERR "\nWARNING: unknown argument \"".$ARGV[$argcnt]."\"\n"; $argcnt++; $noop=1; } if ($argcnt>$#ARGV) { last MAINLOOP;} } # -- read requested data packet(s) from GPS $idlecnt=0; READLIST: while ($idlecnt<9) { # loop as long packets received within last 2 seconds (8*250 ms) (or all data read) $packet=receive_packet_ack(PORT); if (!defined($packet)) { $idlecnt=9999; print STDERR "ERROR: receiving no data packets.\n"; }elsif ($packet eq "") { $idlecnt++; if ($debug) { print STDERR "IDLE (buflen=".length($recbuf).")\n"; } }else{ $idlecnt=0; $pid=ord(substr($packet,1,1)); if ($pid==6) { print STDERR "ERROR: Got extra ACK.\n"; }elsif ($pid==21) { print STDERR "ERROR: Got extra NAK.\n"; }else{ if ($debug) { print STDERR "DATA: ".hexstr($packet)."\n"; } $str=decode_packet ($packet); if (!$debug) { $str=~s/##.*?\n//g; } # clear debug comments print $str; if ($pid==12 || $pid==253 || $pid==14 || $pid==17 || $pid==51) { # Pid_Xfer_Cmplt, Pid_Protocol_Array, Pid_Date_Time_Data, Pid_Position_Data, Pid_Pvt_Data # (end of packet list or one packet protocols) last READLIST; # no more packets expected } } } } # -- advance to next argument $argcnt++; } close PORT; exit; # --------------------------------------------------------------------- # Read from $FH, but return (an empty string) within $timeout # seconds, if no data are available. Return undef at end of file # or other errors. # # $FH: filehandle # $timeout: timeout in seconds, fraction possible (eg. 0.5) # --------------------------------------------------------------------- sub read_timeout { my ($FH,$timeout)=@_; my ($packet,$nfound,$rin); $rin=''; vec($rin,fileno($FH),1) = 1; ($nfound,undef)=select($rin, undef, $rin, $timeout); if (!$nfound) { return ''; } # timed out sysread $FH, $packet,1024; if ($packet eq '') { return undef;} # error or end of file #print "RAW: ".hexstr($packet)."\n"; return $packet; } # --------------------------------------------------------------------- sub hexstr { my ($str)=@_; my ($hex,$i); $hex=""; if ($str ne "") { for ($i=0;$i A201) and index of array @PA # --------------------------------------------------------------------- sub PA_find_protocol { my ($prot)=@_; my $i; for ($i=0;$i<=$#PA;$i++) { if ($PA[$i]=~/^$prot/) { return $i; } } return -1; } # --------------------------------------------------------------------- # semicircle -> degree # --------------------------------------------------------------------- sub semicircle2degree { my ($semi)=@_; my $degree; $degree=$semi*180.0/(1<<31); if ($degree>180) { $degree=$degree-360.0; } return $degree; } # --------------------------------------------------------------------- # radian -> degree # --------------------------------------------------------------------- sub radian2degree { my ($radi)=@_; my $degree; $degree=$radi*180.0/$PI; if ($degree>180) { $degree=$degree-360.0; } return $degree; }