#! /usr/bin/perl
# see POD section at end of program for details

# This is free software: you can redistribute it and/or modify it under the 
# terms of the GNU General Public License as published by the Free Software 
# Foundation, version 2.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc., 51
# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

my $NAME='temper-mon';
my $VERSION='2.0.0';
my $AUTHOR='Tyler J. Wagner <tyler@tolaris.com>';

# includes
use 5.010;
use strict;
use warnings;
use Getopt::Long;
use Pod::Usage;
use Device::USB::PCSensor::HidTEMPer;

# defaults
our $calibration_n = 0;
our $calibration_x = 1;
our $degrees = "celsius";
our $device_num = 1;
our $query_all = "";

# functions
sub app_options;


##########################################################################
# begin main function
##########################################################################

# check program arguments
app_options();

my $pcsensor  = Device::USB::PCSensor::HidTEMPer->new();

# get device list
my @devices = $pcsensor->list_devices();
my $devices_found_num = scalar(@devices);

if ( $device_num < 0 || $device_num > $devices_found_num ) {
	warn "Invalid device_number $device_num; found only $devices_found_num devices.\n";
	exit 1;
}

# if only one device requested, query only it
my $i = 1;
foreach my $device ( @devices ) {
	if ( ( $i == $device_num || $query_all ) && defined $device->internal() ) {
		say $device->internal()->$degrees() * $calibration_x + $calibration_n;
	}
	$i++;
}


# end main
exit;

# single device method
#my $device = $pcsensor->device();
#
#if ( ! defined $device->internal() ) {
#	say "No device detected.";
#	exit 1;
#}


##########################################################################
# Parses command-line arguments and sets related globals.
##########################################################################
sub app_options {
	my ($use_fahrenheit, $help, $man, $version);

	Getopt::Long::Configure ("bundling");
	GetOptions(
		'all|a!'	=> \$query_all,
		'fahrenheit|f!'	=> \$use_fahrenheit,
		'n=f' => \$calibration_n,
		'x=f' => \$calibration_x,
		'help|h|?!'	=> \$help,
		'man|m!'	=> \$man,
		'version|V!'	=> \$version)
		or pod2usage(-verbose => 1, -exitval => 1);

	# chatty output options
	if ( defined $help ) { pod2usage(-verbose => 1, -exitval => 0); }
	if ( defined $man ) { pod2usage(-verbose => 2, -exitval => 0); }
	if ( defined $version ) { warn "$NAME v$VERSION, by $AUTHOR\n"; exit; }

	if ( defined $use_fahrenheit ) { $degrees = "fahrenheit"; }

	# if device_num specified, set it
	if ( @ARGV ) {
		$device_num = shift(@ARGV);
	}

}


__END__

##########################################################################
# POD section
##########################################################################

=head1 NAME

temper-mon - Read temperature from a TEMPer USB thermal probe.


=head1 SYNOPSIS

temper-mon [options] [device_number]

=head1 DESCRIPTION

A tool to read the temperature from one or more TEMPer devices. It outputs the temperature from the device specified by device_number. Devices are numbered from 1, and are listed in order they appear on the USB bus. See "lsusb" for a list.

If device_number is not provided, temper-mon defaults to the first device. To output readings from all devices, use the -a switch.

If your device is providing inaccurate readings, you may manually adjust the result using the -x and -n switches. Calibration is applied by the formula:

T = t * x + n

Where T is the output, t is the temperature read from the TEMPer device, and x and n are factors specified as arguments to those options. If using -a, adjustments are applied to all devices. If you require different adjustments for each device, invoke temper-mon multiple times.

=head1 OPTIONS

 -a, --all           read temperature of all attached devices
 -f, --fahrenheit    output in degrees fahrenheit instead of celsius
 -n <NUM>            add NUM to temperature (may be negative)
 -x <NUM>            multiply temperature by NUM
 -h, --help          brief help message
 -m, --man           show man page
 -V, --version       show program version

=head1 EXAMPLES

temper-mon

   Display temperature of first TEMPer device.

temper-mon 2

   Display temperature of second TEMPer device (counting from 1).

temper-mon -a

   Display temperature of all devices, one per line.

temper-mon -x 1.1 -n 4 2

   Read second TEMPer device, multiply by 1.1, and subtract 4 degrees.

=head1 REQUIRES

Perl 5.010, Device::USB::PCSensor::HidTEMPer, Getopt::Long, Pod::Usage.

To install dependencies on Debian-based systems, including Ubuntu, run:

sudo apt-get install perl-doc libdevice-usb-pcsensor-hidtemper-perl

=head1 AUTHOR

Tyler J. Wagner <tyler@tolaris.com>

=head1 NOTES

This software is documented on the author's website at www.tolaris.com.

This software works with TEMPer USB temperature probes. 'lsusb' should detect your device as:

Bus 00x Device 00x: ID 1130:660c Tenx Technology, Inc. 

Other devices are now supported by the HidTEMPer Perl module. To use them, see the CPAM documentation and edit this source code appropriately.

If you want to run this software as an unpriviledged user, save the following in /etc/udev/rules.d/99-temperusb.rules:

SUBSYSTEMS=="usb", ACTION=="add", ATTRS{idVendor}=="1130", ATTRS{idProduct}=="660c", MODE="666"

You can abuse the calibration feature to output temperature in any other scale. The following commands are equivalent:

temper-mon -x 1.8 -n 32

temper-mon -f

=head1 ACKNOWLEDGEMENTS

Thanks to Magnus Sulland for writing the Perl module that communicates with TEMPer hardware.

http://search.cpan.org/~msulland/Device-USB-PCSensor-HidTEMPer/

=cut
