#!/bin/sh
# save as: /usr/lib/systemd/system-sleep/discharge-log
set -eu
CHARGE_STATUS=/tmp/discharge-log.$(id -u).charge

# The battery uevent file might look like:
# POWER_SUPPLY_NAME=BAT1
# POWER_SUPPLY_TYPE=Battery
# POWER_SUPPLY_STATUS=Charging
# ...
# POWER_SUPPLY_VOLTAGE_MIN_DESIGN=15400000
# POWER_SUPPLY_VOLTAGE_NOW=16859000
# POWER_SUPPLY_CURRENT_NOW=2382000
# ...

# "Detect" battery.
UEVENT=$(echo /sys/class/power_supply/BAT?/uevent)

measure_begin() {
    # > All voltages, currents, charges, energies, time and temperatures in uV,
    # > uA, uAh, uWh, seconds and tenths of degree Celsius unless otherwise
    # > stated. It's driver's job to convert its raw values to units in which
    # > this class operates.
    #
    # POWER_SUPPLY_CHARGE_NOW (charge_now): battery capacity in uAh
    # PREV_POWER_SUPPLY_ENERGY_NOW (energy_now): battery capacity in uWh
    # 
    { echo PREV_T=$(date +%s); sed -e 's/^/PREV_/;s/ //g' "$UEVENT"; } \
        >"$CHARGE_STATUS.new"
    mv "$CHARGE_STATUS.new" "$CHARGE_STATUS" || rm "$CHARGE_STATUS.new"
}

measure_now() {
    { echo T=$(date +%s); sed -e 's/ //g' "$UEVENT"; } \
        >"$CHARGE_STATUS.tmp"
    . "$CHARGE_STATUS.tmp"
    rm "$CHARGE_STATUS.tmp"
}

measure_show() {
    local prefix="${1:-}"
    test -n "$prefix" && prefix="$prefix "

    # We can simply source the file and get all PREV values.
    . "$CHARGE_STATUS"
    # Load the current values.
    measure_now

    dT=$((T - PREV_T))  # s
    if test -n "${POWER_SUPPLY_ENERGY_NOW:-}"; then
        # Energy in mWh
        dEmWh=$(((PREV_POWER_SUPPLY_ENERGY_NOW-POWER_SUPPLY_ENERGY_NOW)/1000))
        dQ=not-reported
        pml0=$((\
            PREV_POWER_SUPPLY_ENERGY_NOW/(PREV_POWER_SUPPLY_ENERGY_FULL/1000)))
        pmln=$((POWER_SUPPLY_ENERGY_NOW/(POWER_SUPPLY_ENERGY_FULL/1000)))
    elif test -n "$POWER_SUPPLY_CHARGE_NOW"; then
        # Take the average voltage (should be somewhere in 15.4..17 V), in mV
        U=$(((POWER_SUPPLY_VOLTAGE_NOW+PREV_POWER_SUPPLY_VOLTAGE_NOW)/2000))
        # Charge in mAh
        dQ=$(((POWER_SUPPLY_CHARGE_NOW-PREV_POWER_SUPPLY_CHARGE_NOW)/1000))
        # Energy in mWh
        dEmWh=$((U * dQ / 1000))
        pml0=$((\
            PREV_POWER_SUPPLY_CHARGE_NOW/(PREV_POWER_SUPPLY_CHARGE_FULL/1000)))
        pmln=$((POWER_SUPPLY_CHARGE_NOW/(POWER_SUPPLY_CHARGE_FULL/1000)))
    else
        echo "$0: got neither ENERGY nor CHARGE values. giving up" >&2
        exit 1
    fi
    dE=$((dEmWh * 1000 * 36 / 10))  # mWh*KH = mJ
    dPML=$((pmln - pml0))           # charge, in promille of fully charged bat.
    pmlph=$((dPML * 3600 / dT))     # promille/hour
    P=$((dE / dT))                  # mW
    {
        echo "${prefix}dT = $dT (s), dQ = $dQ (mAh) = $dEmWh (mWh),\
 rate = $dPML (pmlpt), rate/h = $pmlph (pmlpt/h), dE = $((dE/1000)) (J),\
 P = $P (mW)" |
        tee -a /dev/stderr | systemd-cat -t discharge-log -p notice
    } 2>&1
}

case "${1:-}" in
pre)
    test -f "$CHARGE_STATUS" && measure_show '(run)' >/dev/null
    measure_begin
    ;;
post)
    test -f "$CHARGE_STATUS" && measure_show '(sleep)' >/dev/null
    measure_begin
    ;;
begin)
    shift
    measure_begin "$@"
    ;;
show)
    shift
    measure_show "$@"
    ;;
esac
