#!/usr/bin/perl -w

use POSIX qw(pause);
use Getopt::Std;
use Time::HiRes qw(setitimer ITIMER_REAL);
use Net::Telnet ();
use n8ur qw(trim);

# telnet info
$machine = 'femto.febo.com';
$port = '1299';

# how often do we trigger (seconds)?
my $interval = 30;

#-------------
my $adev_only = 0;
my $pn_only = 0;
my $summary_only = 0;
my $inputs_only = 0;
my $tables_only = 0;
my $wait_until = "";
my $basename = "";
my @lines = "";
my $tmp = 0;
my $minutes = 0;
my $wait_until_minutes = 0;
my $t;

# display usage
my $opt_string = 'haipstu:b:';

sub usage() {
print STDERR << "EOF";

usage: $0 [-h] [-apsi] [-u "timestring"] -b basename

-h      : this (help) message
-a      : get only ADEV plots and tables
-p	: get only phase noise plots and tables
-s	: only print current state and exit
-i	: only print input info and exit
-t	: only capture data tables, no print
-u	: wait Until specified collection time (format Xd Yh, Xh Ym, Xm)
-b      : basename for output files

EOF
}

getopts( "$opt_string", \my %opt ) or usage() and exit;

# print usage
usage() and exit if $opt{h};
usage() and exit if ( (!$opt{i}) && (!$opt{s}) && (!$opt{b}) );

# set variables to command line params

if ($opt{a}) {
	$adev_only = 1;
}

if ($opt{p}) {
	$pn_only = 1;
}

if ($opt{s}) {
	$summary_only = 1;
}

if ($opt{i}) {
	$inputs_only = 1;
}

if ($opt{t}) {
	$tables_only = 1;
}

if ($opt{u}) {
	$wait_until = lc($opt{u});
}

if ($opt{b}) {
	$basename = $opt{b};
}

#------------------------------------------------------------------------------
# subroutines
#------------------------------------------------------------------------------

sub make_minutes($) {

my $instring = shift;
my $tmp = "";
my $var1 = "";
my $var2 = "";
my $days = 0;
my $hours = 0;
my $minutes = 0;
my $mult = 0;

($var1,$var2) = split(" ",trim(lc($instring)));

if ($var1) {
	if (index($var1,"d") > 0) {$mult = 1440;}
	if (index($var1,"h") > 0) {$mult = 60;}
	if (index($var1,"m") > 0) {$mult = 1;}
	chop($var1);
	$minutes += ($var1 * $mult);
}

if ($var2) {
	if (index($var2,"h") > 0) {$mult = 60;}
	if (index($var2,"m") > 0) {$mult = 1;}
	chop($var2);
	$minutes += ($var2 * $mult);
}
return $minutes;
}

#----------

sub get_state($) {

my $format = shift;
my @lines;
my $minutes = 0;

# doubling command is ugly way to make sure output is flushed
@lines = $t->cmd("show state");
@lines = $t->cmd("show state");

$tmp = substr($lines[0],index($lines[0],"\(")+1);
chop($tmp);
chop($tmp);

$minutes = make_minutes($tmp);

if ($format eq "raw") { return $tmp; } else { return $minutes; }
}

#----------
sub get_inputs() {

my @lines;

# doubling command is ugly way to make sure output is flushed
@lines = $t->cmd("show inputs");
@lines = $t->cmd("show inputs");

my @tmp = split(/ /,$lines[1]);
my $input_freq = $tmp[2];
my $input_ampl = $tmp[5];
my $input_scale = 1/($input_freq*1e6);

@tmp = split(/ /,$lines[2]);
my $ref_freq = $tmp[2];
my $ref_ampl = $tmp[5];

my $result = "Input: " . $input_freq . "MHz " . $input_ampl . 
	"dBm Reference: " . $ref_freq . "MHz " . $ref_ampl . "dBm";

return $result;
}

#----------

