From be26081d0b1f61811fa57640bf791558273caba6 Mon Sep 17 00:00:00 2001 From: "Jan \"Yenya\" Kasprzak" Date: Tue, 30 Nov 2010 23:33:50 +0100 Subject: [PATCH] Proof-of-concept implementation. --- SCX/CRC.pm | 58 +++++++++++++++++++++++++ SCX/Reader.pm | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++ digest | 21 ++++++++++ ttymon | 47 +++++++++++++++++++++ 4 files changed, 240 insertions(+) create mode 100755 SCX/CRC.pm create mode 100644 SCX/Reader.pm create mode 100755 digest create mode 100755 ttymon diff --git a/SCX/CRC.pm b/SCX/CRC.pm new file mode 100755 index 0000000..300cb53 --- /dev/null +++ b/SCX/CRC.pm @@ -0,0 +1,58 @@ +#!/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; + diff --git a/SCX/Reader.pm b/SCX/Reader.pm new file mode 100644 index 0000000..1b7c44f --- /dev/null +++ b/SCX/Reader.pm @@ -0,0 +1,114 @@ +#!/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; + diff --git a/digest b/digest new file mode 100755 index 0000000..95af211 --- /dev/null +++ b/digest @@ -0,0 +1,21 @@ +#!/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)); +} + diff --git a/ttymon b/ttymon new file mode 100755 index 0000000..c89dae6 --- /dev/null +++ b/ttymon @@ -0,0 +1,47 @@ +#!/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; + -- 2.43.0