#!/bin/sh
# Copyright One Laptop Per Child
# Power loging script 
# Released under GPLv3

VERSION="2.0.1"
FDATE=`date "+%y%m%d-%H%M%S"`
HOST=`hostname -s`
B_INFO=/sys/class/power_supply/olpc-battery

# This is the delay in the wallclock_delay.  Its the minimum sample time for the
# system date.
WALL_PERIOD=5 

# This is the (approx) delay inbetween readings.
# This delay should be some where in the middle of integer mutiples of WALL_PERIOD
# delays that bound the desired delay.
# That way if our timer and system date are out of phase you don't end up having to wait a whole
# new WALL_PERIOD for the RTC check to expire.
# DELAY=12

# As of ver 1.14 I've switched back to using sleep rather than my wallclock_delay.
# I the previous issues I had with using sleep were never resolved.  
# I'm going to try to resolve them this time if I see them since they are considered
# a bug.

# A delay of 10 seconds seems to be too low.
DELAY=20

if [ -e /sys/class/dmi/id/product_version ]
then
        XO_VERSION=$(< /sys/class/dmi/id/product_version )
else
        XO_VERSION="1"
fi

KERNVER=`uname -r | cut -c 1-6 | sed 's/\.//g'`

if [[ $KERNVER -gt 2625 ]]; then
	KERNAPI=2
else
	KERNAPI=1
fi

echo "Checking/waiting for a battery"

until [ $(< $B_INFO/present ) = 1 ] 
do 
	sleep 1
done

# If we just inserted a battery the EC needs time to
# read all the info.

echo "Found one."
echo "Pausing to let the EC think"

sleep 3

# Now that we wait for a battery we can use the battery serial number in the filename
DS_SERNUM=$(< $B_INFO/serial_number )
LOGFILE="pwr-$FDATE-$DS_SERNUM.csv"

ACR_PROP="charge_counter"

if [ ! -e $B_INFO/$ACR_PROP ]
then
	ACR_PROP="accum_current"
fi

if [ -e /boot/olpc_build ]
then
	BUILD=$(< /boot/olpc_build )
fi

if [ -e /bootpart/boot/olpc_build ]
then
	BUILD=$(< /bootpart/boot/olpc_build )
fi

if [ -e $B_INFO/eeprom ]
then
# Skip 64 bytes and read 5 bytes; display without an address and in single byte mode
# I don't use od directly since the -j skip does not do a real fseek.
	echo "Reading eeprom data."
	MFG_SER=`dd if=$B_INFO/eeprom bs=1 skip=64 count=5 2> /dev/null | od -A n -t x1` 
	CHGCNT=`dd if=$B_INFO/eeprom bs=1 skip=74 count=2 2> /dev/null| od -A n -t x1 ` 
	CHGSOC=`dd if=$B_INFO/eeprom bs=1 skip=76 count=1 2> /dev/null| od -A n -t x1 ` 
	DISCNT=`dd if=$B_INFO/eeprom bs=1 skip=77 count=2 2> /dev/null| od -A n -t x1 ` 
	DISSOC=`dd if=$B_INFO/eeprom bs=1 skip=79 count=1 2> /dev/null| od -A n -t x1 ` 
else
	echo "Can't read the eeprom data because your kernel dosen't support eeprom dump"
	MFG_SER="NA"
	CHGCNT="NA"
	CHGSOC="NA"
	DISCNT="NA"
	DISSOC="NA"
fi

echo "Starting log $LOGFILE"
echo

