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

VERSION="1.16"
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

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/boot/olpc_build ]
then
	BUILD=$(< /boot/boot/olpc_build )
fi

if [ -e /boot/olpc_build ]
then
	BUILD=$(< /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
# 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_level
if [ -n $B_INFO/$CAPACITY ]
then
	CAPACITY=capacity
fi

function get_acr {

	if [ XO_VERSION == "1.5" ]
	then
		ACR_TEMP=$(< $B_INFO/$ACR_PROP )
		echo ${ACR_TEMP-0} 
	else
		ACR_TEMP=$(< $B_INFO/$ACR_PROP )
		echo $(conv_2s_comp ${ACR_TEMP-0})
	fi
}

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 [ XO_VERSION == "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	
