package SCX::Reader;
-use Time::HiRes qw(gettimeofday tv_interval);
-use FileHandle;
-use SCX::CRC;
+use strict;
+
+use Time::HiRes qw(time);
+use Fcntl qw(F_GETFL F_SETFL O_NONBLOCK O_RDONLY);
our $PACKET_SIZE = 9; # 9 bytes + 0x05
-our $LOG_ROTATE = 600;
sub new {
my ($class, $args) = @_;
- my $callback = $args->{callback}
- or die "callback arg not defined";
-
- my $portname = $args->{portname}
- or die "portname not specified";
+ my $filename = $args->{filename}
+ or die "filename not specified";
- system 'stty', '-F', $portname, '115200', 'raw';
- if ($?) {
- die "stty died with code $? (no permissions?)";
- }
-
- open my $tty, '<:raw', $portname
- or die "Can't open $portname: $!";
-
- my $logfile = $args->{logfile};
- my $log_gen = 0;
-
- open my $logfh, '>', "$logfile.$log_gen"
- or die "Can't open $logfile.$log_gen: $!";
+ my $parser = $args->{parser}
+ or die "parser not specified";
+
+ my $fh;
+
+ if ($filename eq '-') {
+ open($fh, '<&=STDIN');
+ my $flags = fcntl($fh, F_GETFL, 0);
+ fcntl($fh, F_SETFL, $flags | O_NONBLOCK);
+ } else {
+ system 'stty', '-F', $filename, '115200', 'raw';
+ if ($?) {
+ die "stty died with code $? (no permissions?)";
+ }
- my $now = gettimeofday;
+ sysopen($fh, $filename, O_RDONLY|O_NONBLOCK)
+ or die "Can't open $filename: $!";
+ }
my $self = {
- portname => $portname,
- fh => $tty,
- logfile => $logfile,
- logfh => $logfh,
- log_gen => $log_gen,
- log_start => $now,
- starttime => $now,
- callback => $callback,
- bytes => [],
+ filename => $filename,
+ fh => $fh,
+ parser => $parser,
};
bless $self, $class;
my $data;
my $bytes_read = sysread $self->fh, $data, $PACKET_SIZE;
- die "Read error on $self->{portname}: $!"
+ die "Read error on $self->{filename}: $!"
if !$bytes_read;
- my @bytes = unpack("C*", $data);
-
- push @{ $self->{bytes} }, @bytes;
- @bytes = @{ $self->{bytes} };
-
- my @bad_bytes;
-
- while (@bytes > $PACKET_SIZE) {
- if ($bytes[0] != 0x55) {
- push @bad_bytes, shift @bytes;
- next;
- }
- my $cmd = $bytes[1];
-
- if ($bytes[$PACKET_SIZE] != 0x05
- || SCX::CRC::digest(@bytes[0..$PACKET_SIZE-2])
- != $bytes[$PACKET_SIZE-1]) {
- push @bad_bytes, shift @bytes;
- next;
- }
-
- if (@bad_bytes) { # Report previous bad bytes first
- $self->log_bytes(\@bad_bytes, "Cannot parse packet");
- @bad_bytes = ();
- }
-
- my @packet = splice @bytes, 0, $PACKET_SIZE+1;
- my $rv = &{ $self->{callback} }(@packet[1..$PACKET_SIZE]);
- $self->log_bytes(@packet, $rv);
- }
- $self->log_bad_bytes(\@bad_bytes, "Cannot parse packet");
-
- @{ $self->{bytes} } = @bytes;
-}
+ my $now = time;
-sub log_bytes {
- my ($self, $bytes, $msg) = @_;
-
- return if !@$bytes;
-
- $msg = defined $msg ? ' # ' . $msg : '';
-
- my $now = gettimeofday;
-
- if ($now - $self->{log_start} >= $LOG_ROTATE) {
- close $self->{logfh};
- $self->{log_gen} = $self->{log_gen} ? 0 : 1;
- open my $fh, '>', $logfile . '.' . $self->{log_gen}
- or die "Can't open $logfile.$self->{log_gen}: $!";
- $self->{logfh} = $fh;
- $self->{log_start} = $now;
- }
+ my @bytes = unpack("C*", $data);
- $self->{logfh}->print(sprintf('% 10.3f', $now - $self->{starttime}),
- (map { sprintf(" %02x", $_) } @bytes),
- $msg, "\n");
+ $self->{parser}->add_data($now, @bytes);
}
1;