| #!/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 "$@" |