#!/usr/bin/perl -w
#
# 5334a.pl
# version 0.8 -- 26 March 2005
#
# Record time interval readings from HP 5334a counters
# 
# Copyright 2005 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 $device = "hp5334a"; # number is attached in the options section

# 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:hgc:t:f:z:';

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

usage: $0 -c [-a samples] [-z a|b|ab] [-h] [t iso|mjd] -f logfile

-a	: samples to average (each sample is 100 gate time counter average)
-c	: counter number
-t	: timestamp format: iso or mjd (default is mjd)
-z	: 50 ohm termination for channel a, b, or ab
-g	: test for bad GPS values (50ns threshold)
-h	: this (help) message
-f	: logfile using full pathname;
	  for output to console, use "-f -"

EOF
}

# main loop
#----------

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

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

# set variables to command line params
my $logfile;
my $errfile;
$logfile = $opt{f};
if ($logfile ne "-") {
	$errfile = $logfile . "-error";
	}
else {
	$errfile = "-";
	}

my $samples = 1;
if ($opt{a}) {
	$samples = $opt{a};
	}

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

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

my $gps = 0;
if ($opt{g}) {
	$gps = 1;
	}

$device = $device . $opt{c};

#----------
# initialize variables
my $result;
my $sum;
my $counter;
my $time_int;
my $last_time_int;
my $command;
my $gpib_status;
my $last_good;
my $first;

#----------
# set up logfile ; use non-buffered since log rate is slow
open (LOG, ">>$logfile") || die "Can't open logfile $logfile!\n";
select(LOG), $| = 1;
if ($gps) {
	open (ERROR, ">>$errfile") || die "Can't open error file $errfile!\n";
	select(ERROR), $| = 1;
	}


#----------
# initialize counter
my $brd = LinuxGpib::ibfind($board);
my $dev = LinuxGpib::ibfind($device);
# clear
LinuxGpib::ibclr($dev);
# set up
# initialize, time interval, auto trigger off, wait to be addressed, SRQ mask 1
$command = "INFN5AU0WA1SM1";
LinuxGpib::ibwrt($dev,$command,length($command));
usleep(10000);
# GV1 to do 100 gate averaging
$command = "GV1";
LinuxGpib::ibwrt($dev,$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($dev,$command,length($command));
	usleep(10000);
	}

#----------
# write header line
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 $device.  Average by ",$samples*100,
	", phase values in seconds.\n";
if ($gps) {
	printf ERROR "# Run started at %s (MJD %11.6F).\n",
		$current_iso,$current_mjd;
	print ERROR "# Error data from $device.  Average by ",$samples*100,
	", phase values in seconds.\n";
	}

#----------
# main loop
$counter = 1;
$last_time_int = 0;
$last_good = 0;
$first = 1;

while (1) {

	if (checkSRQ($brd)) {
		if (!$result) {
			$result = substr(squash(trim(serviceSRQ($dev))),1);
		}
	}
	
	if ($result) {
		$sum += $result;
		if ($counter == $samples) {
			$time_int = $sum/$samples;
			#avoid identical phase by adding a tiny bit
			if ($time_int == $last_time_int) {
				$time_int = $time_int + 1e-15;
				}
			# if $gps is set and more than 50ns between
			# current and last good reading, ignore
			if (!$gps) {
				print LOG logline($tag,9,$time_int);
				}
			else {
			if ($first || (abs($time_int-$last_good) < 50e-9)) {
					print LOG logline($tag,9,$time_int);
					$last_good = $time_int;
					}
				else {
					print ERROR logline($tag,9,$time_int);
					}
			}
			$sum = 0;
			$counter = 0;
			$first = 0;
			$last_time_int = $time_int;
		}
		$counter++;
		$result = 0;
			
	}
	usleep(100000);
}

#----------
# handle signals and errors -- mainly to clear lockfile on termination
sub sig_handler {
	sleep 2;
	close LOG;
	close ERROR;
	# initialize, time interval
	$command = "INFN5";
	LinuxGpib::ibwrt($dev,$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($dev,$command,length($command));
		usleep(10000);
	}
	exit(0);
}
#----------
exit(0);