sub get_adev_table()  {
print "Getting ADEV table...\n";
my $j;
my $k;
my $current_tau;
my $tau_1ms_start;
my $tau_10ms_start;
my $tau_100ms_start;
my $tau_1000ms_start;
my $tau_1ms_stop;
my $tau_10ms_stop;
my $tau_100ms_stop;
my $tau_1000ms_stop;
my @tau_range;
my @tau_1ms;
my @tau_10ms;
my @tau_100ms;
my @tau_1000ms;
my $num_tau;

@lines = $t->cmd("show adev");

# scan to find where each tau0 begins, and where noise data starts
for ($j = 0; $j < @lines;$j++) {
	if (trim($lines[$j]) =~ "^TAU0: 1E-3") { $tau_1ms_start = $j; }
	if (trim($lines[$j]) =~ "^TAU0: 1E-2") { $tau_10ms_start = $j; }
	if (trim($lines[$j]) =~ "^TAU0: 1E-1") { $tau_100ms_start = $j; }
	if (trim($lines[$j]) =~ "^TAU0: 1E0") { $tau_1000ms_start = $j; }
	# initialize arrays
	$tau_range[$j] = 0;
	$tau_1ms[$j]  = 0;
	$tau_10ms[$j]  = 0;
	$tau_100ms[$j]  = 0;
	$tau_1000ms[$j]  = 0;
}
for ($j = $tau_1ms_start; $j < $tau_10ms_start;$j++) {
	if (trim($lines[$j]) =~ "^N") { $tau_1ms_stop = $j; }
}

for ($j = $tau_10ms_start; $j < $tau_100ms_start;$j++) {
	if (trim($lines[$j]) =~ "^N") { $tau_10ms_stop = $j; }
}

for ($j = $tau_100ms_start; $j < $tau_1000ms_start;$j++) {
	if (trim($lines[$j]) =~ "^N") { $tau_100ms_stop = $j; }
}

for ($j = $tau_1000ms_start; $j < @lines;$j++) {
	if (trim($lines[$j]) =~ "^N") { $tau_1000ms_stop = $j; }
}

$k = 1;
for ($j = $tau_1ms_start+1; $j <= $tau_1ms_stop;$j++) {
	@tmp =  split(" ",$lines[$j]);
	$tau_range[$j] = $tmp[1];
	$tau_1ms[$k] = $tmp[3];
	$num_tau++;
	$k++;
}

$k = 4;
for ($j = $tau_10ms_start+1; $j <= $tau_10ms_stop; $j++) {
	@tmp =  split(" ",$lines[$j]);
	$tau_10ms[$k] = $tmp[3];
	$k++;
	}

$k = 7;
for ($j = $tau_100ms_start+1; $j <= $tau_100ms_stop; $j++) {
	@tmp =  split(" ",$lines[$j]);
	$tau_100ms[$k] = $tmp[3];
	$k++;
        }

$k = 10;
for ($j = $tau_1000ms_start+1; $j <= $tau_1000ms_stop; $j++) {
	@tmp =  split(" ",$lines[$j]);
	$tau_1000ms[$k] = $tmp[3];
	$k++;
        }

open (LOG, ">$basename-adev.dat") || die "Can't open $basename-adev.dat!\n";
for ($j = 1; $j < $num_tau; $j++) {
	print LOG $tau_range[$j]," ",$tau_1ms[$j]," ",$tau_10ms[$j]," ",
		$tau_100ms[$j]," ",$tau_1000ms[$j],"\n";
        }
close LOG;
}

#----------

sub get_pn_table() {
print "Getting phase noise tables...\n";
open (LOG, ">$basename-spectrum.dat") || die "Can't open $basename-spectrum.dat!\n";
@lines = $t->cmd("show spectrum");

# There's a blank line before the noise floor data
for ($j = 2; $j < @lines-1; $j++) {
	if (trim($lines[$j]) =~ "^Noise") {$lastline = $j; }
}
for ($j = 3; $j < ($lastline - 1); $j++) {
	print LOG $lines[$j];
}
close LOG;

# Get spur data
open (LOG, ">$basename-spurs.dat") || die "Can't open $basename-spurs.dat!\n";
@lines = $t->cmd("show spurs");
# swallow prompt at end
for ($j = 2; $j < @lines-1; $j++) {
	print LOG $lines[$j];
}
close LOG;
}

