#!/usr/bin/perl -w
#
# 5334a-single.pl
# version 0.8 -- 12 February 2006
#
# Record time interval readings from HP 5334a counter
# 
# Copyright 2006 by John R. Ackermann  N8UR (jra@febo.com)
#
# This program may be copied, modified, distributed and used for 
# any legal purpose provided that (a) the copyright notice above as well
# as these terms are retained on all copies; (b) any modifications that 
# correct bugs or errors, or increase the program's functionality, are 
# sent via email to the author at the address above; and (c) such 
# modifications are made subject to these license terms.

use strict;
use POSIX qw(setsid);
use Getopt::Std;
use Time::HiRes qw(usleep);
use LinuxGpib;
use DateTime;
use n8ur qw(lower_case trim squash collapse round);
use n8ur_gpib qw(checkSRQ serviceSRQ logline);

# device name from /etc/gpib.conf
my $board = "gpib0";
my $device1 = "hp5334a";
my $device2 = "switch1";

my $logfile1;
my $logfile2;
my $logfile3;
my $logfile4;
my $logfile5;
my $logfile6;

my $result;
my $command;
my $gpib_status;
my $switch;

# array elements are: sum, counter, time_int, last_time_int
my @channel1 = (0,1,0,0);
my @channel2 = (0,1,0,0);
my @channel3 = (0,1,0,0);
my @channel4 = (0,1,0,0);
my @channel5 = (0,1,0,0);
my @channel6 = (0,1,0,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';

#----------
# display usage
my $opt_string = 'a:ht:z:1:2:3:4:5:6:';

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

usage: $0 [-a tau] [-z a|b|ab] [-h] [-t iso|mjd]
	-1 ch1 logfile -2 ch2 logfile -3 ch3 logfile
	-4 ch4 logfile -5 ch5 logfile -6 ch6 logfile

-a	 : tau in seconds.  Minimum and increment is 100 for one channel,
	   200 for two channels, etc.
-t	 : timestamp format: iso or mjd (default is mjd)
-z	 : 50 ohm termination for channel a, b, or ab
-h	 : this (help) message
-1,2,3,4,5,6
	 : logfile using full pathname;
	   for output to console, use "-f -"

EOF
}

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

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

# set variables to command line params

my $channels = 1;
$logfile1 = $opt{1};

if ($opt{2}) {
	$logfile2 = $opt{2};
	$channels = 2;
	}

if ($opt{3}) {
	$logfile3 = $opt{3};
	$channels = 3;
	}
	
if ($opt{4}) {
	$logfile4 = $opt{4};
	$channels = 4;
	}
	
if ($opt{5}) {
	$logfile5 = $opt{5};
	$channels = 5;
	}
	
if ($opt{6}) {
	$logfile6 = $opt{6};
	$channels = 6;
	}
	
my $tau = $channels*100;
if ($opt{a}) {
	$tau = $opt{a};
	}

my $samples = $tau/($channels*100);

my $tag = "mjd";
if ($opt{t}) {
	$tag = trim(lower_case($opt{t}));
	}

my $term = "";
if ($opt{z}) {
	$term = trim(lower_case($opt{z}));
	}

#----------
# set up logfile ; use non-buffered since log rate is slow
open (LOG1, ">>$logfile1") || die "Can't open logfile $logfile1!\n";
select(LOG1), $| = 1;

if ($channels >= 2) {
	open (LOG2, ">>$logfile2") || die "Can't open logfile $logfile2!\n";
	select(LOG2), $| = 1;
	}

if ($channels >= 3) {
	open (LOG3, ">>$logfile3") || die "Can't open logfile $logfile3!\n";
	select(LOG3), $| = 1;
	}

if ($channels >= 4) {
	open (LOG4, ">>$logfile4") || die "Can't open logfile $logfile4!\n";
	select(LOG4), $| = 1;
	}

if ($channels >= 5) {
	open (LOG5, ">>$logfile5") || die "Can't open logfile $logfile5!\n";
	select(LOG5), $| = 1;
	}

if ($channels == 6) {
	open (LOG6, ">>$logfile6") || die "Can't open logfile $logfile6!\n";
	select(LOG6), $| = 1;
	}

#----------
# initialize counter
my $brd = LinuxGpib::ibfind($board);
my $dev1 = LinuxGpib::ibfind($device1);
my $dev2 = LinuxGpib::ibfind($device2);
# clear
LinuxGpib::ibclr($dev1);

# clear and set to listen
LinuxGpib::ibclr($dev2);
usleep(10000);
$command = "%";
LinuxGpib::ibwrt($dev2,$command,length($command));
usleep(10000);

