#!/usr/bin/perl -w
#
# therm-logger.pl
# version 0.9 -- 1 February 2003
#
# Query B&B Electronics 232DTT thermometer and log results
# 
# Copyright 2003 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 vars qw( $OS_win $ob $ob_2 $port $port_2 );
use POSIX qw(setsid);
use Getopt::Std;
use Device::SerialPort;

#----------
# some variables that need to be declared
my $quiet = "1";
my $lockfile;
my $lockfile_2;
my $portbase_2;
my $count_in;
my $reading;
my $raw_temp;
my $negative;
my $tempC;
my $tempF;
my $reading_2;
my $raw_temp_2;
my $negative_2;
my $tempC_2;
my $tempF_2;

#----------
# handle signals and errors -- mainly to clear lockfile on termination
sub sig_handler {
	undef $ob;
	undef $ob_2;
	if (-e $lockfile) {unlink $lockfile;}
	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 = 'dhi:f:p:s:';

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

usage: $0 [-dh] -f logfile -i log_interval -p serial_port -s second_port

-d	: run as daemon
-h	: this (help) message
-f	: logfile using full pathname;
	  for output to console, use "-f -"
-i	: logging interval in seconds
-p	: serial port ("ttyS1")
-s	: optional second serial port ("ttyS2")

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};

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

# set variables to command line params
my $interval = $opt{i};
my $portbase = $opt{p};
my $logfile = $opt{f};

if ($opt{s}) {
	$portbase_2 = $opt{s};
	}

# initialize other variables

#----------
# set up first serial port
my $port = "/dev/" . $portbase;
$lockfile = "/var/lock/LCK.." . $portbase;
$ob = Device::SerialPort->new ($port,$quiet,$lockfile);
die "Can't open serial port $port!\n" unless ($ob);

$ob->baudrate(9600)	|| die "fail setting baud after 0";
$ob->parity("none")	|| die "fail setting parity";
$ob->databits(8)	|| die "fail setting databits";
$ob->stopbits(1)	|| die "fail setting stopbits";
$ob->handshake("none")	|| die "fail setting handshake";
$ob->write_settings || die "no settings";

#----------
# set up second serial port if present
if ($opt{s}) {
	$port_2 = "/dev/" . $portbase_2;
	$lockfile_2 = "/var/lock/LCK.." . $portbase_2;
	$ob_2 = Device::SerialPort->new ($port_2,$quiet,$lockfile_2);
	die "Can't open second serial port $port_2!\n" unless ($ob_2);

	$ob_2->baudrate(9600)	|| die "fail setting baud after 0";
	$ob_2->parity("none")	|| die "fail setting parity";
	$ob_2->databits(8)	|| die "fail setting databits";
	$ob_2->stopbits(1)	|| die "fail setting stopbits";
	$ob_2->handshake("none")	|| die "fail setting handshake";
	$ob_2->write_settings || die "no settings";
	}

# end of message characters for serial input
$ob->are_match("\n","\r");
if ($opt{s}) {
	$ob_2->are_match("\n","\r");
	}
#----------

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

#----------
# main loop
while (1) {
	$ob->write("!0RT");
	if ($opt{s}) {
		$ob_2->write("!0RT");
	}
	# sleep to get reading;
	sleep 1;

	# get first serial port reading
	($count_in,$reading) = $ob->read(2);
	$negative = ord(substr($reading,0,1));
	$raw_temp = ord(substr($reading,1,1));
	if ($negative) {
		$raw_temp = ((((~($raw_temp)) & \0xFF)+1)*-1);
	}
	$tempC = $raw_temp/2;
	$tempF = ($tempC*1.8) + 32;

	# get second serial port reading if present
	if ($opt{s}) {
		($count_in,$reading_2) = $ob_2->read(2);
		$negative_2 = ord(substr($reading_2,0,1));
		$raw_temp_2 = ord(substr($reading_2,1,1));
		if ($negative_2) {
			$raw_temp_2 = ((((~($raw_temp_2)) & \0xFF)+1)*-1);
		}
		$tempC_2 = $raw_temp_2/2;
		$tempF_2 = ($tempC_2*1.8) + 32;
	}

	# print routine
	my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = gmtime;

	
	printf LOG 
	  "%4.4u:%2.2u:%2.2u:%2.2u:%2.2u:%2.2u %6.1f %6.1f\n",
	  $year+1900,$mon+1,$mday,$hour,$min,$sec,$tempC,$tempC_2;

	# sleep for loop; subtract 1 second for reading sleep above
	sleep $interval - 1;
}	
#----------

exit 0;
