use Device::SerialPort;
my $port="/dev/ttyACM0";
my $baud=115200;

my $ser;


do_connect();
my $A;
my $waits = 0;

# drain input
DRAIN: while (1) {
	my $A = do_readline();
	if (!$A) {
		# input is non-blocking, so try again in a while
		if ($waits >= 10) {
			last DRAIN;
		}
		$waits++;
		msleep(100);
	} else {
		chomp $A;
		print "read:$A\n";
	}
}

my $commandno = 0;

LOOP: while ($A=<>) {
	chomp $A;
	$A =~ s/;.*$//g;
	$A =~ s/\(.*\)//g;
	$A =~ s/[ \t]//g;
	if ($A eq '') {
		next LOOP;
	}
	$commandno++;
RETRY:
	my $out = "N$commandno".$A;
	my $c = checksum($out);
	$out .= "*$c\n";
	print "wrote:$out";
	do_write($out);
	my $retry = 0;
	WAITOK: while (1) {
		my $B = do_readline();
		if (!$B) {
			msleep(10);
		} else {
			chomp $B;
			print "read:$B\n";
			if (($B.' ') =~ /last line: (\d+)[^\d]/i) {
				$commandno = 1+$1;
			}
			if ($B =~ /^ok/i) {
				if ($retry) {
					goto RETRY;
				}
				last WAITOK;
			} elsif ($B =~ /^resend:/i) {
				$retry = 1;
			} elsif ($B =~ /^error/i) {
				# XXX - consider dieing??
			}
		}
	}
}

sub do_connect {
	$ser = new Device::SerialPort($port) or die "could not open $port";
	$ser->baudrate($baud);
	$ser->databits(8);
	$ser->parity("none");
	$ser->stopbits(1);
	$ser->handshake("rts");
	$ser->read_const_time(10);
	$ser->write_settings() or die;
	# resetting
	$ser->dtr_active('F');
	sleep(1);
	$ser->dtr_active('T');
}

sub do_write {
	my ($str) = @_;
	WRITE: while (1) {
		my $t = $ser->write($str);
		if ($t >= length $str) {
			last WRITE;
		} elsif ($t <= 0) {
			die "couldn't write";
		} else {
			$str = substr $str, $t;
		}
	}
}

my $readline_queue = '';
sub do_readline {
	if ($readline_queue !~ /\n/s) {
		$readline_queue .= $ser->read(255);
	}
	if ($readline_queue =~ /^([^\n]*)\n(.*)$/s) {
		my ($first, $rest) = ($1,$2);
		$readline_queue = $rest;
		return $first;
	}
}

sub msleep {
	my ($s) = @_;
	select(undef, undef, undef, $s/1000);
}

sub checksum {
	my ($str) = @_;
	my $ret = 0;
	while ($str ne '') {
		my $first = substr $str, 0, 1;
		my $rest = substr $str, 1;
		$ret ^= ord $first;
		$str = $rest;
	}
	return $ret;
}