# initialize, time interval, auto trigger off, wait to be addressed, SRQ mask 1
$command = "INFN5AU0WA1SM1";
LinuxGpib::ibwrt($dev1,$command,length($command));
usleep(10000);
# GV1 to do 100 gate averaging
$command = "GV1";
LinuxGpib::ibwrt($dev1,$command,length($command));
usleep(10000);

# set 50 ohm input
$command = "";
if ($term eq "a") {
	$command = "AZ1";
	}
if ($term eq "b") {
	$command = "BZ1";
	}
if ($term eq "ab") {
	$command = "AZ1BZ1";
	}
if ($command) {
	LinuxGpib::ibwrt($dev1,$command,length($command));
	usleep(10000);
	}

#----------
# Switch position (for both A and B) is:
# 1 -- CS1
# 2 -- CS2
# 3 -- RB1
# 4 -- GPS

sub flip_switch {
	my $command;

	if ($channels == 2) {                                 # command
		if ($switch eq "A1B4") { $command = "A2B4"; } # CS2 v GPS
		if ($switch eq "A2B4") { $command = "A1B4"; } # CS1 v GPS
		}

	if ($channels == 3) {
		if ($switch eq "A1B4") { $command = "A2B4"; } # CS2 v GPS
		if ($switch eq "A2B4") { $command = "A3B4"; } # RB1 v GPS
		if ($switch eq "A3B4") { $command = "A1B4"; } # CS1 v GPS
		}

	if ($channels == 4) {
		if ($switch eq "A1B4") { $command = "A2B4"; } # CS2 v GPS
		if ($switch eq "A2B4") { $command = "A3B4"; } # RB1 v GPS
		if ($switch eq "A3B4") { $command = "A2B1"; } # CS2 v CS1
		if ($switch eq "A2B1") { $command = "A1B4"; } # CS1 v GPS
		}

	if ($channels == 5) {
		if ($switch eq "A1B4") { $command = "A2B4"; } # CS2 v GPS
		if ($switch eq "A2B4") { $command = "A3B4"; } # RB1 v GPS
		if ($switch eq "A3B4") { $command = "A2B1"; } # CS2 v CS1
		if ($switch eq "A2B1") { $command = "A3B1"; } # RB1 v CS1
		if ($switch eq "A3B1") { $command = "A1B4"; } # CS1 v GPS
		}

	if ($channels == 6) {
		if ($switch eq "A1B4") { $command = "A2B4"; } # CS2 v GPS
		if ($switch eq "A2B4") { $command = "A3B4"; } # RB1 v GPS
		if ($switch eq "A3B4") { $command = "A2B1"; } # CS2 v CS1
		if ($switch eq "A2B1") { $command = "A3B1"; } # RB1 v CS1
		if ($switch eq "A3B1") { $command = "A3B2"; } # RB1 v CS2
		if ($switch eq "A3B2") { $command = "A1B4"; } # CS1 v GPS
		}

	if ($channels > 1) {
		$switch = $command;
		LinuxGpib::ibwrt($dev2,$command,length($command));
		usleep(10000);
		}
}

#----------
sub process_channel1 {
	$channel1[0] += $result;
	if ($channel1[1] == $samples) {
		$channel1[2] = $channel1[0]/$samples;
		#avoid identical phase by adding a tiny bit
		if ($channel1[2] == $channel1[3]) {
			$channel1[2] += 1e-15;
		}
		print LOG1 logline($tag,9,$channel1[2]);
		$channel1[0] = 0;
		$channel1[1] = 0;
		$channel1[3] = $channel1[2];
		$channel1[2] = 0;
	}
	$channel1[1]++;	
}

sub process_channel2 {
	$channel2[0] += $result;
	if ($channel2[1] == $samples) {
		$channel2[2] = $channel2[0]/$samples;
		#avoid identical phase by adding a tiny bit
		if ($channel2[2] == $channel2[3]) {
			$channel2[2] += 1e-15;
		}
		print LOG2 logline($tag,9,$channel2[2]);
		$channel2[0] = 0;
		$channel2[1] = 0;
		$channel2[3] = $channel2[2];
		$channel2[2] = 0;
	}
	$channel2[1]++;	
}

sub process_channel3 {
	$channel3[0] += $result;
	if ($channel3[1] == $samples) {
		$channel3[2] = $channel3[0]/$samples;
		#avoid identical phase by adding a tiny bit
		if ($channel3[2] == $channel3[3]) {
			$channel3[2] += 1e-15;
		}
		print LOG3 logline($tag,9,$channel3[2]);
		$channel3[0] = 0;
		$channel3[1] = 0;
		$channel3[3] = $channel3[2];
		$channel3[2] = 0;
	}
	$channel3[1]++;	
}

