--- /dev/null
+#!/usr/bin/perl -w
+
+use strict;
+
+package SCX::CRC;
+
+our @crctable;
+
+sub import {
+ return if @crctable;
+
+ my @table = (0x31);
+
+ for my $i (1..7) {
+ my $n = 2 * $table[-1];
+ push @table, $n > 0xff ? ($n ^ 0x31) & 0xff: $n;
+ }
+
+ @crctable = (0x00);
+
+# print "Table = ", join(' ', map { sprintf("%02x", $_) } @table), "\n";
+
+ for my $i (0x01 .. 0xff) {
+ $crctable[$i] ^= $table[0] if $i & 0x01;
+ $crctable[$i] ^= $table[1] if $i & 0x02;
+ $crctable[$i] ^= $table[2] if $i & 0x04;
+ $crctable[$i] ^= $table[3] if $i & 0x08;
+ $crctable[$i] ^= $table[4] if $i & 0x10;
+ $crctable[$i] ^= $table[5] if $i & 0x20;
+ $crctable[$i] ^= $table[6] if $i & 0x40;
+ $crctable[$i] ^= $table[7] if $i & 0x80;
+ }
+
+# print "CRCtable = ", join(' ', map { sprintf("%02x", $_) } @crctable), "\n";
+}
+
+sub digest_str {
+ my ($str) = @_;
+
+ return digest(unpack("C*", $str));
+
+}
+
+sub digest {
+ my (@bytes) = @_;
+
+ my $res = 0;
+
+ for my $byte (@bytes) {
+ my $idx = $byte ^ $res;
+ $res = $crctable[$idx];
+ }
+
+ return $res ^ 0xbb;
+}
+
+1;
+
--- /dev/null
+#!/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;
+
--- /dev/null
+#!/usr/bin/perl -w
+
+use strict;
+use SCXCRC;
+
+my @data = (
+ # ocekavam 0x7d
+ pack("C*", 0x55, 0xff, 0xf0, 0xf0, 0xf0, 0xaa, 0xaa, 0xaa),
+
+ # ocekavam 0xb0
+ pack("C*", 0x55, 0xd6, 0x88, 0x88, 0x88, 0x14, 0x50, 0xaa),
+);
+
+for my $str (@data) {
+# my $c = Digest::CRC->new(type=>'crc8', poly => 0x31, init=>0,
+# xorout=>0xbb);
+# $c->add($str);
+# print $c->hexdigest, "\n";
+ print sprintf("%02x\n", SCXCRC::digest_str($str));
+}
+
--- /dev/null
+#!/usr/bin/perl -w
+
+use Time::HiRes qw(gettimeofday tv_interval);
+use Event::Lib;
+use SCX::Reader;
+
+my ($portname, $logfile) = @ARGV;
+
+if (!defined $portname || !defined $logfile) {
+ die "Usage: $0 /dev/ttyUSB0 logfile\n";
+}
+
+my $reader = SCX::Reader->new({
+ portname => $portname,
+ logfile => $logfile,
+ callback => \&do_packet,
+});
+
+sub stdin_read {
+ my $event = shift;
+ my $fh = $event->fh;
+
+ my $data = <$fh>;
+ chomp $data;
+ print "===== ", $data, " =====\n";
+ $event->add;
+}
+
+sub tty_read {
+ my $event = shift;
+
+ $reader->read();
+ $event->add;
+}
+
+sub do_packet {
+ print "do_packet\n";
+}
+
+my $tty_reader = event_new($reader->fh, EV_READ, \&tty_read);
+my $stdin_reader = event_new(\*STDIN, EV_READ, \&stdin_read);
+
+$tty_reader->add;
+$stdin_reader->add;
+
+event_mainloop;
+