1# Lint as: python2, python3 2# Copyright (c) 2010 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 6import logging, time 7from autotest_lib.client.common_lib import error 8from autotest_lib.client.cros import service_stopper 9from autotest_lib.client.cros.power import power_status 10from autotest_lib.client.cros.power import power_test 11from autotest_lib.client.cros.power import power_utils 12 13 14class power_BatteryCharge(power_test.power_Test): 15 """class power_BatteryCharge.""" 16 version = 1 17 18 def initialize(self, pdash_note=''): 19 """Perform necessary initialization prior to test run.""" 20 21 if not power_utils.has_battery(): 22 raise error.TestNAError('DUT has no battery. Test Skipped') 23 24 self.status = power_status.get_status() 25 26 if not self.status.on_ac(): 27 raise error.TestNAError( 28 'This test needs to be run with the AC power online') 29 30 super(power_BatteryCharge, self).initialize(seconds_period=20, 31 pdash_note=pdash_note, 32 force_discharge=False) 33 34 self._services = service_stopper.ServiceStopper( 35 service_stopper.ServiceStopper.POWER_DRAW_SERVICES + ['ui']) 36 self._services.stop_services() 37 38 def run_once(self, max_run_time=180, percent_charge_to_add=1, 39 percent_initial_charge_max=None, 40 percent_target_charge=None, 41 use_design_charge_capacity=True): 42 43 """ 44 max_run_time: maximum time the test will run for 45 percent_charge_to_add: percentage of the charge capacity charge to 46 add. The target charge will be capped at the charge capacity. 47 percent_initial_charge_max: maxium allowed initial charge. 48 use_design_charge_capacity: If set, use charge_full_design rather than 49 charge_full for calculations. charge_full represents 50 wear-state of battery, vs charge_full_design representing 51 ideal design state. 52 """ 53 54 time_to_sleep = 60 55 56 self._backlight = power_utils.Backlight() 57 self._backlight.set_percent(0) 58 59 self.remaining_time = self.max_run_time = max_run_time 60 61 self.charge_full_design = self.status.battery.charge_full_design 62 self.charge_full = self.status.battery.charge_full 63 if use_design_charge_capacity: 64 self.charge_capacity = self.charge_full_design 65 else: 66 self.charge_capacity = self.charge_full 67 68 if self.charge_capacity == 0: 69 raise error.TestError('Failed to determine charge capacity') 70 71 self.initial_charge = self.status.battery.charge_now 72 percent_initial_charge = self.initial_charge * 100 / \ 73 self.charge_capacity 74 if percent_initial_charge_max and percent_initial_charge > \ 75 percent_initial_charge_max: 76 raise error.TestError('Initial charge (%f) higher than max (%f)' 77 % (percent_initial_charge, percent_initial_charge_max)) 78 79 current_charge = self.initial_charge 80 if percent_target_charge is None: 81 charge_to_add = self.charge_capacity * \ 82 float(percent_charge_to_add) / 100 83 target_charge = current_charge + charge_to_add 84 else: 85 target_charge = self.charge_capacity * \ 86 float(percent_target_charge) / 100 87 88 # trim target_charge if it exceeds charge capacity 89 if target_charge > self.charge_capacity: 90 target_charge = self.charge_capacity 91 92 logging.info('max_run_time: %d', self.max_run_time) 93 logging.info('initial_charge: %f', self.initial_charge) 94 logging.info('target_charge: %f', target_charge) 95 96 self.start_measurements() 97 while self.remaining_time and current_charge < target_charge: 98 if time_to_sleep > self.remaining_time: 99 time_to_sleep = self.remaining_time 100 self.remaining_time -= time_to_sleep 101 102 time.sleep(time_to_sleep) 103 104 self.status.refresh() 105 106 new_charge = self.status.battery.charge_now 107 logging.info('time_to_sleep: %d', time_to_sleep) 108 logging.info('charge_added: %f', (new_charge - current_charge)) 109 110 current_charge = new_charge 111 logging.info('current_charge: %f', current_charge) 112 113 if self.status.battery.status == 'Full': 114 logging.info('Battery full, aborting!') 115 break 116 elif self.status.battery.status == 'Discharging': 117 # TestError might be raised if |use_design_charge_capacity| 118 # is True when testing with older battery. 119 if current_charge > self.charge_capacity * 0.97: 120 logging.info('Battery full (Discharge on AC), aborting!') 121 else: 122 raise error.TestError('This test needs to be run with the ' 123 'battery charging on AC.') 124 self._end_time = time.time() 125 126 def postprocess_iteration(self): 127 """"Collect and log keyvals.""" 128 keyvals = {} 129 keyvals['ah_charge_full'] = self.charge_full 130 keyvals['ah_charge_full_design'] = self.charge_full_design 131 keyvals['ah_charge_capacity'] = self.charge_capacity 132 keyvals['ah_initial_charge'] = self.initial_charge 133 keyvals['ah_final_charge'] = self.status.battery.charge_now 134 s_time_taken = self.max_run_time - self.remaining_time 135 min_time_taken = s_time_taken / 60. 136 keyvals['s_time_taken'] = s_time_taken 137 keyvals['percent_initial_charge'] = self.initial_charge * 100 / \ 138 keyvals['ah_charge_capacity'] 139 keyvals['percent_final_charge'] = keyvals['ah_final_charge'] * 100 / \ 140 keyvals['ah_charge_capacity'] 141 142 percent_charge_added = keyvals['percent_final_charge'] - \ 143 keyvals['percent_initial_charge'] 144 # Conditionally write charge current keyval only when the amount of 145 # charge added is > 50% to remove samples when test is run but battery 146 # is already mostly full. Otherwise current will be ~0 and not 147 # meaningful. 148 if percent_charge_added > 50: 149 hrs_charging = keyvals['s_time_taken'] / 3600. 150 keyvals['a_avg50_charge_current'] = \ 151 (keyvals['ah_final_charge'] - self.initial_charge) / \ 152 hrs_charging 153 154 self.keyvals.update(keyvals) 155 156 self._keyvallogger.add_item('time_to_charge_min', min_time_taken, 157 'point', 'perf') 158 self._keyvallogger.add_item('initial_charge_ah', self.initial_charge, 159 'point', 'perf') 160 self._keyvallogger.add_item('final_charge_ah', 161 self.status.battery.charge_now, 'point', 162 'perf') 163 self._keyvallogger.add_item('charge_full_ah', self.charge_full, 164 'point', 'perf') 165 self._keyvallogger.add_item('charge_full_design_ah', 166 self.charge_full_design, 'point', 'perf') 167 self._keyvallogger.set_end(self._end_time) 168 169 super(power_BatteryCharge, self).postprocess_iteration() 170 171 def cleanup(self): 172 """Restore stop services and backlight level.""" 173 if hasattr(self, '_services') and self._services: 174 self._services.restore_services() 175 if hasattr(self, '_backlight') and self._backlight: 176 self._backlight.restore() 177