#!/usr/bin/perl -w
#
# therm-logger.pl
# version 2.0 -- 14 March 2004
#
# Query Sensatronics E4 thermometer and log results
# 
# Copyright 2003 by John R. Ackermann  N8UR (jra@febo.com)
# Licensed under the GPL version 2 or later; see the file COPYING
# included with this distribution.  I request, but do not require, that
# any modifications that correct bugs or errors, or increase the program's
# functionality, be sent via email to the author at the address above.

use strict;
use POSIX qw(setsid);
use Getopt::Std;
use Time::HiRes qw(usleep sleep gettimeofday tv_interval);
use Net::Telnet;

#----------
# some variables that need to be declared
my $telnet;
my $count = 0;
my $reading;
my $pre;
my $output;
my $loop_start;
my $outer_start;
my $outer_elapsed;
my $elapsed;
my $result;
my $null;
my $temp1;
my $temp1_avg;
my $temp2;
my $temp2_avg;
my $temp3;
my $temp3_avg;
my $temp4;
my $temp4_avg;

#----------
# handle signals and errors -- mainly to clear lockfile on termination
sub sig_handler {
	undef $telnet;
	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';
#----------

#----------
# display usage
my $opt_string = 'adhi:f:';

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

usage: $0 [-adh] -f logfile -i log_interval -p serial_port
-a	: take readings every 10 seconds and average over interval;
	  interval needs to be multiple of 10
-d	: run as daemon
-h	: this (help) message
-f	: logfile using full pathname;
	  for output to console, use "-f -"
-i	: logging interval in seconds (minimum 10, default 60)

EOF
}

#----------
# daemonize
sub daemonize {
	chdir '/' or die "Can't chdir to /: $!";
	umask 0;
	open STDIN, '/dev/null' or die "Can't read /dev/null: $!";
	open STDOUT, '>/dev/null' or die "Can't write to /dev/null: $!";
	open STDERR, '>/dev/null' or die "Can't write to /dev/null: $!";
	defined(my $pid = fork) or die "Can't fork: $!";
	exit if $pid;
	setsid or die "Can't start a new session: $!";
}
#----------

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

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

# get interval
my $interval = 60;
if ($opt{i}) {
	$interval = $opt{i};
	}
# system only updates every 8 seconds, so no point in going faster
if ($interval < 8) {
	$interval = 8;
	}

# average readings
my $average = 0;
if ( ($opt{a}) & ($interval >19) ) {
	$average = $interval/10;
	}

# run as daemon?
&daemonize if $opt{d};

# output file
my $logfile = $opt{f};

#----------
# set up telnet port
$telnet = new Net::Telnet ( Timeout=>7,
			     Port=>80, 
                             Errmode=>'die');

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

#----------
# main loop
while (1) {
	$outer_start = [gettimeofday];
	if ($average) {
		while ($count < $average) {
			$loop_start = [gettimeofday];
			$telnet->open('therm-1.febo.com');
			$telnet->print("GET /temp HTTP/1.0\n");
			($pre,$output) = $telnet->waitfor(Match=>'/[0-9]$/');
			$telnet->close;
			$result = $pre . $output;
			($null,$temp1,$null,$temp2,$null,$temp3,
			     $null,$temp4) = split(/\|/,$result);
			$temp1_avg += $temp1;
			$temp2_avg += $temp2;
			$temp3_avg += $temp3;
			$temp4_avg += $temp4;
			$count++;
  			$elapsed = tv_interval($loop_start, [gettimeofday]);
			# sleep for a bit less than full time
			if ($elapsed < 9.920) {
				sleep(9.920 - $elapsed);
				}
			}
		$temp1 = $temp1_avg/$count;
		$temp1_avg = 0;
		$temp2 = $temp2_avg/$count;
		$temp2_avg = 0;
		$temp3 = $temp3_avg/$count;
		$temp3_avg = 0;
		$temp4 = $temp4_avg/$count;
		$temp4_avg = 0;
		$count = 0;
		}
	else {
		$telnet->open('therm-1.febo.com');
		$telnet->print("GET /temp HTTP/1.0\n");
		($pre,$output) = $telnet->waitfor(Match=>'/[0-9]$/');
		$telnet->close;
		$result = $pre . $output;
		($null,$temp1,$null,$temp2,$null,$temp3,
		     $null,$temp4) = split(/\|/,$result);
		}

	# print routine
	my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = gmtime;
	printf LOG 
  	"%4.4u-%2.2u-%2.2uT%2.2u:%2.2u:%2.2u %5.1f %5.1f %5.1f %5.1f\n",
  	$year+1900,$mon+1,$mday,$hour,$min,$sec,$temp1,$temp2,$temp3,$temp4;

	# fine adjust for loop time
	sleep($interval - (tv_interval($outer_start, [gettimeofday])));
}	
#----------

exit 0;