sub get_freqdiff_table() {
print "Getting frequency difference table...\n";
open (LOG, ">$basename-freqdiff.dat") || die "Can't open $basename-freqdiff.dat!\n";
@lines = $t->cmd("show freqdiff");
for ($j = 1; $j < ($#lines); $j++) {
	print LOG $lines[$j];
}
close LOG;
}

sub get_phasediff_table() {
print "Getting phase difference table...\n";
open (LOG, ">$basename-phasediff.dat") || die "Can't open $basename-phasediff.dat!\n";
@lines = $t->cmd("show phasediff");
for ($j = 1; $j < ($#lines); $j++) {
	print LOG $lines[$j];
}
close LOG;
}

#----------

sub get_adev_plot() {
print "Getting ADEV plot...\n";
system "nc -l -p 9100 > $basename-adev.ps &";
sleep 1;
$t->print("print adevplot adevtable");
$t->waitfor("/=192.168.1.248 >/");
sleep 3;
print "Converting to PNGs...\n";
system "psselect 1 $basename-adev.ps | convert -black-threshold 99.9% -density 295.5 - -rotate 90 -resize 20% -unsharp 0.5x0.5+2.0+0.10 $basename-adevplot.png";
system "psselect 2 $basename-adev.ps | convert -black-threshold 99.9% -density 295.5 - -resize 20% -unsharp 0.5x0.5+2.0+0.10 $basename-adevtable.png";

print "Converting to PDF...\n";
system "convert $basename-adev.ps $basename-adev.pdf";
}

#----------

sub get_pn_plot() {
print "Getting phase noise plot...\n";
	
system "nc -l -p 9100 > $basename-pn.ps &";
sleep 1;
$t->print("print spectplot");
$t->waitfor("/=192.168.1.248 >/");
sleep 3;
print "Converting to PNGs...\n";
system "psselect 1 $basename-pn.ps | convert -black-threshold 99.9% -density 295.5 - -rotate 90 -resize 20% -unsharp 0.5x0.5+2.0+0.10 $basename-spectrumplot.png";

print "Converting to PDF...\n";
system "convert $basename-pn.ps $basename-pn.pdf";
}

#----------

sub get_all_plots() {
print "Getting all plots...\n";
system "nc -l -p 9100 > $basename.ps &";
sleep 1;
$t->print("print adevplot adevtable phasediff freqdiff fcounter spectplot");
$t->waitfor("/=192.168.1.248 >/");
sleep 3;
print "Converting to PNGs...\n";
system "psselect 1 $basename.ps | convert -black-threshold 99.9% -density 295.5 - -rotate 90 -resize 20% -unsharp 0.5x0.5+2.0+0.10 $basename-adevplot.png";
system "psselect 2 $basename.ps | convert -black-threshold 99.9% -density 295.5 - -resize 20% -unsharp 0.5x0.5+2.0+0.10 $basename-adevtable.png";
system "psselect 3 $basename.ps | convert -black-threshold 99.9% -density 295.5 - -rotate 90 -resize 20% -unsharp 0.5x0.5+2.0+0.10 $basename-phasediff.png";
system "psselect 4 $basename.ps | convert -black-threshold 99.9% -density 295.5 - -rotate 90 -resize 20% -unsharp 0.5x0.5+2.0+0.10 $basename-freqdiff.png";
system "psselect 5 $basename.ps | convert -black-threshold 99.9% -density 295.5 - -resize 20% -unsharp 0.5x0.5+2.0+0.10 $basename-freqcounter.png";
system "psselect 6 $basename.ps | convert -black-threshold 99.9% -density 295.5 - -rotate 90 -resize 20% -unsharp 0.5x0.5+2.0+0.10 $basename-spectrumplot.png";

print "Converting to PDF...\n";
system "convert $basename.ps $basename.pdf";
}

# signal handler is empty
$SIG{ALRM} = sub { };

#------------------------------------------------------------------------------
# end of subroutines
#------------------------------------------------------------------------------

#set output unbuffered so progress dots show up
select(STDOUT), $| = 1;

# open TSC-5120
$t = new Net::Telnet (Timeout => 10,Port=>$port);
$t->open($machine);
if ( (!$inputs_only) && (!$summary_only) ) { print "TSC-5120A opened...\n\n"; }

# get current collection time for use later
$tmp = get_state("raw");
$minutes = get_state("min");

print get_inputs(),"\n"; 
print "Collection time: $tmp ($minutes minutes)\n";
if ( ($summary_only) && (!$inputs_only) ) { exit(0); }

if ($inputs_only) { exit(0); }

print "Output file basename: $basename\n";

if ($wait_until) {
	$wait_until_minutes = make_minutes($wait_until);
      	print "\nWaiting until $wait_until ($wait_until_minutes minutes) reached\n";
	setitimer(ITIMER_REAL, 1, $interval);
}

while (1) {
# wait for alarm from timer
	if ($wait_until) {
		pause;
	}
	# Get state
	$tmp = get_state("raw");
	$minutes = get_state("min");
	if ($minutes >= $wait_until_minutes) {
		print "\nProcessing after collecting for $tmp ($minutes minutes)\n";
		if ($adev_only) {
			get_adev_table();
			if (!$tables_only) {
				get_adev_plot();
			}
       		} else {
			if ($pn_only) {
				get_pn_table();
				if (!$tables_only) {
				get_pn_plot();
				}
				} else {
					get_adev_table();
					get_pn_table();
					get_freqdiff_table();
					get_phasediff_table();
					if (!$tables_only) {
						get_all_plots();	
					}
				}
		}	

	print "Zipping it all up...\n";
	if ($adev_only) {
	       	system "zip $basename-adev.zip $basename* > /dev/null";
	}
	if ($pn_only) { system "zip $basename-pn.zip $basename* > /dev/null"; }
	if ( (!$adev_only) && (!$pn_only)  ) {
		system "zip $basename.zip $basename* > /dev/null";
	}

	$t->print("exit");
	$t->close;
	print "TSC-5120 closed...\n";
	exit(0);
	} else { print "."; }

}

$t->print("exit");
$t->close;
print "TSC-5120 closed after failure...\n";
exit(1);
