wrapper about serial port read/write
[vrDialog] / dialog.pl
index b0e630d..6e3445e 100755 (executable)
--- a/dialog.pl
+++ b/dialog.pl
@@ -5,7 +5,10 @@ use strict;
 use Data::Dump qw(dump);
 use Device::SerialPort qw(:STAT);
 
+my $debug = $ENV{DEBUG} || 0;
+
 my $port = Device::SerialPort->new('/dev/ttyUSB0');
+die "can't open serial port" unless $port;
 $port->baudrate(9600);
 $port->databits(8);
 $port->parity('none');
@@ -15,6 +18,19 @@ $port->handshake('none');
 $port->read_char_time(500);
 $port->read_const_time(1000);
 
+sub read_serial {
+       my $len = shift;
+       return $port->read( $len );
+}
+
+sub write_serial {
+       my $bytes = shift;
+       return $port->write( $bytes );
+}
+
+# TODO: implement remote serial port
+# remserial -x 2 -p 23000 -s "9600 raw" /dev/ttyUSB0
+
 sub as_hex {
        my @out;
        foreach my $str ( @_ ) {
@@ -32,24 +48,82 @@ sub hex2bytes {
        return $bytes;
 }
 
-sub v {
-       my ($hex,$expect,$desc) = @_;
-       my $bytes = hex2bytes( $hex );
+sub crc {
+       my $data = shift;
+       my $crc = 0;
+       for my $i ( 0 .. length($data) - 2 ) {
+               if ( $crc & 0x80 ) {
+                       $crc = ( $crc << 1 ) ^ 25;
+               } else {
+                       $crc = $crc << 1;
+               }
+               $crc = $crc & 0xff;
+               my $byte = ord(substr($data,$i,1));
+               $crc = $crc ^ $byte;
+#              warn "## ", as_hex(chr($byte)), " crc = ", $crc, " ", as_hex(chr($crc));
+       }
+       # ignore checksum errors for FF, we will calulate them!
+       if ( chr($crc) ne substr($data,-1,1) && substr($data,-1,1) ne "\xFF" ) {
+               warn "CRC error for ",as_hex($data), " calulated ", as_hex(chr($crc));
+       }
+
+       return substr($data,0,-1) . chr($crc);
+}
+
+sub v_bytes {
+       my ($bytes,$desc) = @_;
        warn "# $desc\n";
+retry:
        warn ">> ",as_hex( $bytes );
-       $port->write( $bytes );
+       crc( $bytes );
+       write_serial( $bytes );
+
+       my $data = read_serial(1);
+       warn "<< len: ",ord($data) if $debug;
 
-       my $data = $port->read(1);
-       warn "<< len: ",ord($data);
-       $data .= $port->read(ord($data) - 1);
+       goto retry if ord($data) == 0;
+
+       $data .= read_serial(ord($data) - 1);
+       crc($data);
        warn "<< ",as_hex($data);
-       warn "?? $expect\n" if $expect;
 
+       my $o = 2;
+       while ( $o < length($data) - 2 ) {
+               my $n = unpack('n', substr($data,$o,2));
+               $n = -( 0xffff - $n ) if $n & 0x8000;
+               warn "## $o = ",$n, "\t",$n / 16,"\n";
+               $o += 2;
+       }
+
+       while ( $o < length($data) - 1 ) {
+               my $n = unpack('c', substr($data,$o,1));
+               warn "## $o = ", $n, "\n";
+               $o += 1;
+       }
+
+       return $data;
+}
+
+sub v {
+       my ($hex,$desc) = @_;
+       v_bytes( hex2bytes( $hex ), $desc );
 }
 
-#v '07 02 00 00 00 04 C4', "hardware version";
+if ( ! @ARGV ) {
+       v '07 02 00 00 00 04 C4', "hardware version";
+
+       v '07 0A 00 00 00 04 44', 'software version';
 
-#v '07 0A 00 00 00 04 44', 'software version';
+       v '07 00 01 00 06 0E EA', 'temperatures';
 
-v '07 00 01 00 06 0E EA', 'temperatures';
+       v '07 00 00 00 26 0A A6', 'last errros';
+}
+
+#v '07 00 00 00 26 00 AC', 'last errros (with invalid length)';
 
+foreach my $reg ( @ARGV ) {
+       warn "# send user $reg\n";
+       v_bytes(
+               crc( hex2bytes( "07 00 00 00 $reg 01 FF" ) )
+       ,"user: $reg");
+}