1# Lint as: python2, python3 2# Copyright 2021 The Chromium OS Authors. All rights reserved. 3# Use of this source code is governed by a BSD-style license that can be 4# found in the LICENSE file. 5"""Helper class for power autotests that force DUT to discharge with EC.""" 6 7from __future__ import absolute_import 8from __future__ import division 9from __future__ import print_function 10 11import logging 12import time 13 14from autotest_lib.client.common_lib import error 15from autotest_lib.client.cros import ec 16from autotest_lib.client.cros.power import power_utils 17from six.moves import range 18 19_FORCE_DISCHARGE_SETTINGS = ['false', 'true', 'optional'] 20 21 22def _parse(force_discharge): 23 """ 24 Parse and return force discharge setting. 25 26 @param force_discharge: string of whether to tell ec to discharge battery 27 even when the charger is plugged in. 'false' means no forcing 28 discharge; 'true' means forcing discharge and raising an error when 29 it fails; 'optional' means forcing discharge when possible but not 30 raising an error when it fails, which is more friendly to devices 31 without a battery. 32 33 @return: string representing valid force discharge setting. 34 35 @raise error.TestError: for invalid force discharge setting. 36 37 """ 38 setting = str(force_discharge).lower() 39 if setting not in _FORCE_DISCHARGE_SETTINGS: 40 raise error.TestError( 41 'Force discharge setting \'%s\' need to be one of %s.' % 42 (str(force_discharge), _FORCE_DISCHARGE_SETTINGS)) 43 return setting 44 45 46def _wait_for_battery_discharge(status): 47 """ 48 Polling every 100ms for 2 seconds until battery is discharging. This 49 normally would take about 350ms. 50 51 @param status: DUT power status object. 52 53 @return: boolean indicating force discharge success. 54 """ 55 for _ in range(20): 56 status.refresh() 57 if status.battery_discharging(): 58 return True 59 time.sleep(0.1) 60 return False 61 62 63def process(force_discharge, status): 64 """ 65 Perform force discharge steps. 66 67 @param force_discharge: string of whether to tell ec to discharge battery 68 even when the charger is plugged in. 'false' means no forcing 69 discharge; 'true' means forcing discharge and raising an error when 70 it fails; 'optional' means forcing discharge when possible but not 71 raising an error when it fails, which is more friendly to devices 72 without a battery. 73 @param status: DUT power status object. 74 75 @return: bool to indicate whether force discharge steps are successful. Note 76 that DUT cannot force discharge if DUT is not connected to AC. 77 78 @raise error.TestError: for invalid force discharge setting. 79 @raise error.TestNAError: when force_discharge is 'true' and the DUT is 80 incapable of forcing discharge. 81 @raise error.TestError: when force_discharge is 'true' and the DUT command 82 to force discharge fails. 83 """ 84 force_discharge = _parse(force_discharge) 85 86 if force_discharge == 'true': 87 if not status.battery: 88 raise error.TestNAError('DUT does not have battery. ' 89 'Could not force discharge.') 90 if not ec.has_cros_ec(): 91 raise error.TestNAError('DUT does not have CrOS EC. ' 92 'Could not force discharge.') 93 if not power_utils.charge_control_by_ectool(False): 94 raise error.TestError('Could not run battery force discharge.') 95 if not _wait_for_battery_discharge(status): 96 logging.warning('Battery does not report discharging state.') 97 return True 98 elif force_discharge == 'optional': 99 if not status.battery: 100 logging.warning('DUT does not have battery. ' 101 'Do not force discharge.') 102 return False 103 if not ec.has_cros_ec(): 104 logging.warning('DUT does not have CrOS EC. ' 105 'Do not force discharge.') 106 return False 107 if not power_utils.charge_control_by_ectool(False): 108 logging.warning('Could not run battery force discharge. ' 109 'Do not force discharge.') 110 return False 111 if not _wait_for_battery_discharge(status): 112 logging.warning('Battery does not report discharging state.') 113 return True 114 elif force_discharge == 'false': 115 return False 116 117 118def restore(force_discharge_success): 119 """ 120 Set DUT back to charging. 121 122 @param force_discharge_success: if DUT previously forced discharge 123 successfully, set DUT back to charging. 124 """ 125 if force_discharge_success: 126 if not power_utils.charge_control_by_ectool(True): 127 logging.warning('Can not restore from force discharge.') 128