128 lines
4.8 KiB
Python
128 lines
4.8 KiB
Python
# Lint as: python2, python3
|
|
# Copyright 2021 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.
|
|
"""Helper class for power autotests that force DUT to discharge with EC."""
|
|
|
|
from __future__ import absolute_import
|
|
from __future__ import division
|
|
from __future__ import print_function
|
|
|
|
import logging
|
|
import time
|
|
|
|
from autotest_lib.client.common_lib import error
|
|
from autotest_lib.client.cros import ec
|
|
from autotest_lib.client.cros.power import power_utils
|
|
from six.moves import range
|
|
|
|
_FORCE_DISCHARGE_SETTINGS = ['false', 'true', 'optional']
|
|
|
|
|
|
def _parse(force_discharge):
|
|
"""
|
|
Parse and return force discharge setting.
|
|
|
|
@param force_discharge: string of whether to tell ec to discharge battery
|
|
even when the charger is plugged in. 'false' means no forcing
|
|
discharge; 'true' means forcing discharge and raising an error when
|
|
it fails; 'optional' means forcing discharge when possible but not
|
|
raising an error when it fails, which is more friendly to devices
|
|
without a battery.
|
|
|
|
@return: string representing valid force discharge setting.
|
|
|
|
@raise error.TestError: for invalid force discharge setting.
|
|
|
|
"""
|
|
setting = str(force_discharge).lower()
|
|
if setting not in _FORCE_DISCHARGE_SETTINGS:
|
|
raise error.TestError(
|
|
'Force discharge setting \'%s\' need to be one of %s.' %
|
|
(str(force_discharge), _FORCE_DISCHARGE_SETTINGS))
|
|
return setting
|
|
|
|
|
|
def _wait_for_battery_discharge(status):
|
|
"""
|
|
Polling every 100ms for 2 seconds until battery is discharging. This
|
|
normally would take about 350ms.
|
|
|
|
@param status: DUT power status object.
|
|
|
|
@return: boolean indicating force discharge success.
|
|
"""
|
|
for _ in range(20):
|
|
status.refresh()
|
|
if status.battery_discharging():
|
|
return True
|
|
time.sleep(0.1)
|
|
return False
|
|
|
|
|
|
def process(force_discharge, status):
|
|
"""
|
|
Perform force discharge steps.
|
|
|
|
@param force_discharge: string of whether to tell ec to discharge battery
|
|
even when the charger is plugged in. 'false' means no forcing
|
|
discharge; 'true' means forcing discharge and raising an error when
|
|
it fails; 'optional' means forcing discharge when possible but not
|
|
raising an error when it fails, which is more friendly to devices
|
|
without a battery.
|
|
@param status: DUT power status object.
|
|
|
|
@return: bool to indicate whether force discharge steps are successful. Note
|
|
that DUT cannot force discharge if DUT is not connected to AC.
|
|
|
|
@raise error.TestError: for invalid force discharge setting.
|
|
@raise error.TestNAError: when force_discharge is 'true' and the DUT is
|
|
incapable of forcing discharge.
|
|
@raise error.TestError: when force_discharge is 'true' and the DUT command
|
|
to force discharge fails.
|
|
"""
|
|
force_discharge = _parse(force_discharge)
|
|
|
|
if force_discharge == 'true':
|
|
if not status.battery:
|
|
raise error.TestNAError('DUT does not have battery. '
|
|
'Could not force discharge.')
|
|
if not ec.has_cros_ec():
|
|
raise error.TestNAError('DUT does not have CrOS EC. '
|
|
'Could not force discharge.')
|
|
if not power_utils.charge_control_by_ectool(False):
|
|
raise error.TestError('Could not run battery force discharge.')
|
|
if not _wait_for_battery_discharge(status):
|
|
logging.warning('Battery does not report discharging state.')
|
|
return True
|
|
elif force_discharge == 'optional':
|
|
if not status.battery:
|
|
logging.warning('DUT does not have battery. '
|
|
'Do not force discharge.')
|
|
return False
|
|
if not ec.has_cros_ec():
|
|
logging.warning('DUT does not have CrOS EC. '
|
|
'Do not force discharge.')
|
|
return False
|
|
if not power_utils.charge_control_by_ectool(False):
|
|
logging.warning('Could not run battery force discharge. '
|
|
'Do not force discharge.')
|
|
return False
|
|
if not _wait_for_battery_discharge(status):
|
|
logging.warning('Battery does not report discharging state.')
|
|
return True
|
|
elif force_discharge == 'false':
|
|
return False
|
|
|
|
|
|
def restore(force_discharge_success):
|
|
"""
|
|
Set DUT back to charging.
|
|
|
|
@param force_discharge_success: if DUT previously forced discharge
|
|
successfully, set DUT back to charging.
|
|
"""
|
|
if force_discharge_success:
|
|
if not power_utils.charge_control_by_ectool(True):
|
|
logging.warning('Can not restore from force discharge.')
|