#!/usr/bin/perl
use warnings;
use strict;
use autodie;

package gpio;

use Data::Dump qw(dump);

my @last;
my $mode;

my $bcm_desc;
foreach my $pin_file ( glob 'pins/bcm-*.tsv' ) {
	open(my $fh, '<', $pin_file);
	while(<$fh>) {
		chomp;
		my ($pin,$desc) = split(/\t+/,$_,2);
		$bcm_desc->{$pin} = $desc;
	}
	close($fh);
	warn "# $pin_file ",dump($bcm_desc);
}

sub add_bcm_desc {
	my ( $pin, $desc ) = @_;
	$bcm_desc->{$pin} = $desc;
}

sub pins {

my @pcf = `gpio -x pcf8591:120:0x48 readall`;
my @gpio = `gpio -g readall`;
my $i = 0;

foreach (@gpio) {
	chomp;
#	next unless /\d\s/;

	# kill wiringpi mapping columns
	s/^(.{8}).{6}/$1/;
	s/.{6}(.{8})$/$1/;

	s/([ \d]{2})(...GPIO.)../$1$2$1/;
	s/(GPIO.)..(...)(\s*\d+)/$1$3$2$3/;

	my $line = substr($_,0,29) . '  ' . substr($_,39);
	if ( my $add = shift @pcf ) {
		$line .= '  ' . $add;
	}

	chomp $line;
	my @l = split(/\|/, $line);
	my @o = split(/\|/, $last[$i] || '');

	if ( $#l >= 9 ) {
		no warnings;

		$l[2] = sprintf "%-" . length($l[2]) . 's', ($bcm_desc->{ $1 }||$l[2]) if $l[1] =~ m/(\d+)/;
		$l[8] = sprintf "%"  . length($l[8]) . 's', ($bcm_desc->{ $1 }||$l[8]) if $l[9] =~ m/(\d+)/;

		$mode->{ $l[1]  } = [ $l[4] + 0, $l[2], $l[3] ];
		$mode->{ $l[9]  } = [ $l[6] + 0, $l[8], $l[7] ];
		$mode->{ $l[11] } = [ $l[12], $l[13] ] if $l[13];
		#warn "## l = ",dump(@l) if $i > 2 && $i < 5;
	}


	$line = join('|', @l);
	$line .= "|" unless $line =~ m/\+$/;


	if ( $last[$i] && $line ne $last[$i] ) {
		$last[$i] = $line; # save before highlight
		foreach my $i ( 0 .. $#l ) {
			$l[$i] = "\e[33;7;1m$l[$i]\e[0m" if $l[$i] ne $o[$i];
		}
		$line = join('|', @l);
		$line .= "|" unless $line =~ m/\+$/;
	} else {
		$last[$i] = $line;
	}


	$i++;

	# re-create from modified data
	print "$line\n";

}

#warn "# mode = ", dump($mode);

} #/gpio

sub pin2dir {
	my $pin = shift;
	my ($p) = grep { /$pin/ } keys %$mode;
warn dump($p);
	my $dir = $mode->{ $p }->[2];
	warn "# pin2dir $pin = $dir\n";
	return $dir;
}

sub cmd {
	my $cmd = shift;
	chomp $cmd;
	if ( $cmd =~ m/^(\d+)$/ ) {
		my $pin = $1;
		system "gpio -g mode $pin out" unless pin2dir($pin) =~ m/OUT/i;

		my $v = `gpio -g read $pin`;
		warn "# pin $pin ", $v;
		$v ^= 1;
		system "gpio -g write $pin $v";
	} elsif ( $cmd =~ m/^gpio\s+(.+)/ ) {
		system "gpio -g $1";
	}
}

package main;

return 1 if caller; # used as module

while(1) {
	gpio::pins();
	my $cmd = <STDIN>;
	gpio::cmd($cmd);
}

