#!/usr/bin/perl -w
use strict;
use FindBin;
use lib "$FindBin::Bin/lib";

use Tk;

use Joystick;
use Control;
use Servo;

use EFIS::AI;
use EFIS::Needle;

my $version = q$Id: gs,v 1.10 2001/11/10 00:43:33 tramm Exp $;

my $config_file	= shift || 'config-60';
my $curve_size	= 128;
my $ai_size	= 128;


my $mw = MainWindow->new(
	-title		=> 'Control Curve editor',
) or die "Unable to open window on display $ENV{DISPLAY}\n";

my $js = Joystick->new(
) or warn "Unable to open joystick: $!\n";

my $servo	= Servo->new( 0, "/dev/ttyS0" );

$mw->fileevent(
	$js->{dev},
	readable	=> sub { $js->update }
) if $js;

$mw->fileevent(
	$servo->{device},
	readable	=> sub { efis_update( $servo->{device} ) },
) if $servo;

Control->joystick( $js ) if $js;


#
# Read in the configuration file and draw the controls
# on their own tab.
#
my $f = $mw->Frame(
)->pack(
	-side		=> 'top',
	-expand		=> 1,
	-fill		=> 'x',
);

my $controls = do $config_file
	or die "Config file parsing failed: $@\n";

$_->draw(
	$f,
	$curve_size,
	$curve_size
)->pack(
	-side		=> 'left',
)
	for @$controls;


#
# Button 5 is the engine KILL.  The throttle goes to zero and
# stays there.
#
$js->watch_button( 5, sub {
	my $js		= shift;
	my $value	= shift;

	Control->by_name( 'Throttle' )->{servo}->set( -128 );
} ) if $js;

#
# Button 1 (the trigger) is the reset to level.
#
$js->watch_button( 0, sub {
	my $reset = chr(0xFC) . chr(0x00) . chr(0x00);
	syswrite $servo->{device}, $reset;
} ) if $js;

#
# Random instruments go on the bottom of the display
#
$f = $mw->Frame(
)->pack(
	-side		=> 'top',
	-expand		=> '1',
	-fill		=> 'x',
);


#
# Needle gauges for engine and rotor tach
# from the realtime system.
#
my ($n1,$n2) = (30,50);
my $tach = $f->Needle( 
	-width		=> $ai_size,
	-label0		=> 'N1',
	-label1		=> 'N2',
)->pack(
	-side		=> 'left',
);

$tach->set( 0 => $n1 );
$tach->set( 1 => $n2 );

for my $axis (qw/0 1/)
{
	$js->watch_axis( $axis => sub {
		my $js		= shift;
		my $value	= shift;

		$tach->set( $axis, (32768 + $value) * 100 / 65536 );
	} ) if $js;
}

#
# Temp gauages are also provided by the realtime
#
my ($cht,$egt) = (0, 0);
my $temp_gauge = $f->Needle(
	-width		=> $ai_size,
	-label0		=>'CHT',
	-label1		=>'EGT',
	-ranges		=> [
		gold		=>  20,
		blue		=>  80,
		gold		=>  90,
		red		=> 100,
	],
)->pack(
	-side		=> 'left',
);

$temp_gauge->set( 0 => $cht );
$temp_gauge->set( 1 => $egt );

#
# Needle gauges for the fuel and voltage levels
# also provided by the realtime system
#
my ($volts,$fuel) = (100,100);
my $fuel_gauge = $f->Needle(
	-width		=> $ai_size,
	-label0		=> 'Volts',
	-label1		=> 'Fuel',
	-ranges		=> [
		red		=> 20,
		gold		=> 50,
		blue		=> 90,
		green		=> 100,
		
	],
)->pack(
	-side		=> 'left',
);

$fuel_gauge->set( 0 => $volts );
$fuel_gauge->set( 1 => $fuel );


#
# EFIS update from the realtime system
#
my ($roll,$pitch,$yaw) = (0) x 3;
my ($roll_hex,$pitch_hex,$yaw_hex) = (0x0000) x 3;
my ($roll_scale,$pitch_scale,$yaw_scale) = (8) x 3;

my $ai = $f->Attitude(
	-width		=> $ai_size,
	-height		=> $ai_size,
)->pack(
	-side		=> 'left',
);

for(
	[ Roll		=> \$roll	],
	[ Pitch		=> \$pitch	],
	[ Yaw		=> \$yaw	],
	[ Hex_Roll	=> \$roll_hex	],
	[ Hex_Pitch	=> \$pitch_hex	],
	[ Hex_Yaw	=> \$yaw_hex	],
) {
	my ($label,$var) = @$_;
	my $f = $f->Frame(
		-border		=> 2,
		-relief		=> 'sunken',
	)->pack(
		-side		=> 'top',
		-anchor		=> 'w',
		-expand		=> 0,
		-fill		=> 'x',
	);

	$f->Label(
		-text		=> "$label:",
		-justify	=> 'left',
		-anchor		=> 'w',
		-width		=> 10,
	)->pack(
		-side		=> 'left',
		-anchor		=> 'w',
	);

	$f->Label(
		-textvariable	=> $var,
		-justify	=> 'right',
		-anchor		=> 'e',
		-width		=> 8,
	)->pack(
		-side		=> 'right',
		-anchor		=> 'e',
	);
}

sub int16
{
	my $value	= hex shift;
	return $value - 0xFFFF
		if $value > 0x8000;
	return $value;
}

sub efis_update
{
	my $dev		= shift;
	local $_	= <$dev>;

	print "efis updating: $_";

	my %values = (
		/([A-Z])=?([0-9a-f]+)/g
	) or return;

	if( exists $values{R} )
	{
		$roll	= int16($values{R}) / $roll_scale;
		$ai->set_roll( $roll );
	}

	if( exists $values{P} )
	{
		$pitch	= int16($values{P}) / $pitch_scale;
		$ai->set_pitch( $pitch );
	}

	if( exists $values{H} )
	{
		$yaw	= int16($values{H}) / $yaw_scale;
		#$efis->set_yaw( $yaw );
	}

	if( exists $values{C} )
	{
		my $cht = hex($values{C}) * 100 / 256;
		$temp_gauge->set( 0 => int $cht );
	}

	if( exists $values{E} )
	{
		my $egt = hex($values{E}) * 100 / 256;
		$temp_gauge->set( 1 => int $egt );
	}

	$_ = sprintf "%.2f", $_ for $roll, $pitch, $yaw;
}

#
# Draw the rest of the interface
#
$f = $mw->Frame(
)->pack(
	-side		=> 'top',
	-fill		=> 'x',
	-expand		=> 1,
);

$f->Button(
	-text		=> 'Exit',
	-command	=> sub { $mw->destroy },
)->pack(
	-side		=> 'top',
	-expand		=> 1,
	-fill		=> 'x',
);


$mw->MainLoop;
__END__
