#!/usr/bin/perl -w

use strict;
use Device::SerialPort 0.12;

#printf "%016b\n",&getValue(0x7F, 0x26);
#exit 1;

my ($logFile, $frameSize, $scopeRate, $portFile)=&readArgs(@ARGV);
my $port = &initPort($portFile);
&mainLoop($logFile, $frameSize, $scopeRate, $port);


sub readArgs {
  my $logFile = "";
  my $frameSize = 0x1000;
  my $scopeRate = 10;
  my $portFile  = "/dev/ttyS0";
  my $cnt=0;
  while ($cnt<=$#_) {
    my $option = $_[$cnt++];
    printf "O=%s\n",$option;
    if ($option eq "-s") {
      $scopeRate = $_[$cnt++];
    } elsif ($option eq "-f") {
      $frameSize = $_[$cnt++];
    } elsif ($option eq "-l") {
      $logFile = $_[$cnt++];
    } elsif ($option eq "-p") {
      $portFile = $_[$cnt++];
    } else {
      &usage();
    }
  }
  printf STDERR "logFile   = %s\n",$logFile;
  printf STDERR "frameSize = %s\n",$frameSize;
  printf STDERR "scopeRate = %s\n",$scopeRate;
  printf STDERR "port      = %s\n",$portFile;
  return ($logFile, $frameSize, $scopeRate, $portFile);
}


sub usage {
  die "Usage: logger.pl [-s scopeRate] [-f frameSize] [-l logFile] [-p port]\n";
}


sub initPort {
  my ($portFile)=@_;
  my $port = Device::SerialPort->new ($portFile) || die "Can't Open $portFile: $!";
  $port->baudrate(1200)    || die "failed setting baudrate";
  $port->parity("none")    || die "failed setting parity";
  $port->databits(8)       || die "failed setting databits";
  $port->handshake("none") || die "failed setting handshake";
  $port->write_settings    || die "no settings";
  return $port;
}


sub mainLoop {
  my ($logFile, $frameSize, $scopeRate, $port)=@_;
  undef $logFile unless length($logFile)>0;
  $scopeRate*=2;
  if (defined $logFile) {
    open LOG,">$logFile";
    binmode LOG;
    print LOG pack("L",$frameSize);
    flush LOG;
  }

  my $counter = 0;
  my $waveCtr = 0;
  my $offset = 0;
  #my $veryOldNum = 0xFF;
  my $oldNum = 0xFF;
  while(1==1) {
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = gmtime();
    if ($hour % 6 == 0 and $min == 0 and $sec == 0) {
      my $timestamp = time();
      print LOG pack("L",$timestamp);
      last;
    }
    my ($count_in, $string_in) = $port->read(1);
    next unless $count_in>0;
    my $num=ord($string_in);
    if (defined $logFile) {
      if ($counter==0) {
        flush LOG;
        my $timestamp = time();
        print LOG pack("L",$timestamp);
        printf STDERR "Frame %08x\n",$timestamp if $scopeRate<1;
      }
      $counter++;
      $counter=0 if $counter>=$frameSize;
      print LOG pack("C",$num);
    }
    if ($scopeRate>0) {
      $waveCtr++;
      if ($waveCtr>=$scopeRate+$offset) {
        $waveCtr = 0;
        #printf STDERR "%08b %08b %08b",$veryOldNum,$oldNum,$num;
	my $value = &getValue($num, $oldNum);
	#my $value2 = &getValue($oldNum, $veryOldNum);
        #printf STDERR " %d %d\n",$value1,$value2;
	if ($value<0) {
	  print "- ??? -\n";
	  $offset = 1;
	} else {
          my $off=78*$value/1024;
          print STDERR " "x$off."#\n";
	  $offset = 0;
	}
      }
    }
    #$veryOldNum = $oldNum;
    $oldNum = $num;
  }
  close LOG if defined $logFile;
}


sub getValue {
  my ($hi, $lo)=@_;
  my $crc = 0;
  $crc|=(($lo & 0x01)<<2) ^ (($lo & 0x20)>>3);
  #printf "%08b + %08b -> %08b\n",($lo & 0x01)<<2,($lo & 0x20)>>3,$crc;
  $crc|=(($lo & 0x02)<<2) ^ (($lo & 0x40)>>3);
  #printf "%08b + %08b -> %08b\n",($lo & 0x02)<<2,($lo & 0x40)>>3,$crc;
  $crc|=(($lo & 0x04)<<2) ^ (($lo & 0x80)>>3);
  #printf "%08b + %08b -> %08b\n",($lo & 0x04)<<2,($lo & 0x80)>>3,$crc;
  $crc|=(($lo & 0x08)<<2) ^ (($hi & 0x01)<<5);
  #printf "%08b + %08b -> %08b\n",($lo & 0x08)<<2,($hi & 0x01)<<5,$crc;
  $crc|=(($lo & 0x10)<<2) ^ (($hi & 0x02)<<5);
  #printf "%08b + %08b -> %08b\n",($lo & 0x10)<<2,($hi & 0x02)<<5,$crc;
  #printf "%08b == %08b\n",$hi & 0xFC,$crc;
  if (($hi & 0xFC) eq $crc) {
    return (($hi & 0x03) << 8) | $lo;
  } else {
    return -1;
  }
}