echo "pwr_log Ver: $VERSION" > $LOGFILE
echo -n "HOST: "	>> $LOGFILE 
echo $HOST  		>> $LOGFILE 
echo -n "DATE: " 	>> $LOGFILE 
echo `date` 		>> $LOGFILE
echo -n "ECVER: " 	>> $LOGFILE 
echo `cat /ofw/ec-name` >> $LOGFILE
echo -n "OFWVER: " 	>> $LOGFILE 
echo `cat /ofw/openprom/model` 	>> $LOGFILE
echo -n "MODEL: " 	>> $LOGFILE 
echo `cat /ofw/model` 	>> $LOGFILE
echo -n "SERNUM: " 	>> $LOGFILE
echo `cat /ofw/serial-number` 	>> $LOGFILE
echo -n "BATTECH: " 	>> $LOGFILE 
echo `cat $B_INFO/technology` 	>> $LOGFILE
echo -n "BATMFG: " 	>> $LOGFILE 
echo `cat $B_INFO/manufacturer` >> $LOGFILE
echo -n "BATSER: " 	>> $LOGFILE 
echo $DS_SERNUM 	>> $LOGFILE
echo -n "BUILD: " 	>> $LOGFILE 
echo $BUILD 		>> $LOGFILE
echo -n "MFGSER: " 	>> $LOGFILE
echo $MFG_SER 		>> $LOGFILE
echo -n "CHGCNT: " 	>> $LOGFILE
echo $CHGCNT 		>> $LOGFILE
echo -n "CHGSOC: " 	>> $LOGFILE
echo $CHGSOC 		>> $LOGFILE
echo -n "DISCNT: " 	>> $LOGFILE
echo $DISCNT 		>> $LOGFILE
echo -n "DISSOC: " 	>> $LOGFILE
echo $DISSOC 		>> $LOGFILE
echo -n "WALL_PERIOD: "	>> $LOGFILE
echo $WALL_PERIOD: 	>> $LOGFILE
echo -n "DELAY: " 	>> $LOGFILE
echo $DELAY: 		>> $LOGFILE
echo -n "XOVER: " 	>> $LOGFILE
echo $XO_VERSION 	>> $LOGFILE
echo -n "KERNVER: " 	>> $LOGFILE
echo $KERNVER 		>> $LOGFILE
echo -n "KERNAPI: " 	>> $LOGFILE
echo $KERNAPI 		>> $LOGFILE

# Allow the addition of some descriptive text from the cmd line
echo -n "COMMENT: " >> $LOGFILE
echo $1 >> $LOGFILE
echo "<StartData>" >> $LOGFILE

# feed this the wall clock time in seconds you wish to delay
# It will spin until that time has passed.  If the system is suspeneded
# it may sleep more.
function wallclock_delay {
	DATE1=`date +%s`
	EXPIRE=$((DATE1+$1))
        while [ `date +%s` -lt $EXPIRE ]; do
        	sleep $WALL_PERIOD	 
	done
}

# convert a number into 2's complement
function conv_2s_comp {

# this has since been changed in the kernel so that it returns
# a signed value rather than unsigned. which fixes the math
# So if its already negative then bail

	if [ $1 -lt 0 ]
	then
		echo $1
		return
	fi

	if [ $1 -gt 32767 ]
	then
		echo $(( 0 - (65535-$1+1) )) 
		return
	fi

	echo $1
}

CAPACITY=capacity
if [ ! -f $B_INFO/$CAPACITY ]
then
	CAPACITY=capacity_level
fi

function get_acr {

    local acr_temp

    acr_temp=$(< $B_INFO/$ACR_PROP )
    test $KERNAPI -eq 1 && acr_temp=$(conv_2s_comp ${acr_temp:-0})
    echo ${acr_temp:-0}
}

START_ACR=$(get_acr)

while true
do 
	CAPLEVEL=$(< $B_INFO/$CAPACITY )
	VOLT=$(< $B_INFO/voltage_avg)
	CURR=$(< $B_INFO/current_avg)
	TEMP=$(< $B_INFO/temp)
	STAT=$(< $B_INFO/status)

	ACR=$(get_acr)
	ACR_DIFF=$(( ${ACR-0}-${START_ACR-0} ))
	if [ $KERNAPI -eq 1 ]
	then
		MAh=$(( $ACR_DIFF * 625 / 1500 ))
	else
		MAh=$ACR_DIFF
	fi
	echo `date +%s`",$CAPLEVEL,$VOLT,$CURR,$TEMP,$ACR,$STAT,$MAh" | tee -a $LOGFILE
	sync
#	wallclock_delay $DELAY
	sleep $DELAY
done