sub process_channel4 {
	$channel4[0] += $result;
	if ($channel4[1] == $samples) {
		$channel4[2] = $channel4[0]/$samples;
		#avoid identical phase by adding a tiny bit
		if ($channel4[2] == $channel4[3]) {
			$channel4[2] += 1e-15;
		}
		print LOG4 logline($tag,9,$channel4[2]);
		$channel4[0] = 0;
		$channel4[1] = 0;
		$channel4[3] = $channel4[2];
		$channel4[2] = 0;
	}
	$channel4[1]++;	
}

sub process_channel5 {
	$channel5[0] += $result;
	if ($channel5[1] == $samples) {
		$channel5[2] = $channel5[0]/$samples;
		#avoid identical phase by adding a tiny bit
		if ($channel5[2] == $channel5[3]) {
			$channel5[2] += 1e-15;
		}
		print LOG5 logline($tag,9,$channel5[2]);
		$channel5[0] = 0;
		$channel5[1] = 0;
		$channel5[3] = $channel5[2];
		$channel5[2] = 0;
	}
	$channel5[1]++;	
}

sub process_channel6 {
	$channel6[0] += $result;
	if ($channel6[1] == $samples) {
		$channel6[2] = $channel6[0]/$samples;
		#avoid identical phase by adding a tiny bit
		if ($channel6[2] == $channel6[3]) {
			$channel6[2] += 1e-15;
		}
		print LOG6 logline($tag,9,$channel6[2]);
		$channel6[0] = 0;
		$channel6[1] = 0;
		$channel6[3] = $channel6[2];
		$channel6[2] = 0;
	}
	$channel6[1]++;	
}



#----------

# write header line
my $dt = DateTime->now;
my $current_iso = $dt->ymd('-') . 'T' . $dt->hms(':');
my $current_mjd = $dt->mjd;
printf LOG1 "# Run started at %s (MJD %11.6F).\n",
	$current_iso,$current_mjd;
print LOG1 "# Data from $device1 (channel 1).  Tau = ",$tau,
	", phase values in seconds.\n";
if ($channels >= 2) {
	printf LOG2 "# Run started at %s (MJD %11.6F).\n",
		$current_iso,$current_mjd;
	print LOG2 "# Data from $device1 (channel 2).  Tau = ",$tau,
		", phase values in seconds.\n";
}

if ($channels >= 3) {
	printf LOG3 "# Run started at %s (MJD %11.6F).\n",
		$current_iso,$current_mjd;
	print LOG3 "# Data from $device1 (channel 3).  Tau = ",$tau,
		", phase values in seconds.\n";
}

if ($channels >= 4) {
	printf LOG4 "# Run started at %s (MJD %11.6F).\n",
		$current_iso,$current_mjd;
	print LOG4 "# Data from $device1 (channel 4).  Tau = ",$tau,
		", phase values in seconds.\n";
}

if ($channels >= 5) {
	printf LOG5 "# Run started at %s (MJD %11.6F).\n",
		$current_iso,$current_mjd;
	print LOG5 "# Data from $device1 (channel 5).  Tau = ",$tau,
		", phase values in seconds.\n";
}

if ($channels == 6) {
	printf LOG6 "# Run started at %s (MJD %11.6F).\n",
		$current_iso,$current_mjd;
	print LOG6 "# Data from $device1 (channel 6).  Tau = ",$tau,
		", phase values in seconds.\n";
}
#----------
# set switch to state 1
$switch ="A1B4";
$command = $switch;
LinuxGpib::ibwrt($dev2,$command,length($command));
usleep(10000);

#----------
# main loop
while (1) {
	if (checkSRQ($brd) && (!$result)) {
		$result = substr(squash(trim(serviceSRQ($dev1))),1);
	}
	
	if ($result) {
		if ($switch eq "A1B4") { process_channel1; }
		if ($switch eq "A2B4") { process_channel2; }
		if ($switch eq "A3B4") { process_channel3; }
		if ($switch eq "A2B1") { process_channel4; }
		if ($switch eq "A3B1") { process_channel5; }
		if ($switch eq "A3B2") { process_channel6; }
		flip_switch;
		$result = 0;
	}
	usleep(100000);
}

#----------
# handle signals and errors -- mainly to clear lockfile on termination
sub sig_handler {
	sleep 2;
	close LOG1;
	close LOG2;
	# initialize, time interval
	$command = "INFN5";
	LinuxGpib::ibwrt($dev1,$command,length($command));
	usleep(10000);

	# set 50 ohm input if necessary; assumes auto trigger off
	$command = "";
	if ($term eq "a") {
		$command = "AU0AZ1";
	}
	if ($term eq "b") {
		$command = "AU0BZ1";
	}
	if ($term eq "ab") {
		$command = "AU0AZ1BZ1";
	}
	if ($command) {
		LinuxGpib::ibwrt($dev1,$command,length($command));
		usleep(10000);
	}
	exit(0);
}

#----------
exit(0);
