#!/usr/bin/perl -w
use strict;

use POSIX qw(strftime);
use Time::HiRes qw(gettimeofday tv_interval usleep);
use IO::Termios;
use IO::Select;
use constant ACK => chr(6);

my $interval = 5;

my %esc = (
	2 => '<STX>',
	3 => '<ETX>',
	10 => '\\n',
	13 => '\\r',
);
sub escape($) {
	my $in = shift;
	my $out = '';
	foreach my $c (split //, $in) {
		my $ord = ord $c;
		if ($ord >= 32 and $ord <= 126) {
			#warn "ascii char $ord - no escaping\n";
			$out .= $c;
		} elsif ($esc{$ord}) {
			$out .= $esc{$ord};
		} else {
			#warn "special char $ord - escaping\n";
			$out .= sprintf('\\x%02x', $ord);
		}
	}
	return $out;
}

sub mylog($@) {
	my $fmt = shift;
	my ($s, $us)  = gettimeofday;
	printf '%s.%03d '.$fmt."\n", strftime('%H:%M:%S', localtime), $us/1000, @_;
}

sub lineread($) {
	local $SIG{ALRM} = sub {
		return;
	};
	my $term = shift;
	##$term->blocking(0);
	alarm 2;
	my $line = <$term>;
	#$term->blocking(1);
	return unless $line;
	#$line =~ s/[\r\n]//g;
	#return unless $line;
	return $line;
}

sub hexdump($) {
	return join(' ', map { sprintf '%02x', ord($_) } split //, shift);
}

my $port = shift || "/dev/ttyUSB0";

my $term = IO::Termios->open($port )
   or die "Cannot open $port: $!";
mylog "opened port %s", $port;

$term->setbaud(300);
$term->setcsize(7);
$term->setparity('e');
$term->setstop(1);
#$serial->handshake("none");

my $sel = IO::Select->new($term);

while (1) {
	my $t0 = [gettimeofday];
	$term->print("/?!\r\n");
	mylog "sent hello string";
	next unless scalar $sel->can_read(2);

	my $line = lineread($term);
	next unless $line;
	mylog "got reply: '%s' (%s)", escape($line), hexdump($line);

	$term->print(ACK."000\r\n");
	next unless scalar $sel->can_read(2);
	while ($line = lineread($term)) {
		mylog "data: '%s' (%s)", escape $line, hexdump($line);
	}
	my $elapsed = tv_interval($t0);
	if ($elapsed < $interval) {
		my $sleep = $interval - $elapsed;
		mylog "finished cycle (sleep %.1f)", $sleep;
		usleep $sleep;
	} else {
		mylog "finished cycle (%.3fs)", $elapsed;
	}

	#select(undef, undef, undef, 1);
}

