#!/usr/bin/perl -w

# VEMS Genboard protocol emulator
# Allows megatunix to communicate with 

# http://www.suspectclass.com/~sgifford/interceptty/interceptty.html
# usage:
# interceptty -q '!PATH_TO/emu_genboard.pl' /tmp/tty
# in megatunix specify the comm port to be /tmp/tty

use Switch;

$SIG{INT} = \&leave_int;

# number of elements in each row
# set this to the same number as VE_SIZE_RPM
$table_elements=8;

# read mtt files
foreach (@ARGV) { 
    parse_mtt($_);
    print STDERR "mtt file: '$_' read\n";
}

select(STDOUT);
$| = 1;

system "stty cbreak < /dev/tty > /dev/tty 2>&1";


# define size of pages

$rpm_size = 8;
$kpa_size = 8;

%page_length = ( 0 => 125, # used for B&G emulation
		 1 => 18, # used for B&G emulation
		 c => 249,
		 j => $rpm_size*$kpa_size,
		 n => $rpm_size*$kpa_size,
		 l => $rpm_size*$kpa_size,
		 r => $rpm_size,
		 k => $kpa_size,
		 h => 3*8,
		 );


$state = '0';
$page = 0;

while (1) {
    $c = getc;
    $valc = ord($c);

    switch ($state) {
	case '0' {
	    switch ($c) {
		case 'A' {
		    runtime();
		}
		case 'B' {
		    save_to_eeprom();
		}
		case 'C' { 
		    echo_byte(); # echo back 1 byte (system clock, seconds)
		}
		case 'Q' {
		    printf("%c", 30);  # echo back version (B&G)
		}
		case 'W' {
		    $state = "W1";
		}
		case 'V' {
		    send_page($page);
		}
		case 'P' {
		    $state = "P"; # then receive page number
		}
		case 'S' {
		    send_signature();  # <64 chars
		}
		case '?' {
		    send_signature_version();  # <64 chars
		}
		else {
		    my $chex = sprintf("%02x", $valc);
		    print STDERR "Unknown command '$c' (0x$chex)\n";
		}
	    }
	}
	case "W1" {
	    $tmp_byte = $valc;
	    $state = "W2";
	}
	case "W2" {
	    store_in_page($page, $tmp_byte, $valc);
	    $state = '0';
	}
	case "P" {
	    $page = $valc;
	    $state = '0';
	    print STDERR "Activated page: $page\n";
	}
	else {
	    print STDERR "The impossible state! '$c'\n";
	    $state = '0';
	}
    }
}


sub runtime {
    my $v = sprintf("%c", 50) x 22;
    print $v;
}

sub echo_byte {
    printf("%c", 1);
}

sub store_in_page {
    my ($page, $offset, $val) = @_;
    $pages[$page][$offset] = $val;
#    if ($page == 0) { 
#	$pages[ord('c')][$offset] = $val; # we're cheating a bit
#    }
    print STDERR "Write: page=$page, offset=$offset, val=$val\n";
}

sub send_page {
    my $page = shift;
#    if ($page == 0) { 
#	$page = ord('c');  # we're cheating a bit
#    }

    if (defined($page_length{$page})) {
	$plen = $page_length{$page};
    } else {
	$plen=0;
    }

    print STDERR sprintf("Requested p[%d] = {", $page);
    for (my $i=0; $i<$plen; $i++) {
	if (defined($pages[$page][$i])) {
	    printf("%c", $pages[$page][$i]);
	    print STDERR sprintf("%02x ", $pages[$page][$i]);
	} else {
	    printf("%c", 0);
	    print STDERR sprintf("%02x ", 0);
	}
    }
    print STDERR " }\n";
#    print STDERR "Requested page: $page\n";
}

sub send_signature {
    print "VEMS Genboard v3";
}

sub send_signature_version {
    print "x.y.z";
}


sub save_to_eeprom {
    # yeah right, lets save in a file instead
    print_pages();
}

# read mtt files and store in 'page' array
sub parse_mtt {
    my $fname = shift;
    open IF, "<$fname" or die "ERROR, could not open '$fname' for reading: $!";

    while ($l = <IF>) {
	if ($l =~ /^g(\w{2})(\w)(\w{2})/) {
	    my $offset = $1;
	    my $table = $2;
	    my $value = hex($3);

	    # offset is converted differently depending on the table
	    if ($table eq 'c') {
		$offset = hex($offset);
	    } else {
		my ($a, $b) = split //, $offset;
		$offset = $table_elements * $a + $b;
	    }

#	    print STDERR "$table $offset $value\n";
	    $pages[ord($table)][$offset] = $value;
	}
    }
    close IF;
}

# TODO, print the changes 
sub print_pages {
    print STDERR "Saved!\n";
}

sub leave_int {
    $SIG{INT} = \&leave_int;
    system "stty -cbreak < /dev/tty > /dev/tty 2>&1";
    exit;
}
