+#!/usr/bin/perl -w
+
+package SCX::Reader;
+
+use Time::HiRes qw(gettimeofday tv_interval);
+use FileHandle;
+use SCX::CRC;
+
+our $PACKET_SIZE = 10;
+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";
+
+ 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 $now = gettimeofday;
+
+ my $self = {
+ portname => $portname,
+ fh => $tty,
+ logfile => $logfile,
+ logfh => $logfh,
+ log_gen => $log_gen,
+ log_start => $now,
+ starttime => $now,
+ callback => $callback,
+ bytes => [],
+ };
+
+ bless $self, $class;
+
+ return $self;
+}
+
+sub fh { return shift->{fh}; }
+
+sub read {
+ my ($self) = @_;
+
+ my $data;
+ my $bytes_read = sysread $self->fh, $data, $PACKET_SIZE;
+ die "Read error on $self->{portname}: $!"
+ if !$bytes_read;
+
+ 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),
+ "\n");
+
+ push @{ $self->{bytes} }, @bytes;
+ @bytes = @{ $self->{bytes} };
+
+ my @bad_bytes;
+
+ while (@bytes >= $PACKET_SIZE) {
+ if ($bytes[0] != 0x55 || $bytes[9] != 0x05
+ || SCX::CRC::digest(@bytes[0..7]) != $bytes[8]) {
+ push @bad_bytes, shift @bytes;
+ next;
+ }
+
+ if (@bad_bytes) {
+ $self->{logfh}->print("Cannot parse bytes",
+ (map { sprintf(' %02x', $_) } @bad_bytes),
+ "\n");
+ @bad_bytes = ();
+ }
+
+ $self->{logfh}->print("Callback\n");
+ &{ $self->{callback} }(@bytes[1..7]);
+ splice @bytes, 0, 10;
+ }
+ if (@bad_bytes) {
+ $self->{logfh}->print("Cannot parse bytes",
+ (map { sprintf(' %02x', $_) } @bad_bytes),
+ "\n");
+ @bad_bytes = ();
+ }
+
+ @{ $self->{bytes} } = @bytes;
+}
+
+1;
+