1*9c5db199SXin Li# Lint as: python2, python3 2*9c5db199SXin Li# Copyright 2015 The Chromium OS Authors. All rights reserved. 3*9c5db199SXin Li# Use of this source code is governed by a BSD-style license that can be 4*9c5db199SXin Li# found in the LICENSE file. 5*9c5db199SXin Li 6*9c5db199SXin Liimport error, logging, os, serial, shutil, threading, time 7*9c5db199SXin Li 8*9c5db199SXin Li_power_play_data_file = '/tmp/power_play_data' 9*9c5db199SXin Li 10*9c5db199SXin Liclass PowerPlay(object): 11*9c5db199SXin Li """Class to record serial over USB data from Power Play (go/powerplay). 12*9c5db199SXin Li 13*9c5db199SXin Li It detects if powerplay is connected to the DUT over USB and opens the 14*9c5db199SXin Li serial port to start receiving powerplay data. It also opens a text file to 15*9c5db199SXin Li save this data after some formatting. 16*9c5db199SXin Li """ 17*9c5db199SXin Li 18*9c5db199SXin Li version = 1 19*9c5db199SXin Li 20*9c5db199SXin Li def __init__(self, test_obj, record_interval=0): 21*9c5db199SXin Li """Initialize PowerPlay. 22*9c5db199SXin Li 23*9c5db199SXin Li @param test_obj: test object. 24*9c5db199SXin Li @param record_interval: Power play data recording interval in seconds. 25*9c5db199SXin Li """ 26*9c5db199SXin Li self.test = test_obj 27*9c5db199SXin Li self.ser = None 28*9c5db199SXin Li self.recording_interval = record_interval 29*9c5db199SXin Li self.momentary_curr_list = list() 30*9c5db199SXin Li self.record_thread = None 31*9c5db199SXin Li 32*9c5db199SXin Li def extract_current(self, pp_data): 33*9c5db199SXin Li """Extract momentary current value from each line of powerplay data. 34*9c5db199SXin Li 35*9c5db199SXin Li @param pp_data: Single line of powerplay data with eight comma separated 36*9c5db199SXin Li values. 37*9c5db199SXin Li @return list containing momentary current values. 38*9c5db199SXin Li """ 39*9c5db199SXin Li if pp_data[0].isdigit(): 40*9c5db199SXin Li self.momentary_curr_list.append(float(pp_data[pp_data.index(',')+1:] 41*9c5db199SXin Li [:pp_data[pp_data.index(',')+1:].index(',')])) 42*9c5db199SXin Li return self.momentary_curr_list 43*9c5db199SXin Li 44*9c5db199SXin Li def start_recording_power_play_data(self): 45*9c5db199SXin Li """Starts a new thread to record power play data.""" 46*9c5db199SXin Li self.record_thread = threading.Thread(target=self.start_record_thread) 47*9c5db199SXin Li self.record_thread.daemon = True 48*9c5db199SXin Li self.record_thread.start() 49*9c5db199SXin Li 50*9c5db199SXin Li def start_record_thread(self): 51*9c5db199SXin Li """Start recording power play data. 52*9c5db199SXin Li 53*9c5db199SXin Li Get a list of connected USB devices and try to establish a serial 54*9c5db199SXin Li connection. Once the connection is established, open a text file and 55*9c5db199SXin Li start reading serial data and write it to the text file after some 56*9c5db199SXin Li formatting. 57*9c5db199SXin Li """ 58*9c5db199SXin Li devices = [x for x in os.listdir('/dev/') if x.startswith('ttyUSB')] 59*9c5db199SXin Li 60*9c5db199SXin Li for device in devices: 61*9c5db199SXin Li device_link = '/dev/' + device 62*9c5db199SXin Li try: 63*9c5db199SXin Li if self.ser == None: 64*9c5db199SXin Li logging.info('Trying ... %s', device_link) 65*9c5db199SXin Li self.ser = serial.Serial(device_link, 115200) 66*9c5db199SXin Li logging.info('Successfully connected to %s', device_link) 67*9c5db199SXin Li break 68*9c5db199SXin Li except serial.SerialException as e: 69*9c5db199SXin Li raise error.TestError('Failed to connect to %s becuase of %s' % 70*9c5db199SXin Li (device_link, str(e))) 71*9c5db199SXin Li 72*9c5db199SXin Li self.text_file = open(_power_play_data_file, 'w') 73*9c5db199SXin Li 74*9c5db199SXin Li if self.ser != None: 75*9c5db199SXin Li title_row = ('time,powerplay_timestamp,momentary_current (A),' + 76*9c5db199SXin Li 'momentary_charge (AH),average_current (A),' + 77*9c5db199SXin Li 'total_standby_time,total_wake_time,num_wakes,is_awake?\n') 78*9c5db199SXin Li self.text_file.write(title_row) 79*9c5db199SXin Li start_time = time.time() 80*9c5db199SXin Li while self.ser.readline(): 81*9c5db199SXin Li current_timestamp = (('{:>10.3f}'. 82*9c5db199SXin Li format(time.time() - start_time)).replace(' ', '')) 83*9c5db199SXin Li pp_data = (self.ser.readline().replace('\00', ''). 84*9c5db199SXin Li replace(' ', ',').replace('\r', '')) 85*9c5db199SXin Li if (not pp_data.startswith('#') and (len(pp_data) > 30) and 86*9c5db199SXin Li not self.text_file.closed): 87*9c5db199SXin Li self.text_file.write(current_timestamp + ',' + pp_data) 88*9c5db199SXin Li self.momentary_curr_list = self.extract_current(pp_data) 89*9c5db199SXin Li time.sleep(self.recording_interval) 90*9c5db199SXin Li self.ser.flushInput() 91*9c5db199SXin Li else: 92*9c5db199SXin Li self.text_file.write('No data from powerplay. Check connection.') 93*9c5db199SXin Li 94*9c5db199SXin Li def stop_recording_power_play_data(self): 95*9c5db199SXin Li """Stop recording power play data. 96*9c5db199SXin Li 97*9c5db199SXin Li Close the text file and copy it to the test log results directory. Also 98*9c5db199SXin Li report current data to the performance dashboard. 99*9c5db199SXin Li """ 100*9c5db199SXin Li if not self.text_file.closed: 101*9c5db199SXin Li self.text_file.close() 102*9c5db199SXin Li shutil.copy(_power_play_data_file, self.test.resultsdir) 103*9c5db199SXin Li self.test.output_perf_value(description='momentary_current_draw', 104*9c5db199SXin Li value=self.momentary_curr_list, 105*9c5db199SXin Li units='Amps', higher_is_better=False) 106