File Coverage

blib/lib/GPS/Serial.pm
Criterion Covered Total %
statement 48 129 37.2
branch 14 72 19.4
condition 6 26 23.0
subroutine 11 16 68.7
pod 0 8 0.0
total 79 251 31.4


line stmt bran cond sub pod time code
1             # Copyright (c) 1999-2000 João Pedro Gonçalves . All rights reserved.
2             # This program is free software; you can redistribute it and/or
3             # modify it under the same terms as Perl itself.
4              
5             package GPS::Serial;
6              
7 3     3   14 use strict;
  3         3  
  3         105  
8 3     3   12 use vars qw($VERSION $OS_win $has_serialport $stty_path);
  3         3  
  3         473  
9              
10             $VERSION = sprintf("%d.%02d", q$Revision: 1.18 $ =~ /(\d+)\.(\d+)/);
11              
12             BEGIN {
13             #Taken from SerialPort/eg/any_os.plx
14              
15             #We try to use Device::SerialPort or
16             #Win32::SerialPort, if it's not windows
17             #and there's no Device::SerialPort installed,
18             #then we just use the FileHandle module that
19             #comes with perl
20              
21 3 50   3   25 $OS_win = ($^O eq "MSWin32") ? 1 : 0;
22              
23 3 50   3   174 if ($OS_win) {
  3 50       2454  
  3 0       86254  
  3 0       148  
24 0         0 eval "use Win32::SerialPort";
25 0 0       0 die "Must have Win32::SerialPort correctly installed: $@\n" if ($@);
26 0         0 $has_serialport++;
27             } elsif (eval q{ use Device::SerialPort; 1 }) {
28 3         4350 $has_serialport++;
29             } elsif (eval q{ use POSIX qw(:termios_h); use FileHandle; 1}) {
30             # NOP
31             } elsif (-x "/bin/stty") {
32 0         0 $stty_path = "/bin/stty";
33             } else {
34 0         0 die "Missing either POSIX, FileHandle, Device::SerialPort or /bin/stty";
35             }
36             } # End BEGIN
37              
38             #$|++; # XXX should not be here...
39              
40             sub _read {
41             #$self->_read(length)
42             #reads packets from whatever you're listening from.
43             #length defaults to 1
44              
45 600     600   871 my ($self,$len) = @_;
46 600   50     2431 $len ||=1;
47              
48 600 50       1390 $self->serial or die "Read from an uninitialized handle";
49              
50 600         723 my $buf;
51              
52 600 50       1253 if ($self->{serialtype} eq 'FileHandle') {
53 600         814 sysread($self->serial,$buf,$len);
54             } else {
55 0         0 (undef, $buf) = $self->serial->read($len);
56             }
57              
58 600 50 33     2258 if ($self->{verbose} && $buf) {
59 0         0 print STDERR "R:(",join(" ", map {$self->Pid_Byte($_)}unpack("C*",$buf)),")\n";
  0         0  
60             } else {
61             # Strange: this delay is necessary, otherwise nothing works
62             # (seen on a slow Debian machine with Garmin Vista)
63             # Turning on verbose output also helps
64 600         1196 $self->usleep(1);
65             }
66              
67 600         3160 return $buf;
68             }
69              
70             sub _readline {
71             #$self->_readline()
72             #reads until $/ is found
73             #NMEA-aware - only lines beginning with $ count
74             #if NMEA is the chosen protocol
75              
76 14     14   22 my ($self) = @_;
77 14         26 my $line = '';
78 14 50       35 $self->serial or warn "Read from an uninitialized handle";
79              
80 14     0   246 local $SIG{ALRM} = sub {die "GPS Device has timed out\n"};
  0         0  
81 14         26 eval { alarm($self->{timeout}) };
  14         62  
82              
83 14         29 while (1) {
84 600 100       1722 $self->usleep(1) unless (length($line) % 32);
85 600         1782 my $buf .= $self->_read;
86 600         1584 $line .= $buf;
87 600 100       2492 if ($buf eq $/) {
88 14         31 eval {alarm(0) };
  14         46  
89 14 50 33     691 return ( ($self->{protocol} eq 'NMEA' && substr($line,0,1) ne '$')
90             ? $self->_readline
91             : $line );
92             }
93 586         728 eval { alarm($self->{timeout}) }; # set new timeout
  586         2272  
94             }
95             }
96              
97             sub safe_read {
98             #Reads one byte, escapes DLE bytes
99             #Used by the GRMN Protocol
100 0     0 0 0 my $self = shift;
101 0         0 my $buf = $self->_read;
102 0 0       0 $buf eq "\x10" ? $self->_read : $buf;
103             }
104              
105             sub _write {
106             #$self->_write(buffer,length)
107             #syswrite wrapper for the serial device
108             #length defaults to buffer length
109              
110 0     0   0 my ($self,$buf,$len,$offset) = @_;
111 0 0       0 $self->connect() or die "Write to an uninitialized handle";
112              
113 0   0     0 $len ||= length($buf);
114              
115 0 0       0 if ($self->{verbose}) {
116 0         0 print STDERR "W:(",join(" ", map {$self->Pid_Byte($_)}unpack("C*",$buf)),")\n";
  0         0  
117             }
118              
119 0 0       0 $self->serial or die "Write to an uninitialized handle";
120              
121 0 0       0 if ($self->{serialtype} eq 'FileHandle') {
122 0   0     0 syswrite($self->serial,$buf,$len,$offset||0);
123             } else {
124 0         0 my $out_len = $self->serial->write($buf);
125 0 0       0 warn "Write incomplete ($len != $out_len)\n" if ( $len != $out_len );
126             }
127             }
128              
129             sub connect {
130 1     1 0 2 my $self = shift;
131 1 50       7 return $self->serial if $self->serial;
132              
133 1 50 33     18 if ($OS_win || $has_serialport) {
    0          
134 1         7 $self->{serial} = $self->serialport_connect;
135             } elsif (defined $stty_path) {
136 0         0 $self->{serial} = $self->stty_connect;
137             } else {
138 0         0 $self->{serial} = $self->unix_connect;
139             }
140              
141 0 0       0 print "Using $$self{serialtype}\n" if $self->verbose;
142             }
143              
144             sub serialport_connect {
145 1     1 0 1 my $self= shift;
146             my $PortObj = ( $OS_win ?
147             (new Win32::SerialPort ($self->{port})) :
148 1   50     11 (new Device::SerialPort ($self->{port})) )
149             || die "Can't open $$self{port}: $!\n";
150              
151 0         0 $PortObj->baudrate($self->{baud});
152 0         0 $PortObj->parity("none");
153 0         0 $PortObj->databits(8);
154 0         0 $PortObj->stopbits(1);
155 0 0       0 $PortObj->read_interval(5) if $OS_win;
156 0         0 $PortObj->write_settings;
157 0         0 $self->{serialtype} = 'SerialPort';
158 0         0 $PortObj;
159             }
160              
161             sub unix_connect {
162             #This was adapted from a script on connecting to a sony DSS, credits to its author (lost his email)
163 0     0 0 0 my $self = shift;
164 0         0 my $port = $self->{'port'};
165 0         0 my $baud = $self->{'baud'};
166 0         0 my($termios,$cflag,$lflag,$iflag,$oflag,$voice);
167              
168 0   0     0 my $serial = new FileHandle("+>$port") || die "Could not open $port: $!\n";
169              
170 0         0 $termios = POSIX::Termios->new();
171 0 0       0 $termios->getattr($serial->fileno()) || die "getattr: $!\n";
172 0         0 $cflag = 0 | CS8() | CREAD() |CLOCAL();
173 0         0 $lflag = 0;
174 0         0 $iflag = 0 | IGNBRK() |IGNPAR();
175 0         0 $oflag = 0;
176              
177 0         0 $termios->setcflag($cflag);
178 0         0 $termios->setlflag($lflag);
179 0         0 $termios->setiflag($iflag);
180 0         0 $termios->setoflag($oflag);
181 0 0       0 $termios->setattr($serial->fileno(),TCSANOW()) || die "setattr: $!\n";
182 0         0 eval qq[
183             \$termios->setospeed(POSIX::B$baud) || die "setospeed: \$!\n";
184             \$termios->setispeed(POSIX::B$baud) || die "setispeed: \$!\n";
185             ];
186              
187 0 0       0 die $@ if $@;
188              
189 0 0       0 $termios->setattr($serial->fileno(),TCSANOW()) || die "setattr: $!\n";
190              
191 0 0       0 $termios->getattr($serial->fileno()) || die "getattr: $!\n";
192 0         0 for (0..NCCS()) {
193 0 0       0 if ($_ == NCCS()) {
194 0         0 last;
195             }
196 0 0 0     0 if ($_ == VSTART() || $_ == VSTOP()) {
197 0         0 next;
198             }
199 0         0 $termios->setcc($_,0);
200             }
201 0 0       0 $termios->setattr($serial->fileno(),TCSANOW()) || die "setattr: $!\n";
202              
203 0         0 $self->{serialtype} = 'FileHandle';
204 0         0 $serial;
205             }
206              
207             sub stty_connect {
208 0     0 0 0 my $self = shift;
209 0         0 my $port = $self->{'port'};
210 0         0 my $baud = $self->{'baud'};
211 0         0 my($termios,$cflag,$lflag,$iflag,$oflag,$voice);
212              
213 0 0       0 if ($^O eq 'freebsd') {
214 0         0 my $cc = join(" ", map { "$_ undef" } qw(eof eol eol2 erase erase2 werase kill quit susp dsusp lnext reprint status));
  0         0  
215 0         0 system("$stty_path <$port cs8 cread clocal ignbrk ignpar ospeed $baud ispeed $baud $cc");
216 0 0       0 warn "$stty_path failed" if $?;
217 0         0 system("$stty_path <$port -e");
218             } else { # linux
219 0         0 my $cc = join(" ", map { "$_ undef" } qw(eof eol eol2 erase werase kill intr quit susp start stop lnext rprnt flush));
  0         0  
220 0         0 system("$stty_path <$port cs8 clocal -hupcl ignbrk ignpar ispeed $baud ospeed $baud $cc");
221 0 0       0 die "$stty_path failed" if $?;
222 0         0 system("$stty_path <$port -a");
223             }
224              
225 0 0       0 open(FH, "+>$port") or die "Could not open $port: $!\n";
226 0         0 $self->{serialtype} = 'FileHandle';
227 0         0 \*FH;
228             }
229              
230             sub usleep {
231 627     627 0 776 my $l = shift;
232 627   33     3410 $l = ref($l) && shift;
233 627         719123 select( undef,undef,undef,($l/1000));
234             }
235              
236 1219     1219 0 7507 sub serial { shift->{serial} }
237              
238 28     28 0 119 sub verbose { shift->{verbose} }
239              
240              
241             1;
242              
243              
244             __END__