#!/usr/bin/perl -w
##
## tsc-freq.pl -- get fcounter data from TSC-5120A
## version 1.0 -- 25 December 2009
##
## Copyright 2009 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 pause);
use Getopt::Std;
use Time::HiRes qw(usleep setitimer ITIMER_REAL);
use DateTime;
use n8ur qw(lower_case trim squash collapse round);
use n8ur_gpib qw(logline logline_tsc);
use Net::Telnet;

my $machine = '192.168.1.248';
my $port = '1299';

my $file;
my $t;
my @lines;
my $j;
my $k;
my @tmp;
my @reading;
my @actual = ["","","",""];
my @frac = ["","","",""];
my @avg_frac = [0,0,0,0];
my @avg_actual = [0,0,0,0];
my @count = [0,0,0,0];
my $count_string;
my @sum_frac = [0,0,0,0];
my @sum_actual = [0,0,0,0];
my $dt;
my $start;
my $current;
my $duration;
my $tau; 
my $avg_freq;

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

usage: $0 [-h ] [-i interval] [-n nominal freq] [-b]
	[-d description] -f filename

-h	: this help
-i	: reading interval (seconds); default = 10
-n	: nominal frequency (Hz)
-b	: log actual freq as well as offset (only with -n)
-d	: description, surrounded by quotes
-f	: output file base name using full pathname;
	  for output to console, use "-f -";

EOF
}

my $opt_string = 'hbi:n:d:t:f:';
getopts( "$opt_string", \my %opt ) or usage() and exit;
usage() and exit if $opt{h};
usage() and exit if !$opt{f};

my $interval = 10;
if ($opt{i}) {
	$interval = $opt{i};
	}

my $nominal = 0;
if ($opt{n}) {
	$nominal = $opt{n};
	}

my $description = "";
if ($opt{d}) {
	$description = $opt{d};
	}

my $both = 0;
if ($opt{b}) {
	$both = 1;
	}

my $tags = "mjd";
if ($opt{t}) {
	$tags = $opt{t};
	}

$file = $opt{f};

open (LOG, ">$file") || die "Can't open $file!\n";
select (LOG), $| = 1;

# handle signals and errors -- mainly to clear lockfile on termination
sub sig_handler {
	$dt = DateTime->now;
	$duration = sprintf "%.2f",($dt->mjd - $start->mjd) * 24;
	$current = $dt->ymd('-') . 'T' . $dt->hms(':');
	print "\n";
	printf LOG "# Run terminated at %s (MJD %5.6f)\n",$current,$dt->mjd;
	printf LOG "# Duration: %s hours\n",$duration;
	print LOG "# Cumulative averages:\n";

	for ($j = 1; $j < @sum_actual; $j++) {
		if ($j == 1) {$tau = "1 second:"};
		if ($j == 2) {$tau = "10 second:"};
		if ($j == 3) {$tau = "100 second:"};
		if ($j == 4) {$tau = "1000 second:"};
		$count_string = trim($count[$j]);

		$avg_freq = $sum_actual[$j]/$count[$j];

		if ($sum_frac[$j]) {
			$avg_frac[$j] = sprintf "%+.6e",
				$sum_frac[$j]/$count[$j];
		} else { $avg_frac[$j] = ""; }	

		if ($sum_actual[$j]) {
			printf LOG "# %s\t%+.17f %s (%s)\n",
				$tau,$avg_freq, $avg_frac[$j],$count_string;
			}
	}
        close LOG;
        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';
#----------

$t = new Net::Telnet (Timeout => 10,Port=>$port);
$t->open($machine);
$t->waitfor("/=.*>/");

# pause routine
# how often do we trigger (seconds)?
$SIG{ALRM} = sub { };
setitimer(ITIMER_REAL, 1, $interval);

# write header line
$start = DateTime->now;
$current = $start->ymd('-') . 'T' . $start->hms(':');
print LOG "# Frequency counter output from TSC-5120A (1, 10, 100, 1000 seconds)\n";
if ($description) { print LOG "# $description\n"; }

printf LOG "# Run started at %s (MJD %11.6F).\n",$current,$start->mjd;
print LOG "# Measurement interval: $interval seconds";
if ($nominal) {
	printf LOG 
		", nominal frequency: %f MHz",
		$nominal / 1e6;
	}
print LOG "\n";

while (1) {
# wait for alarm from timer
pause;

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

for ($j = 3; $j < @lines-1; $j++) {
	@tmp = split(/\s/,$lines[$j]);
	$reading[$j-2] = $tmp[2];
	}
for ($j = 1; $j < @reading; $j++) {
	if ($reading[$j]) {
		trim($reading[$j]);
#		 $actual[$j] = sprintf "%+.17f", $reading[$j];
		 $actual[$j] = $reading[$j];
		if ($nominal) {
			$frac[$j] = sprintf "%+.6e",
				((($reading[$j]*1e6)-$nominal)/$nominal);
			$sum_frac[$j] += $frac[$j];
			}
		$sum_actual[$j] += $reading[$j];
		$count[$j]++;
	} else	{
		$actual[$j] = " ";
		$frac[$j] = " ";
		}
}

$dt = DateTime->now;
if ($tags eq "iso") {
	$current = $dt->ymd('-') . 'T' . $dt->hms(':');
	}
else {
	$current = sprintf "%5.6f",$dt->mjd;
}
print LOG $current," ";

if ($actual[1]) { print LOG $actual[1]," " };
if ($actual[2]) { print LOG $actual[2]," " };
if ($actual[3]) { print LOG $actual[3]," " };
if ($actual[4]) { print LOG $actual[4]," " };

if ($nominal) {
	if ($frac[1]) { print LOG $frac[1]," " };
	if ($frac[2]) { print LOG $frac[2]," " };
	if ($frac[3]) { print LOG $frac[3]," " };
	if ($frac[4]) { print LOG $frac[4]," " };
	}

print LOG "\n";
}

close LOG;

$t->print("exit");
$t->close;
