blob: e37f28d4d1181fa1fa80f080146063744c8fcb23 [file] [log] [blame]
#!/bin/sh
# Copyright 2015 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
# This script controls battery power level and performs required battery
# cutoff protection by sending commands to EC with ectool.
SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
DISPLAY_MESSAGE="${SCRIPT_DIR}/display_wipe_message.sh"
# After calling display_wipe_message.sh to draw image with frecon, we must
# redirect text output to tty1 to display information on the screen.
TTY=/dev/tty1
usage_help() {
echo "Usage: $0
[--method shutdown|reboot|battery_cutoff]
[--check-ac connect_ac|remove_ac]
[--min-battery-percent <minimum battery percentage>]
[--max-battery-percent <maximum battery percentage>]
[--min-battery-voltage <minimum battery voltage>]
[--max-battery-voltage <maximum battery voltage>]"
}
reset_activate_date() {
/usr/sbin/activate_date --clean
}
has_battery() {
( type ectool && ectool battery ) >/dev/null 2>&1
}
get_battery_percentage() {
local full="" current=""
full="$(ectool battery 2>/dev/null |
awk '/Last full charge/ {print int($4)}')"
current="$(ectool battery 2>/dev/null |
awk '/Remaining capacity/ {print int($3)}')"
echo $((current * 100 / full))
}
get_battery_voltage() {
ectool battery 2>/dev/null | awk '/Present voltage/ {print int($3)}'
}
is_ac_present() {
ectool battery | grep -q AC_PRESENT
}
require_ac() {
if ! is_ac_present; then
"${DISPLAY_MESSAGE}" "connect_ac"
while ! is_ac_present; do
sleep 0.5
done
fi
}
require_remove_ac() {
if is_ac_present; then
"${DISPLAY_MESSAGE}" "remove_ac"
while is_ac_present; do
sleep 0.5
done
fi
}
check_battery_value() {
local min_battery_value="$1" max_battery_value="$2"
local get_value_cmd="$3"
local battery_value=""
local prev_battery_value=""
battery_value="$(${get_value_cmd})"
if [ -n "$min_battery_value" ] &&
[ "$battery_value" -lt "$min_battery_value" ]; then
require_ac
${DISPLAY_MESSAGE} "charging"
# Wait for battery to charge to min_battery_value
prev_battery_value="-1"
# Print a new line before and after showing battery info.
echo ""
while [ "$battery_value" -lt "$min_battery_value" ]; do
# Only print battery info when it changes.
if [ "$battery_value" -ne "$prev_battery_value" ]; then
# Keep printing battery information in the same line.
printf '\rcurrent: %s, target: %s' \
"$battery_value" "$min_battery_value" >"${TTY}"
prev_battery_value="$battery_value"
fi
sleep 1
battery_value="$(${get_value_cmd})"
done
echo ""
fi
if [ -n "$max_battery_value" ] &&
[ "$battery_value" -gt "$max_battery_value" ]; then
require_remove_ac
${DISPLAY_MESSAGE} "discharging"
# Wait for battery to discharge to max_battery_value
prev_battery_value="-1"
# Print a new line before and after showing battery info.
echo ""
while [ "$battery_value" -gt "$max_battery_value" ]; do
# Only print battery info when it changes.
if [ "$battery_value" -ne "$prev_battery_value" ]; then
# Keep printing battery information in the same line.
printf '\rcurrent: %s, target: %s' \
"$battery_value" "$max_battery_value" >"${TTY}"
prev_battery_value="$battery_value"
fi
sleep 1
battery_value="$(${get_value_cmd})"
done
echo ""
fi
}
check_ac_state() {
local cutoff_ac_state="$1"
if [ "$cutoff_ac_state" = "connect_ac" ]; then
require_ac
elif [ "$cutoff_ac_state" = "remove_ac" ]; then
require_remove_ac
fi
}
main() {
local cutoff_method=""
local cutoff_ac_state=""
local min_battery_percent="" max_battery_percent=""
local min_battery_voltage="" max_battery_voltage=""
local key
while [ $# -ge 1 ]
do
key="$1"
case "$key" in
"--method" )
cutoff_method="$2"
shift 2
;;
"--check-ac" )
cutoff_ac_state="$2"
shift 2
;;
"--min-battery-percent" )
min_battery_percent="$2"
shift 2
;;
"--max-battery-percent" )
max_battery_percent="$2"
shift 2
;;
"--min-battery-voltage" )
min_battery_voltage="$2"
shift 2
;;
"--max-battery-voltage" )
max_battery_voltage="$2"
shift 2
;;
* )
usage_help
exit 1
;;
esac
done
reset_activate_date
if has_battery; then
# Needed by 'ectool battery'.
mkdir -p /var/lib/power_manager
modprobe i2c_dev
if [ -n "$min_battery_percent" ] || [ -n "$max_battery_percent" ]; then
check_battery_value "$min_battery_percent" "$max_battery_percent" \
"get_battery_percentage"
fi
if [ -n "$min_battery_voltage" ] || [ -n "$max_battery_voltage" ]; then
check_battery_value "$min_battery_voltage" "$max_battery_voltage" \
"get_battery_voltage"
fi
fi
# Ask operator to plug or unplug AC before doing cut off.
check_ac_state "$cutoff_ac_state"
$DISPLAY_MESSAGE "cutting_off"
# TODO (shunhsingou): In bug
# https://bugs.chromium.org/p/chromium/issues/detail?id=589677, small amount
# of devices fail to do cut off in factory. This may be caused by unstable
# ectool, or shutdown fail in the tmpfs. Here we add more retries for
# solving this problem. Remove the retry when finding the root cause.
for i in $(seq 5)
do
case "$cutoff_method" in
"shutdown" )
shutdown -h now
;;
"reboot" )
reboot
;;
"battery_cutoff" )
crossystem battery_cutoff_request=1 && sleep 3 && reboot
;;
* )
# By default we shutdown the device without doing anything.
shutdown -h now
esac
sleep 15
done
$DISPLAY_MESSAGE "cutoff_failed"
sleep 1d
exit 1
}
main "$@"