1# Copyright (c) 2010 The Chromium OS Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5import logging, time 6from autotest_lib.client.bin import test 7from autotest_lib.client.common_lib import error 8from autotest_lib.client.cros import power_status, power_utils, service_stopper 9 10class power_BatteryCharge(test.test): 11 """class power_BatteryCharge.""" 12 version = 1 13 14 def initialize(self): 15 if not power_utils.has_battery(): 16 raise error.TestNAError('DUT has no battery. Test Skipped') 17 18 self.status = power_status.get_status() 19 20 if not self.status.on_ac(): 21 raise error.TestNAError( 22 'This test needs to be run with the AC power online') 23 24 self._services = service_stopper.ServiceStopper( 25 service_stopper.ServiceStopper.POWER_DRAW_SERVICES + ['ui']) 26 self._services.stop_services() 27 28 29 def run_once(self, max_run_time=180, percent_charge_to_add=1, 30 percent_initial_charge_max=None, 31 percent_target_charge=None, 32 use_design_charge_capacity=True): 33 34 """ 35 max_run_time: maximum time the test will run for 36 percent_charge_to_add: percentage of the charge capacity charge to 37 add. The target charge will be capped at the charge capacity. 38 percent_initial_charge_max: maxium allowed initial charge. 39 use_design_charge_capacity: If set, use charge_full_design rather than 40 charge_full for calculations. charge_full represents 41 wear-state of battery, vs charge_full_design representing 42 ideal design state. 43 """ 44 45 time_to_sleep = 60 46 47 self._backlight = power_utils.Backlight() 48 self._backlight.set_percent(0) 49 50 self.remaining_time = self.max_run_time = max_run_time 51 52 self.charge_full_design = self.status.battery[0].charge_full_design 53 self.charge_full = self.status.battery[0].charge_full 54 if use_design_charge_capacity: 55 self.charge_capacity = self.charge_full_design 56 else: 57 self.charge_capacity = self.charge_full 58 59 if self.charge_capacity == 0: 60 raise error.TestError('Failed to determine charge capacity') 61 62 self.initial_charge = self.status.battery[0].charge_now 63 percent_initial_charge = self.initial_charge * 100 / \ 64 self.charge_capacity 65 if percent_initial_charge_max and percent_initial_charge > \ 66 percent_initial_charge_max: 67 raise error.TestError('Initial charge (%f) higher than max (%f)' 68 % (percent_initial_charge, percent_initial_charge_max)) 69 70 current_charge = self.initial_charge 71 if percent_target_charge is None: 72 charge_to_add = self.charge_capacity * \ 73 float(percent_charge_to_add) / 100 74 target_charge = current_charge + charge_to_add 75 else: 76 target_charge = self.charge_capacity * \ 77 float(percent_target_charge) / 100 78 79 # trim target_charge if it exceeds charge capacity 80 if target_charge > self.charge_capacity: 81 target_charge = self.charge_capacity 82 83 logging.info('max_run_time: %d', self.max_run_time) 84 logging.info('initial_charge: %f', self.initial_charge) 85 logging.info('target_charge: %f', target_charge) 86 87 while self.remaining_time and current_charge < target_charge: 88 if time_to_sleep > self.remaining_time: 89 time_to_sleep = self.remaining_time 90 self.remaining_time -= time_to_sleep 91 92 time.sleep(time_to_sleep) 93 94 self.status.refresh() 95 if not self.status.on_ac(): 96 raise error.TestError( 97 'This test needs to be run with the AC power online') 98 99 new_charge = self.status.battery[0].charge_now 100 logging.info('time_to_sleep: %d', time_to_sleep) 101 logging.info('charge_added: %f', (new_charge - current_charge)) 102 103 current_charge = new_charge 104 logging.info('current_charge: %f', current_charge) 105 106 if self.status.battery[0].status == 'Full': 107 logging.info('Battery full, aborting!') 108 break 109 110 111 def postprocess_iteration(self): 112 keyvals = {} 113 keyvals['ah_charge_full'] = self.charge_full 114 keyvals['ah_charge_full_design'] = self.charge_full_design 115 keyvals['ah_charge_capacity'] = self.charge_capacity 116 keyvals['ah_initial_charge'] = self.initial_charge 117 keyvals['ah_final_charge'] = self.status.battery[0].charge_now 118 keyvals['s_time_taken'] = self.max_run_time - self.remaining_time 119 keyvals['percent_initial_charge'] = self.initial_charge * 100 / \ 120 keyvals['ah_charge_capacity'] 121 keyvals['percent_final_charge'] = keyvals['ah_final_charge'] * 100 / \ 122 keyvals['ah_charge_capacity'] 123 124 percent_charge_added = keyvals['percent_final_charge'] - \ 125 keyvals['percent_initial_charge'] 126 # Conditionally write charge current keyval only when the amount of 127 # charge added is > 50% to remove samples when test is run but battery 128 # is already mostly full. Otherwise current will be ~0 and not 129 # meaningful. 130 if percent_charge_added > 50: 131 hrs_charging = keyvals['s_time_taken'] / 3600. 132 keyvals['a_avg50_charge_current'] = \ 133 (keyvals['ah_final_charge'] - self.initial_charge) / \ 134 hrs_charging 135 136 self.write_perf_keyval(keyvals) 137 138 139 def cleanup(self): 140 if hasattr(self, '_services') and self._services: 141 self._services.restore_services() 142 if hasattr(self, '_backlight') and self._backlight: 143 self._backlight.restore() 144