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.4 by root, Fri Jul 18 01:31:12 2008 UTC vs.
Revision 1.7 by root, Sat Jul 26 05:34:58 2008 UTC

56The host to connect to, default is C<locahost>. 56The host to connect to, default is C<locahost>.
57 57
58=item port => $port 58=item port => $port
59 59
60The port to connect to, default is C<2947>. 60The port to connect to, default is C<2947>.
61
62=item min_speed => $speed_in_m_per_s
63
64Sets the mininum speed (default: 0) that is considered real for the
65purposes of replay compression or estimate. Speeds below this value will
66be considered 0.
61 67
62=item on_error => $cb->($gps) 68=item on_error => $cb->($gps)
63 69
64Called on every connection or protocol failure, reason is in C<$!> 70Called on every connection or protocol failure, reason is in C<$!>
65(protocl errors are signalled via EBADMSG). Can be used to bail out if you 71(protocl errors are signalled via EBADMSG). Can be used to bail out if you
140 $self->connect; 146 $self->connect;
141 147
142 $self 148 $self
143} 149}
144 150
151sub DESTROY {
152 my ($self) = @_;
153
154 $self->record_log;
155}
156
145sub event { 157sub event {
146 my $event = splice @_, 1, 1, (); 158 my $event = splice @_, 1, 1, ();
147 159
148 warn "event<$event,@_>\n";#d# 160 #warn "event<$event,@_>\n";#d#
149 if ($event = $_[0]{"on_$event"}) { 161 if ($event = $_[0]{"on_$event"}) {
150 &$event; 162 &$event;
151 } 163 }
152} 164}
153 165
214 }, 226 },
215 on_read => sub { 227 on_read => sub {
216 $_[0]{rbuf} =~ s/^([^\015\012]*)\015\012// 228 $_[0]{rbuf} =~ s/^([^\015\012]*)\015\012//
217 or return; 229 or return;
218 230
219 $self->feed ($1); 231 $self->feed ($1)
232 unless $self->{replay_cb};
220 }, 233 },
221 ; 234 ;
222 235
223 $self->send ("w"); 236 $self->send ("w");
224 $self->send ("o"); 237 $self->send ("o");
281 if (@data > 3) { 294 if (@data > 3) {
282 # the gpsd time is virtually useless as it is truncated :/ 295 # the gpsd time is virtually useless as it is truncated :/
283 for (qw(tag _time _terr lat lon alt herr verr bearing speed vspeed berr serr vserr mode)) { 296 for (qw(tag _time _terr lat lon alt herr verr bearing speed vspeed berr serr vserr mode)) {
284 $type = shift @data; 297 $type = shift @data;
285 $fix->{$_} = $type eq "?" ? undef : $type; 298 $fix->{$_} = $type eq "?" ? undef : $type;
299 }
300
301 if (my $s = $self->{stretch}) {
302 $s = 1 / $s;
303
304 $fix->{herr} *= $s; # ?
305 $fix->{verr} *= $s; # ?
306 $fix->{berr} *= $s; # ?
307 $fix->{serr} *= $s; # ?
308 $fix->{vserr} *= $s; # ?
309
310 $fix->{speed} *= $s;
311 $fix->{vspeed} *= $s;
286 } 312 }
287 313
288 $fix->{mode} = 2 if $fix->{mode} eq "?"; # arbitrary choice 314 $fix->{mode} = 2 if $fix->{mode} eq "?"; # arbitrary choice
289 } else { 315 } else {
290 $fix->{mode} = 1; 316 $fix->{mode} = 1;
322} 348}
323 349
324=item ($lat, $lon) = $gps->estimate ([$max_seconds]) 350=item ($lat, $lon) = $gps->estimate ([$max_seconds])
325 351
326This returns an estimate of the current position based on the last fix and 352This returns an estimate of the current position based on the last fix and
327the time passed since then. Useful for interactive applications where you 353the time passed since then.
328want more frequent updates, but not very useful to store, as the next fix 354
329might well be totally off. 355Useful for interactive applications where you want more frequent updates,
356but not very useful to store, as the next fix might well be totally
357off. For example, when displaying a real-time map, you could simply call
358C<estimate> ten times a second and update the cursor or map position, but
359you should use C<on_fix> to actually gather data to plot the course itself.
330 360
331If the fix is older then C<$max_seconds> (default: C<1.9> times the update 361If the fix is older then C<$max_seconds> (default: C<1.9> times the update
332interval, i.e. usually C<1.9> seconds) or if no fix is available, returns 362interval, i.e. usually C<1.9> seconds) or if no fix is available, returns
333the empty list. 363the empty list.
334 364
346 376
347 my $diff = AnyEvent->time - $fix->{time}; 377 my $diff = AnyEvent->time - $fix->{time};
348 378
349 $diff <= $max or return; 379 $diff <= $max or return;
350 380
351 if ($fix->{speed} > $fix->{serr}) { 381 if ($fix->{speed} >= $self->{min_speed}) {
352 my ($lat, $lon) = $geo->forward ($fix->{lat}, $fix->{lon}, $fix->{bearing}, $fix->{speed} * $diff); 382 my ($lat, $lon) = $geo->forward ($fix->{lat}, $fix->{lon}, $fix->{bearing}, $fix->{speed} * $diff);
353 ($lat, $lon) 383 ($lat, $lon)
354 384
355 } else { 385 } else {
356 # if we likely have zero speed, return the point itself 386 # if we likely have zero speed, return the point itself
363 393
364 syswrite $self->{logfh}, JSON::encode_json ([AnyEvent->time, @arg]) . "\n" 394 syswrite $self->{logfh}, JSON::encode_json ([AnyEvent->time, @arg]) . "\n"
365 if $self->{logfh}; 395 if $self->{logfh};
366} 396}
367 397
398=item $gps->record_log ($path)
399
400If C<$path> is defined, then that file will be created or truncated and a
401log of all (raw) packets received will be written to it. This log file can
402later be replayed by calling C<< $gps->replay_log ($path) >>.
403
404If C<$path> is undefined then the log will be closed.
405
406=cut
407
368sub record_log { 408sub record_log {
369 my ($self, $path) = @_, 409 my ($self, $path) = @_;
370 410
411 if (defined $path) {
412 $self->record_log;
413
371 require JSON; 414 require JSON;
372 415
373 open $self->{logfh}, ">", $path 416 open $self->{logfh}, ">:perlio", $path
374 or Carp::croak "$path: $!"; 417 or Carp::croak "$path: $!";
375 418
376 $self->log (start => $VERSION); 419 $self->log (start => $VERSION, 0, 0, { interval => $self->{interval} });
420 } elsif ($self->{logfh}) {
421 $self->log ("stop");
422 delete $self->{logfh};
423 }
424}
425
426=item $gps->replay_log ($path, %options)
427
428Replays a log file written using C<record_log> (or stops replaying when
429C<$path> is undefined). While the log file replays, real GPS events will
430be ignored. This comes in handy when testing.
431
432Please note that replaying a log will change configuration options that
433will not be restored, so it's best not to reuse a gpsd object after a
434replay.
435
436The C<AnyEvent::GPSD> distribution comes with an example log
437(F<eg/example.aegps>) that you can replay for testing or enjoyment
438purposes.
439
440The options include:
441
442=over 4
443
444=item compress => 1
445
446If set to a true value (default: false), then passages without fix will be
447replayed much faster than passages with fix. The same happens for passages
448without much movement.
449
450=item stretch => $factor
451
452Multiplies all times by the given factor. Values < 1 make the log replay
453faster, values > 1 slower. Note that the frequency of fixes will not be
454increased, o stretch factors > 1 do not work well.
455
456A stretch factor of zero is not allowed, but if you want to replay a log
457instantly you may speicfy a very low value (e.g. 1e-10).
458
459=back
460
461=cut
462
463sub replay_log {
464 my ($self, $path, %option) = @_;
465
466 if (defined $path) {
467 $self->replay_log;
468
469 require JSON;
470
471 open my $fh, "<:perlio", $path
472 or Carp::croak "$path: $!";
473
474 $self->{stretch} = $option{stretch} || 1;
475 $self->{compress} = $option{compress};
476
477 $self->{imterval} /= $self->{stretch};
478
479 Scalar::Util::weaken $self;
480
481 $self->{replay_cb} = sub {
482 my $line = <$fh>;
483
484 if (2 > length $line) {
485 $self->replay_log;
486 } else {
487 my ($time, $type, @data) = @{ JSON::decode_json ($line) };
488
489 $time *= $self->{stretch};
490
491 if ($type eq "start") {
492 my ($module_version, $major_version, $minor_version, $args) = @data;
493
494 $self->{interval} = ($args->{interval} || 1) / $self->{stretch};
495 }
496
497 if (
498 $type eq "start"
499 or ($self->{compress}
500 and $self->{fix} && ($self->{fix}{mode} < 2 || $self->{fix}{speed} < $self->{min_speed}))
501 ) {
502 $self->{replay_now} = $time;
503 }
504
505 $self->{replay_timer} = AnyEvent->timer (after => $time - $self->{replay_now}, cb => sub {
506 $self->{replay_now} = $time;
507 $self->{command} = []; # no can do
508 $self->feed ($data[0]) if $type eq "raw";
509 $self->{replay_cb}();
510 });
511 }
512 };
513
514 $self->{replay_cb}();
515
516 } else {
517 delete $self->{stretch};
518 delete $self->{compress};
519 delete $self->{replay_timer};
520 delete $self->{replay_cb};
521 }
377} 522}
378 523
379=back 524=back
380 525
381=head1 SEE ALSO 526=head1 SEE ALSO

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines