#!/usr/bin/perl
|
|
|
|
use strict;
|
|
use warnings;
|
|
use 5.10.0;
|
|
|
|
use Device::SerialPort;
|
|
use POSIX qw(setsid);
|
|
use File::Slurp;
|
|
use Getopt::Long;
|
|
use LWP::UserAgent;
|
|
|
|
my $remote;
|
|
my $refresh_rate = 10;
|
|
my $daemon = 0;
|
|
my $cpucount = 2; # default to 2 CPUs
|
|
my $device = '/dev/ttyUSB0';
|
|
|
|
my $getopt_result = GetOptions (
|
|
"device=s" => \$device, # string
|
|
"refresh=i" => \$refresh_rate, # numeric
|
|
"remote=s" => \$remote, # string
|
|
"daemon" => \$daemon, # flag
|
|
"cores=i" => \$cpucount # numeric
|
|
);
|
|
|
|
say "Talking to Arduino on $device";
|
|
|
|
if ($daemon) {
|
|
daemonize();
|
|
}
|
|
|
|
# set a count explicitly - need this for remotes
|
|
if ($remote && $cpucount) {
|
|
countcpus($cpucount);
|
|
}
|
|
|
|
# connect to the arduino
|
|
my $port = Device::SerialPort->new($device)
|
|
or die "Couldn't connect to $device";
|
|
|
|
$port->databits(8);
|
|
$port->baudrate(9600);
|
|
$port->parity('none');
|
|
$port->stopbits(1);
|
|
|
|
# ^C
|
|
$SIG{INT} = "cleanup";
|
|
|
|
while (1) {
|
|
my $degrees = getdegrees();
|
|
|
|
# pack into a 16 bit int (i think) and send to the arduino
|
|
my $count_out = $port->write(pack 's', $degrees)
|
|
or die "Unable to write to $device";
|
|
|
|
say "$degrees degrees, $count_out bytes sent" unless $daemon;
|
|
sleep $refresh_rate;
|
|
}
|
|
|
|
sub getdegrees {
|
|
my $loadstring;
|
|
if ($remote) {
|
|
$loadstring = getremoteload($remote);
|
|
} else {
|
|
$loadstring = read_file('/proc/loadavg');
|
|
}
|
|
|
|
my ($load) = split / /, $loadstring;
|
|
say "Load: $load" unless $daemon;
|
|
return 1 if $load >= countcpus();
|
|
return int(($load / countcpus()) * 180);
|
|
}
|
|
|
|
# sometimes i miss writing a language that's too clever for its own good
|
|
{ my $count;
|
|
sub countcpus {
|
|
my ($setcount) = @_;
|
|
if ($setcount) {
|
|
say "CPUs explicitly set to $setcount" unless $daemon;
|
|
$count = $setcount;
|
|
}
|
|
$count //= grep { /^processor\s+: [0-9]/ } read_file('/proc/cpuinfo');
|
|
}
|
|
}
|
|
|
|
sub getremoteload {
|
|
my ($remote) = @_;
|
|
# Create a user agent object
|
|
my $ua = LWP::UserAgent->new;
|
|
$ua->agent("loaduino/0.1 ");
|
|
|
|
# Create a request
|
|
my $req = HTTP::Request->new(GET => $remote);
|
|
|
|
# Pass request to the user agent and get a response back
|
|
my $res = $ua->request($req);
|
|
|
|
# Check the outcome of the response
|
|
my $loadstring;
|
|
if ($res->is_success) {
|
|
$loadstring = $res->content;
|
|
} else {
|
|
say $res->status_line;
|
|
$loadstring = '0.0';
|
|
}
|
|
|
|
say "Load string: $loadstring";
|
|
return $loadstring;
|
|
}
|
|
|
|
sub daemonize {
|
|
chdir '/';
|
|
umask 0;
|
|
open STDIN, '/dev/null';
|
|
open STDOUT, '>', '/dev/null';
|
|
open STDERR, '>', '/dev/null';
|
|
defined(my $pid = fork)
|
|
or die "Can't fork: $!";
|
|
exit if $pid;
|
|
setsid
|
|
or die "Can't start a new sesssion: $!";
|
|
}
|
|
|
|
sub cleanup {
|
|
say "cleaning up";
|
|
$port->close() || warn "close failed";
|
|
undef $port;
|
|
die "murdered!";
|
|
}
|
|
|
|
END {
|
|
if (defined $port) {
|
|
cleanup();
|
|
}
|
|
}
|
|
|