ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent-GPSD/GPSD.pm
(Generate patch)

Comparing AnyEvent-GPSD/GPSD.pm (file contents):
Revision 1.1 by root, Wed Jul 2 04:57:02 2008 UTC vs.
Revision 1.4 by root, Fri Jul 18 01:31:12 2008 UTC

88 88
89C<snr> contains the signal strength in decibals (28+ is usually the 89C<snr> contains the signal strength in decibals (28+ is usually the
90minimum value for a good fix). 90minimum value for a good fix).
91 91
92C<fix> contains either C<1> to indicate that this satellite was used for 92C<fix> contains either C<1> to indicate that this satellite was used for
93the last position fix, C<0> otherwise. EGNOS/WAAS etc. satellites will 93the last position fix, C<0> otherwise. EGNOS/WAAS etc. satellites will
94always show as C<0>, even if their correction info was used. 94always show as C<0>, even if their correction info was used.
95 95
96The passed hash references are read-only.
97
96=item on_fix => $cb->({point}) 98=item on_fix => $cb->({point})
97 99
98Called regularly. The C<{point}> hash contains at least the following 100Called regularly (usually about once/second), even when there is no
99members: 101connection to the GPSD (so is useful to update your idea of the current
102position). The passed hash reference must I<not> be modified in any way.
103
104If C<mode> is C<2> or C<3>, then the C<{point}> hash contains at least the
105following members, otherwise it is undefined which members exist. Members
106whose values are not known are C<undef> (usually the error values, speed
107and so on).
100 108
101 time when this fix was received (s) 109 time when this fix was received (s)
102 110
103 lat latitude (S -90..90 N) 111 lat latitude (S -90..90 N)
104 lon longitude (W -180..180 E) 112 lon longitude (W -180..180 E)
122 130
123sub new { 131sub new {
124 my $class = shift; 132 my $class = shift;
125 my $self = bless { 133 my $self = bless {
126 @_, 134 @_,
135 interval => 1,
136 fix => { time => AnyEvent->now, mode => 1 },
127 }, $class; 137 }, $class;
128 138
139 $self->interval_timer;
129 $self->connect; 140 $self->connect;
130 141
131 $self 142 $self
132} 143}
133 144
142 153
143sub retry { 154sub retry {
144 my ($self) = @_; 155 my ($self) = @_;
145 156
146 delete $self->{fh}; 157 delete $self->{fh};
158 delete $self->{command};
147 159
148 Scalar::Util::weaken $self; 160 Scalar::Util::weaken $self;
149 $self->{retry_w} = AnyEvent->timer (after => 1, cb => sub { 161 $self->{retry_w} = AnyEvent->timer (after => 1, cb => sub {
150 delete $self->{retry_w}; 162 delete $self->{retry_w};
151 $self->connect; 163 $self->connect;
152 }); 164 });
165}
166
167# make sure we send "no fix" updates when we lose connectivity
168sub interval_timer {
169 my ($self) = @_;
170
171 $self->{interval_w} = AnyEvent->timer (after => $self->{interval}, cb => sub {
172 if (AnyEvent->now - $self->{fix}{time} > $self->{interval} * 1.9) {
173 $self->{fix}{mode} = 1;
174 $self->event (fix => $self->{fix});
175 }
176
177 $self->interval_timer;
178 });
179
180 Scalar::Util::weaken $self;
153} 181}
154 182
155sub connect { 183sub connect {
156 my ($self) = @_; 184 my ($self) = @_;
157 185
177 on_error => sub { 205 on_error => sub {
178 $self->event ("error"); 206 $self->event ("error");
179 $self->retry; 207 $self->retry;
180 }, 208 },
181 on_eof => sub { 209 on_eof => sub {
182 $! = &Errno::EBADMSG; 210 $! = &Errno::EPIPE;
183 $self->event ("error"); 211 $self->event ("error");
212 $self->log ("disconnect");
184 $self->retry; 213 $self->retry;
185 }, 214 },
186 on_read => sub { 215 on_read => sub {
187 $_[0]{rbuf} =~ s/^([^\015\012]*)\015\012// 216 $_[0]{rbuf} =~ s/^([^\015\012]*)\015\012//
188 or return; 217 or return;
192 ; 221 ;
193 222
194 $self->send ("w"); 223 $self->send ("w");
195 $self->send ("o"); 224 $self->send ("o");
196 $self->send ("y"); 225 $self->send ("y");
226 $self->send ("c");
197 227
198 $self->event ("connect"); 228 $self->event ("connect");
229 $self->log ("connect");
199 } else { 230 } else {
200 $self->event ("error"); 231 $self->event ("error");
201 } 232 }
202 }; 233 };
203 234
223sub feed { 254sub feed {
224 my ($self, $line) = @_; 255 my ($self, $line) = @_;
225 256
226 $self->{now} = AnyEvent->now; 257 $self->{now} = AnyEvent->now;
227 258
259 $self->log (raw => $line)
260 if $self->{logfh};
261
228 unless ($line =~ /^GPSD,(.)=(.*)$/) { 262 unless ($line =~ /^GPSD,(.)=(.*)$/) {
229 $! = &Errno::EBADMSG; 263 $! = &Errno::EBADMSG;
230 $self->event ("error"); 264 $self->event ("error");
231 return $self->retry; 265 return $self->retry;
232 } 266 }
233 267
234 my ($type, $data) = ($1, $2); 268 my ($type, $data) = ($1, $2);
235 269
270 #warn "$type=$data\n";#d#
271
236 $self->{state}{$type} = [$data => $self->{now}]; 272 $self->{state}{$type} = [$data => $self->{now}];
237 273
238 if ($type eq "O") { 274 if ($type eq "O") {
239 my @data = split /\s+/, $data; 275 my @data = split /\s+/, $data;
276
277 my $fix = $self->{fix};
278
240 my %fix = (time => $self->{now}); 279 $fix->{time} = $self->{now};
241 280
242 if (@data > 3) { 281 if (@data > 3) {
243 # the gpsd time is virtually useless as it is truncated :/ 282 # the gpsd time is virtually useless as it is truncated :/
244 $fix{$_} = shift @data for qw(tag _time _terr lat lon alt herr verr bearing speed vspeed berr serr vserr mode); 283 for (qw(tag _time _terr lat lon alt herr verr bearing speed vspeed berr serr vserr mode)) {
284 $type = shift @data;
285 $fix->{$_} = $type eq "?" ? undef : $type;
286 }
245 287
246 $fix{mode} = 2 if $fix{mode} eq "?"; # arbitrary choice 288 $fix->{mode} = 2 if $fix->{mode} eq "?"; # arbitrary choice
247 } else { 289 } else {
248 $fix{mode} = 1; 290 $fix->{mode} = 1;
249 } 291 }
250 292
251 $self->{fix} = \%fix;
252 $self->event (fix => \%fix); 293 $self->event (fix => $fix);
253 294
254 } elsif ($type eq "Y") { 295 } elsif ($type eq "Y") {
255 my (undef, @sats) = split /:/, $data; 296 my (undef, @sats) = split /:/, $data;
256 297
257 $self->{satellite_info} = [map { 298 $self->{satellite_info} = [map {
264 fix => $sat[4], 305 fix => $sat[4],
265 } 306 }
266 } @sats]; 307 } @sats];
267 308
268 $self->event (satellite_update => $self->{satellite_info}); 309 $self->event (satellite_update => $self->{satellite_info});
310
311 } elsif ($type eq "C") {
312 $self->{interval} = $data >= 1 ? $data * 1 : 1;
269 } 313 }
270 314
271 # we (wrongly) assume that gpsd responses are always in response 315 # we (wrongly) assume that gpsd responses are always in response
272 # to an earlier command 316 # to an earlier command
273 317
282This returns an estimate of the current position based on the last fix and 326This returns an estimate of the current position based on the last fix and
283the time passed since then. Useful for interactive applications where you 327the time passed since then. Useful for interactive applications where you
284want more frequent updates, but not very useful to store, as the next fix 328want more frequent updates, but not very useful to store, as the next fix
285might well be totally off. 329might well be totally off.
286 330
287If the fix is older then C<$max_seconds> (default: C<1.9>) or if no fix is 331If the fix is older then C<$max_seconds> (default: C<1.9> times the update
288available, returns the empty list. 332interval, i.e. usually C<1.9> seconds) or if no fix is available, returns
333the empty list.
289 334
290=cut 335=cut
291 336
292sub estimate { 337sub estimate {
293 my ($self, $max) = @_; 338 my ($self, $max) = @_;
294 339
295 $max ||= 1.9 unless defined $max; 340 $max ||= 1.9 * $self->{interval} unless defined $max;
296 341
297 my $geo = $self->{geo_forward} ||= new Geo::Forward; 342 my $geo = $self->{geo_forward} ||= new Geo::Forward;
298 343
299 my $fix = $self->{fix} or return; 344 my $fix = $self->{fix} or return;
300 $fix->{mode} >= 2 or return; 345 $fix->{mode} >= 2 or return;
311 # if we likely have zero speed, return the point itself 356 # if we likely have zero speed, return the point itself
312 ($fix->{lat}, $fix->{lon}) 357 ($fix->{lat}, $fix->{lon})
313 } 358 }
314} 359}
315 360
361sub log {
362 my ($self, @arg) = @_;
363
364 syswrite $self->{logfh}, JSON::encode_json ([AnyEvent->time, @arg]) . "\n"
365 if $self->{logfh};
366}
367
368sub record_log {
369 my ($self, $path) = @_,
370
371 require JSON;
372
373 open $self->{logfh}, ">", $path
374 or Carp::croak "$path: $!";
375
376 $self->log (start => $VERSION);
377}
378
316=back 379=back
317 380
318=head1 SEE ALSO 381=head1 SEE ALSO
319 382
320L<AnyEvent>. 383L<AnyEvent>.

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines