#!/usr/bin/perl -w

use POSIX qw(setsid pause);
use Getopt::Std;
use Time::HiRes qw(setitimer ITIMER_REAL time usleep);
use LinuxGpib;
use n8ur qw(trim squash collapse round);
use n8ur_gpib qw(checkSRQ serviceSRQ logline timetag);

#----------
my $tags = "mjd";
my $interval = 150;
my $num_avg = 20;

my $wwv1 = "2.5000MZ";
my $wwv2 = "5.000MZ";
my $wwv3 = "10.000MZ";

my $wwvlog = "/home/jra/wwv-2.dat";
#----------

# device name from /etc/gpib.conf
my $board = "gpib0";
my $device1 = "hp3586c_1";
my $device2 = "hp3586c_2";
my $device3 = "hp3586c_3";

my $brd;
my $dev1;
my $dev2;
my $dev3;
my $command;
my $gpib_status;
my $tmp;
my $count;
my $count1;
my $count2;
my $count3;
my $reading1;
my $reading2;
my $reading3;
my $tmp_amp1;
my $tmp_amp2;
my $tmp_amp3;
my $tmp_fr1;
my $tmp_fr2;
my $tmp_fr3;
my $fr1;
my $fr2;
my $fr3;
my $amp1;
my $amp2;
my $amp3;
my $valid1;
my $valid2;
my $valid3;
my $time;
my $lsst_wwv;
my $ibstatus;
my $loop_time;
my $min_time;
my $max_time;
my $total_loops;
my $sum_time;
my $avg_time;

#----------
# handle signals and errors -- mainly to clear lockfile on termination
sub sig_handler {
	sleep 2;
	close WWV;
	exit(0);
}

# there's got to be a better way!
$SIG{'HUP'} = 'sig_handler';
$SIG{'INT'} = 'sig_handler';
$SIG{'KILL'} = 'sig_handler';
$SIG{'STOP'} = 'sig_handler';
$SIG{'TERM'} = 'sig_handler';
#----------
$SIG{ALRM} = sub { };
#----------
# display usage
my $opt_string = 'h:f:';

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

usage: $0 [-h] [-a samples to average] [-g gate time] -f logfile

-h	: this (help) message
-f	: logfile using full pathname;
	  for output to console, use "-f -"

EOF
}

sub set_wwv {
	# set frequency, do a cal, do measure continue
	$command = "FR" . $wwv1 . ",CA1,MC";
	LinuxGpib::ibwrt($dev1,$command,length($command));
	usleep(500);
	$command = "FR" . $wwv2 . ",CA1,MC";
	LinuxGpib::ibwrt($dev2,$command,length($command));
	usleep(500);
	$command = "FR" . $wwv3 . "CA1,MC";
	LinuxGpib::ibwrt($dev3,$command,length($command));
}

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

# print usage
usage() and exit if $opt{h};
# usage() and exit if !$opt{f};

# set variables to command line params

setitimer(ITIMER_REAL, 10, $interval);

#----------
# set up logfile

open (WWV, ">>$wwvlog") ||
	die "Can't open logfile $wwvlog!\n";
# set nonbuffered mode
select(WWV), $| = 1;

#----------
# initialize
$dev1 = LinuxGpib::ibfind($device1);
$dev2 = LinuxGpib::ibfind($device2);
$dev3 = LinuxGpib::ibfind($device3);

# clear
LinuxGpib::ibclr($dev1);
LinuxGpib::ibclr($dev2);
LinuxGpib::ibclr($dev3);
sleep(2);

# set up
# Cal off, 50 ohm term, average off, 20 Hz bandwidth, counter on
$command = "CA0,T1,A0,B1,CN1";
LinuxGpib::ibwrt($dev1,$command,length($command));
usleep(500);
LinuxGpib::ibwrt($dev2,$command,length($command));
usleep(500);
LinuxGpib::ibwrt($dev3,$command,length($command));
usleep(500);

#----------

$total_loops = 0;
$first = 1;
$last_wwv = timetag($tags);
$loop_time = 0;
$min_time = 1e6;
$max_time = 0;

# write header line
 my $dt = DateTime->now;
 my $current_iso = $dt->ymd('-') . 'T' . $dt->hms(':');
 my $current_mjd = $dt->mjd;
 printf WWV "# Run started at %s (MJD %11.6F).",$current_iso,$current_mjd;
 print WWV "  Average by: $num_avg.\n";
 print WWV "# MJD, F1, A1, F2, A2, F3, A3, Tau, Loop Time\n";
#
# for timer output to be pretty
print STDOUT "\n";


while (1) {

set_wwv;

# wait for alarm from timer
pause;

$time = timetag($tags);
if (!$first) {
	print WWV $time," ",$fr1," ",$amp1," ",
 		$fr2," ",$amp2," ", $fr3," ",
		$amp3," ",
		round(0,($time-$last_wwv)*86400)," ",
		$loop_time,"\n";
}
$last_wwv = $time;

$count = 0;
$count1 = 0;
$count2 = 0;
$count3 = 0;
$tmp_amp1 = 0;
$tmp_amp2 = 0;
$tmp_amp3 = 0;
$amp1 = 0;
$amp2 = 0;
$amp3 = 0;
$tmp_fr1 = 0;
$tmp_fr2 = 0;
$tmp_fr3 = 0;
$fr1 = 0;
$fr2 = 0;
$fr3 = 0;

# allow new freq to settle
sleep(15);

while ($count < $num_avg) {

	$reading1 = "";
	$reading2 = "";
	$reading3 = "";

	$command = "TR";
	LinuxGpib::ibwrt($dev1,$command,length($command));
	usleep(5000);
	LinuxGpib::ibwrt($dev2,$command,length($command));
	usleep(5000);
	LinuxGpib::ibwrt($dev3,$command,length($command));
	sleep(3);

	$ibstatus = LinuxGpib::ibrd($dev1,$reading1,23);
	usleep(5000);
	$ibstatus = LinuxGpib::ibrd($dev2,$reading2,23);
	usleep(5000);
	$ibstatus = LinuxGpib::ibrd($dev3,$reading3,23);
	usleep(5000);

	# backup in case initial reading times out
	until ($reading1 =~ /^[NOU]/) {
		LinuxGpib::ibwrt($dev1,$command,length($command));
		sleep(2);
		$ibstatus = LinuxGpib::ibrd($dev1,$reading1,23);
	}	

	until ($reading2 =~ /^[NOU]/) {
		LinuxGpib::ibwrt($dev2,$command,length($command));
		sleep(2);
		$ibstatus = LinuxGpib::ibrd($dev2,$reading2,23);
	}	

	until ($reading3 =~ /^[NOU]/) {
		LinuxGpib::ibwrt($dev3,$command,length($command));
		sleep(2);
		$reading1 = "";
		$ibstatus = LinuxGpib::ibrd($dev3,$reading3,23);
	}	

	# process results
	if (length($reading1) > 20) { 
		$valid1 = substr($reading1,0,1);
		$tmp = trim(substr($reading1,1,8));
		if ($tmp != -999.999) { 
			$tmp_amp1 += $tmp;
			$tmp_fr1 += trim(substr($reading1,11));
			$count1++;
      		}
	}	

	if (length($reading2) > 20) { 
		$valid2 = substr($reading2,0,1);
		$tmp = trim(substr($reading2,1,8));
		if ($tmp != -999.999) { 
			$tmp_amp2 += $tmp;
			$tmp_fr2 += trim(substr($reading2,11));
			$count2++;
      		}
	}	

	if (length($reading3) > 20) { 
		$valid3 = substr($reading3,0,1);
		$tmp = trim(substr($reading3,1,8));
		if ($tmp != -999.999) { 
			$tmp_amp3 += $tmp;
			$tmp_fr3 += trim(substr($reading3,11));
			$count3++;
      		}
	}	

	$count++;	
}

if ($count1) {
	$fr1 = round(2,$tmp_fr1/$count1);
	$amp1 = sprintf("%.1f",round(1,($tmp_amp1/$count1)));
} else {
	$fr1 = 0;
	$amp1 = 0;
}

if ($count2) {
	$fr2 = round(2,$tmp_fr2/$count2);
	$amp2 = sprintf("%.1f",round(1,($tmp_amp2/$count2)));
} else {
	$fr2 = 0;
	$amp2 = 0;
}

if ($count3) {
	$fr3 = round(2,$tmp_fr3/$count3);
	$amp3 = sprintf("%.1f",round(1,($tmp_amp3/$count3)));
} else {
	$fr3 = 0;
	$amp3 = 0;
}

$total_loops++;
$timer2 = timetag($tags);
$loop_time = round(0,($timer2-$time)*86400);
$sum_time += $loop_time;
$avg_time = round(1,$sum_time/$total_loops);
if ($loop_time > $max_time) { $max_time = $loop_time; }
if ($loop_time < $min_time) { $min_time = $loop_time; }
print STDOUT "Loop time: $loop_time, min = $min_time, ";
print STDOUT "max = $max_time, average = $avg_time ";
print STDOUT "(total loops = $total_loops)\n";

$first = 0;
}

#----------

exit 0;
