#!/usr/bin/perl -w
#
# 5334plotter.pl
# version 0.91 -- 25 January 2015
#
# Record time interval readings from HP 5334a counter
# Set switches, take one reading, then exit
# 
# Configured for 10 DUT inputs and 4 REF inputs
#
# Copyright 2015 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 $brd;
my $device1 = "hp5334a";
my $dev1;
my $device2 = "switch_1";
my $dev2;
my $device3 = "switch_2";
my $dev3;

my $sw1 = "";
my $sw1a = "";
my $sw1b = "";
my $sw2 = "";
my $sw2a = "";
my $sw2b = "";
my $dut = "";
my $ref = "";
my $logfile;
my $result;
my $command;
my $count;

# there's got to be a better way!
$SIG{'HUP'} = 'sig_handler';
$SIG{'INT'} = 'sig_handler';
$SIG{'KILL'} = 'sig_handler';
#$SIG{'REF'} = 'sig_handler';
$SIG{'TERM'} = 'sig_handler';

#----------
# display usage
my $opt_string = 'vhwa:b:c:t:z:f:';

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

usage: $0 [-v] [-z a|b|ab] [-h] [-t iso|mjd] [-w] [-c comment ]
       -a ch -b ch -f logfile

-a	 : start channel (1 - 10)
-b	 : stop channel (1 - 4)
-c	 : comment for logfile header
-f 	 : logfile using full pathname; for output to console, use "-f -"
-h	 : this (help) message
-t	 : timestamp format: iso or mjd (default is mjd)
-v	 : aVerage for 100 readings
-w	 : wrap if reading > 500ms (take reciprocal)
-z	 : 50 ohm termination for channel a, b, or ab

EOF
}

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

$logfile = $opt{f};

# Input A, start signal
my $a = 1;
if ($opt{a}) { $a = $opt{a}; }
usage() and exit if ($a > 10);

# Input B, stop signal
my $b = 1;
if ($opt{b}) { $b = $opt{b}; }
usage() and exit if ($b > 4);

# average
my $v = 0;
my $avg = "off";
if ($opt{v}) {
	$v = 1;
	$avg = "on";
	}

# wrap
my $w = 0;
if ($opt{w}) {
	$w = 1;
	}

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

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

my $comment = "";
if ($opt{c}) { $comment = $opt{c}; }

#----------
sub log_open {
# set up logfile ; use non-buffered since log rate is slow
if (-e $logfile) {
	open (LOG, ">>$logfile") || die "Can't open logfile $logfile!\n";
} else {
	open (LOG, ">$logfile") || die "Can't create logfile $logfile!\n";
	my $dt = DateTime->now;
	my $current_iso = $dt->ymd('-') . 'T' . $dt->hms(':');
	my $current_mjd = $dt->mjd;
	printf LOG "# Run started at %s (MJD %11.6F).\n",
		$current_iso,$current_mjd;
	print LOG "# Data from $device1.";
	print LOG " 100 gate averaging $avg, phase values in seconds.\n";
	print LOG "# Start channel ",$a," ($dut).  Stop channel ",$b," ($ref).\n";
	if ($comment) { print LOG "# ",$comment,"\n"; }
	}
select(LOG), $| = 1;
}

#----------
sub device_init {
# initialize
$brd = LinuxGpib::ibfind($board);
$dev1 = LinuxGpib::ibfind($device1);
$dev2 = LinuxGpib::ibfind($device2);
$dev3 = LinuxGpib::ibfind($device3);

# clear
LinuxGpib::ibclr($dev1);
usleep(100);
LinuxGpib::ibclr($dev2);
usleep(100);
LinuxGpib::ibclr($dev3);
usleep(100);
}

sub counter_init {
# time interval, auto trigger off, wait to be addressed, SRQ mask 1,reset
$command = "INFN5AU0WA1SM1RE";
LinuxGpib::ibwrt($dev1,$command,length($command));
usleep(100);

# GV1 to do 100 gate averaging
$command = "GV0";
if ($v) {
	$command = "GV1";
}
LinuxGpib::ibwrt($dev1,$command,length($command));
usleep(100);

# 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(100);
	}

}
#----------
sub set_switch {

# Switch position (for both A and B) is:
# 1A1 feeds 1B; 1A2 feeds 2A for DUTs; 1A3 and 1A4 are DUTs;  2B is for REFs

	DUT: {
		$a == 1 && do { $sw1a = "A1" ; $sw1b = "B1" ; last DUT; };
		$a == 2 && do { $sw1a = "A1" ; $sw1b = "B2" ; last DUT; };
		$a == 3 && do { $sw1a = "A1" ; $sw1b = "B3" ; last DUT; };
		$a == 4 && do { $sw1a = "A1" ; $sw1b = "B4" ; last DUT; };
		$a == 5 && do { $sw1a = "A2" ; $sw2a = "A1" ; last DUT; };
		$a == 6 && do { $sw1a = "A2" ; $sw2a = "A2" ; last DUT; };
		$a == 7 && do { $sw1a = "A2" ; $sw2a = "A3" ; last DUT; };
		$a == 8 && do { $sw1a = "A2" ; $sw2a = "A4" ; last DUT; };
		$a == 9 && do { $sw1a = "A3" ; last DUT; };
		$a == 10 && do { $sw1a = "A4" ; last DUT; };
}

	REF: {
		$b == 1 && do { $sw2b = "B1" ; last REF; };
		$b == 2 && do { $sw2b = "B2" ; last REF; };
		$b == 3 && do { $sw2b = "B3" ; last REF; };
		$b == 4 && do { $sw2b = "B4" ; last REF; };
}

	if ($a >= 1 and $a <= 4) { $dut = 1 . $sw1a . "-" . 1 . $sw1b; };
	if ($a >= 5 and $a <= 8) { $dut = 1 . $sw1a . "-" . 2 . $sw2a; };
	if ($a >= 9) { $dut = 1 . $sw1a; };
	$ref = 2 . $sw2b;


	$command = $sw1a . $sw1b;
	LinuxGpib::ibwrt($dev2,$command,length($command));
	usleep(100);

	$command = $sw2a . $sw2b;
	LinuxGpib::ibwrt($dev3,$command,length($command));
	usleep(100);
}

#----------

# main loop

# init devices
device_init;

#set start and stop channel
set_switch;
usleep(100);

# get counter ready
counter_init;

$result = 0;
$count = 0;
while ((!$result) && ($count <= 100)) {
	# sleep a bit
	if ($v) { sleep 10; } else { usleep 20000; }
	if (checkSRQ($brd) && (!$result)) {
		$result = substr(squash(trim(serviceSRQ($dev1))),1);
		}
	$count++
	}

# 5334 can't deal with negative time interval.  Assume if reading is
# > 500 milliseconds, that it's really early and take reciprocal.
if ( ($w) && ($result > 0.5) ) {
	$result = 0.0 - (1.0 - $result) 
	};

log_open;

print LOG logline($tag,9,$result);

# return to local
LinuxGpib::ibloc($dev1);
usleep(100);
LinuxGpib::ibloc($dev2);
usleep(100);
LinuxGpib::ibloc($dev3);
usleep(100);

close LOG;
exit(0);
#---------
# handle signals and errors -- mainly to clear lockfile on termination
sub sig_handler {
	usleep(10000);
	close LOG;
	exit(0);
}

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