#!/usr/bin/perl
# g15stats - G15 LCD status script
# Copyright 2007 - Robin H. Johnson <robbat2@gentoo.org>
# Based on an earlier version by:
# Brendan Pike <spike@isohunt.com>
#
# You need g15composer running for this already!
# Work in progress!!
#
# Example Output:
# '2007/12/29 Sat 05:21:08 13:21Z  ' 
# '.33/1.2/22.   1/133  101d09h45m '
# 'Mem/Swap 2924/8867 1002/8192 U/F'
# '_123456789_123456789_123456789_1'
# '_123456789_123456789_123456789_1'
# '_123456789_123456789_123456789_1'
#
# Explaination:
#  Date   Weekday   Time   UTC time
# 'YYYY/MM/DD DOW HH:MM:SS H2:M2Z  '
#
#  LoadAvg     Procs#      Uptime
# '.33/1.2/22.   1/133  101d09h05m '
#
#          Used/Free  Used/Free
# 'Mem/Swap 2924/8867 1002/8192 U/F'
# Displayed in MiB (yes, I have 12GiB of RAM)
#
# Load average display styles:
#   0 < LoadAvg < 1   = .XX
#   1 < LoadAvg < 10  = X.X
#  10 < LoadAvg < 100 = XX.
# 100 < LoadAvg		  = XXX
# (I hit a loadavg of 100+ on my SMP box occasionally, when processes are
# blocking for IO)
#
# Proc# - this is the number of active and total processes, just like top
# Uptime - Self explainitory.
#
# These are lines for you to replace however you want.
# I haven't thought of something for them yet.
# '_123456789_123456789_123456789_1'
#
# Development notes:
# Try to write this script to cause as LEAST load as possible.
# Ideally, you should not touch disk at all, nor execute any program.
# Causing heavy kernel stuff is bad too.

use strict;
use warnings;
use POSIX;

#my $pipe = "$ENV{HOME}/.g15stats";
my $pipe = "/dev/shm/g15stats";
my $cpipe = "/var/run/g15composer";

sub send_cmd {
	my ($pipe, $cmd) = @_;
	open PIPE, ">>", $pipe || return 0;
	print PIPE "$cmd\n";
	close PIPE;
	return 1;
}

sub cleanup {
	my ($fn) = $pipe;
	send_cmd($fn, "TM \"foo\"");
	send_cmd($fn, "SC");
	unlink $fn;
	exit 0;
}

sub create_subpipe {
	my ($masterpipe_fn, $pipe_fn) = @_;
	unless(-e $masterpipe_fn and -p $masterpipe_fn and -w $masterpipe_fn) {
		die "Master pipe is not available @ $masterpipe_fn";
	}
	unless(-e $pipe_fn && -p $pipe_fn && -w $pipe_fn) {
		unlink $pipe_fn || die "Cannot remove dud file at $pipe_fn";
		mkfifo($pipe_fn, 0600) || die "Cannot create new pipe_fn at $pipe_fn";
	}
	send_cmd($masterpipe_fn, (sprintf 'SN "%s"', $pipe_fn)) || die "Cannot contact master @ $masterpipe_fn";
}

sub grab_date {
	my $t = time;
    my $local 	= POSIX::strftime "%Y/%m/%d %a %H:%M:%S", localtime($t);
	return $local;
}
sub grab_utc {
	my $t = time;
    my $utc		= POSIX::strftime "%H:%MZ", gmtime($t);
	return $utc;
}
sub grab_mem_swap {
	open F, "</proc/meminfo";
	#my %mem = ( 'MemTotal' => 0, 'MemFree' => 0, 'SwapTotal' => 0, 'SwapFree' => 0 );
	my %mem;
	while(<F>) {
		chomp;
		my @m = split /[\s:]+/;
		$mem{$m[0]} = $m[1];
	}
	close F;
	foreach (qw(Mem Swap)) {
		$mem{$_.'Used'} = $mem{$_.'Total'} - $mem{$_.'Free'};
	}
	# Scale from KiB to MiB
	foreach (keys %mem) {
		$mem{$_} /= 1024;
	}
	return sprintf "Mem/Swap %d/%d %d/%d U/F",$mem{'MemUsed'},$mem{'MemFree'},$mem{'SwapUsed'},$mem{'SwapFree'};
}
sub grab_uptime {
	open F, "</proc/uptime";
	my $l = <F>;
	close F;
	chomp $l;
	(my $uptime, $_) = split /\s+/, $l;
	my ($d, $h, $m);
	$m = int($uptime) / 60;
	$h = int($m) / 60;
	$d = int($h) / 24;
	$m %= 60; $h %= 24;
	return sprintf '%3dd%02dh%02dm', $d, $h, $m;
}
sub grab_loadavg {
	sub f {
		$_ = $_[0];
		if($_ < 1) {
			$_ = sprintf '%.2f', $_;
			$_ =~ s/^0+//g;
		} elsif($_ < 10) {
			$_ = sprintf '%3.1f', $_;
		} elsif($_ < 100) {
			$_ = sprintf '%2.0f.', $_;
		} else {
			$_ = sprintf '%3.0f', $_;
		}
		return $_;
	}
	open F, "</proc/loadavg";
	my $l = <F>;
	close F;
	chomp $l;
	my ($la1, $la5, $la15, $aproc, $tproc, $npid) = split /[\s\/]+/, $l;
	#return sprintf 'load %s/%s/%s procs %2d/%d', f($la1), f($la5), f($la15), $aproc, $tproc;
	return sprintf '%s/%s/%s %3d/%-3d', f($la1), f($la5), f($la15), $aproc, $tproc;
}
create_subpipe($cpipe, $pipe);
$SIG{HUP}  = \&cleanup;
$SIG{INT}  = \&cleanup;
$SIG{QUIT} = \&cleanup;
$| = 1;

my @lines;
my $i = 0;

# How often to refresh the system stats
my $refresh_freq = 1;

while(1) {
	if($i++ % 1 == 0) {
		@lines = ();
		$lines[0] = '';
		push @lines, grab_loadavg().' '.grab_uptime();
		#push @lines, grab_uptime();
		push @lines, grab_mem_swap();
		push @lines, "_123456789"x5;
		push @lines, "_123456789"x5;
		push @lines, "_123456789"x5;
		push @lines, "_123456789"x5;
	}
	
	$lines[0] = grab_date().' '.grab_utc();
	
	my $cmd = "TM ".join(' ', map { "\"$_\"" } @lines);
	#my $cmd = "TO 0 0 M 0 ".join(' ', map { "\"$_\"" } @lines);
	send_cmd($pipe, $cmd);
	sleep 1;
}
cleanup();
