blob: 76b58a45a79ed04ebcc8cb0283c74298e0121652 [file] [log] [blame]
Sergei Trofimov4e6afe92015-10-09 09:30:04 +01001# Copyright 2015 ARM Limited
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14#
15from __future__ import division
16import os
17import tempfile
18import csv
19import time
20import pexpect
21
22from devlib.platform import Platform
Chris Redpath09915102015-12-12 21:46:59 +000023from devlib.instrument import Instrument, InstrumentChannel, MeasurementsCsv, Measurement, CONTINUOUS, INSTANTANEOUS
Sergei Trofimov4e6afe92015-10-09 09:30:04 +010024from devlib.exception import TargetError, HostError
25from devlib.host import PACKAGE_BIN_DIRECTORY
26from devlib.utils.serial_port import open_serial_connection
27
28
29class VersatileExpressPlatform(Platform):
30
31 def __init__(self, name, # pylint: disable=too-many-locals
32
33 core_names=None,
34 core_clusters=None,
35 big_core=None,
36 modules=None,
37
38 # serial settings
39 serial_port='/dev/ttyS0',
40 baudrate=115200,
41
42 # VExpress MicroSD mount point
43 vemsd_mount=None,
44
45 # supported: dtr, reboottxt
46 hard_reset_method=None,
47 # supported: uefi, uefi-shell, u-boot, bootmon
48 bootloader=None,
49 # supported: vemsd
50 flash_method='vemsd',
51
52 image=None,
53 fdt=None,
54 initrd=None,
55 bootargs=None,
56
57 uefi_entry=None, # only used if bootloader is "uefi"
58 ready_timeout=60,
59 ):
60 super(VersatileExpressPlatform, self).__init__(name,
61 core_names,
62 core_clusters,
63 big_core,
64 modules)
65 self.serial_port = serial_port
66 self.baudrate = baudrate
67 self.vemsd_mount = vemsd_mount
68 self.image = image
69 self.fdt = fdt
70 self.initrd = initrd
71 self.bootargs = bootargs
72 self.uefi_entry = uefi_entry
73 self.ready_timeout = ready_timeout
74 self.bootloader = None
75 self.hard_reset_method = None
76 self._set_bootloader(bootloader)
77 self._set_hard_reset_method(hard_reset_method)
78 self._set_flash_method(flash_method)
79
80 def init_target_connection(self, target):
81 if target.os == 'android':
82 self._init_android_target(target)
83 else:
84 self._init_linux_target(target)
85
86 def _init_android_target(self, target):
87 if target.connection_settings.get('device') is None:
88 addr = self._get_target_ip_address(target)
89 target.connection_settings['device'] = addr + ':5555'
90
91 def _init_linux_target(self, target):
92 if target.connection_settings.get('host') is None:
93 addr = self._get_target_ip_address(target)
94 target.connection_settings['host'] = addr
95
96 def _get_target_ip_address(self, target):
97 with open_serial_connection(port=self.serial_port,
98 baudrate=self.baudrate,
99 timeout=30,
100 init_dtr=0) as tty:
101 tty.sendline('')
102 self.logger.debug('Waiting for the Android shell prompt.')
103 tty.expect(target.shell_prompt)
104
105 self.logger.debug('Waiting for IP address...')
106 wait_start_time = time.time()
107 while True:
108 tty.sendline('ip addr list eth0')
109 time.sleep(1)
110 try:
111 tty.expect(r'inet ([1-9]\d*.\d+.\d+.\d+)', timeout=10)
112 return tty.match.group(1)
113 except pexpect.TIMEOUT:
114 pass # We have our own timeout -- see below.
115 if (time.time() - wait_start_time) > self.ready_timeout:
116 raise TargetError('Could not acquire IP address.')
117
118 def _set_hard_reset_method(self, hard_reset_method):
119 if hard_reset_method == 'dtr':
120 self.modules.append({'vexpress-dtr': {'port': self.serial_port,
121 'baudrate': self.baudrate,
122 }})
123 elif hard_reset_method == 'reboottxt':
124 self.modules.append({'vexpress-reboottxt': {'port': self.serial_port,
125 'baudrate': self.baudrate,
126 'path': self.vemsd_mount,
127 }})
128 else:
129 ValueError('Invalid hard_reset_method: {}'.format(hard_reset_method))
130
131 def _set_bootloader(self, bootloader):
132 self.bootloader = bootloader
133 if self.bootloader == 'uefi':
134 self.modules.append({'vexpress-uefi': {'port': self.serial_port,
135 'baudrate': self.baudrate,
136 'image': self.image,
137 'fdt': self.fdt,
138 'initrd': self.initrd,
139 'bootargs': self.bootargs,
140 }})
141 elif self.bootloader == 'uefi-shell':
142 self.modules.append({'vexpress-uefi-shell': {'port': self.serial_port,
143 'baudrate': self.baudrate,
144 'image': self.image,
145 'bootargs': self.bootargs,
146 }})
147 elif self.bootloader == 'u-boot':
Sergei Trofimova1e991c2015-12-15 16:17:08 +0000148 uboot_env = None
149 if self.bootargs:
150 uboot_env = {'bootargs': self.bootargs}
Sergei Trofimov4e6afe92015-10-09 09:30:04 +0100151 self.modules.append({'vexpress-u-boot': {'port': self.serial_port,
152 'baudrate': self.baudrate,
Sergei Trofimova1e991c2015-12-15 16:17:08 +0000153 'env': uboot_env,
Sergei Trofimov4e6afe92015-10-09 09:30:04 +0100154 }})
155 elif self.bootloader == 'bootmon':
156 self.modules.append({'vexpress-bootmon': {'port': self.serial_port,
157 'baudrate': self.baudrate,
158 'image': self.image,
159 'fdt': self.fdt,
160 'initrd': self.initrd,
161 'bootargs': self.bootargs,
162 }})
163 else:
164 ValueError('Invalid hard_reset_method: {}'.format(bootloader))
165
166 def _set_flash_method(self, flash_method):
167 if flash_method == 'vemsd':
168 self.modules.append({'vexpress-vemsd': {'vemsd_mount': self.vemsd_mount}})
169 else:
170 ValueError('Invalid flash_method: {}'.format(flash_method))
171
172
173class Juno(VersatileExpressPlatform):
174
175 def __init__(self,
176 vemsd_mount='/media/JUNO',
177 baudrate=115200,
178 bootloader='u-boot',
179 hard_reset_method='dtr',
180 **kwargs
181 ):
182 super(Juno, self).__init__('juno',
183 vemsd_mount=vemsd_mount,
184 baudrate=baudrate,
185 bootloader=bootloader,
186 hard_reset_method=hard_reset_method,
187 **kwargs)
188
189
190class TC2(VersatileExpressPlatform):
191
192 def __init__(self,
193 vemsd_mount='/media/VEMSD',
194 baudrate=38400,
195 bootloader='bootmon',
196 hard_reset_method='reboottxt',
197 **kwargs
198 ):
199 super(TC2, self).__init__('tc2',
200 vemsd_mount=vemsd_mount,
201 baudrate=baudrate,
202 bootloader=bootloader,
203 hard_reset_method=hard_reset_method,
Sergei Trofimov4e6afe92015-10-09 09:30:04 +0100204 **kwargs)
205
206
207class JunoEnergyInstrument(Instrument):
208
209 binname = 'readenergy'
Chris Redpath09915102015-12-12 21:46:59 +0000210 mode = CONTINUOUS | INSTANTANEOUS
Sergei Trofimov4e6afe92015-10-09 09:30:04 +0100211
212 _channels = [
Sergei Trofimov9192deb2017-08-31 17:38:33 +0100213 InstrumentChannel('sys', 'current'),
214 InstrumentChannel('a57', 'current'),
215 InstrumentChannel('a53', 'current'),
216 InstrumentChannel('gpu', 'current'),
217 InstrumentChannel('sys', 'voltage'),
218 InstrumentChannel('a57', 'voltage'),
219 InstrumentChannel('a53', 'voltage'),
220 InstrumentChannel('gpu', 'voltage'),
221 InstrumentChannel('sys', 'power'),
222 InstrumentChannel('a57', 'power'),
223 InstrumentChannel('a53', 'power'),
224 InstrumentChannel('gpu', 'power'),
225 InstrumentChannel('sys', 'energy'),
226 InstrumentChannel('a57', 'energy'),
227 InstrumentChannel('a53', 'energy'),
228 InstrumentChannel('gpu', 'energy'),
Sergei Trofimov4e6afe92015-10-09 09:30:04 +0100229 ]
230
231 def __init__(self, target):
232 super(JunoEnergyInstrument, self).__init__(target)
233 self.on_target_file = None
234 self.command = None
235 self.binary = self.target.bin(self.binname)
236 for chan in self._channels:
237 self.channels[chan.name] = chan
238 self.on_target_file = self.target.tempfile('energy', '.csv')
Brendan Jackman49b547a2017-04-26 15:07:05 +0100239 self.sample_rate_hz = 10 # DEFAULT_PERIOD is 100[ms] in readenergy.c
Sergei Trofimov4e6afe92015-10-09 09:30:04 +0100240 self.command = '{} -o {}'.format(self.binary, self.on_target_file)
Chris Redpath09915102015-12-12 21:46:59 +0000241 self.command2 = '{}'.format(self.binary)
Sergei Trofimov4e6afe92015-10-09 09:30:04 +0100242
243 def setup(self):
244 self.binary = self.target.install(os.path.join(PACKAGE_BIN_DIRECTORY,
245 self.target.abi, self.binname))
246
247 def reset(self, sites=None, kinds=None):
248 super(JunoEnergyInstrument, self).reset(sites, kinds)
249 self.target.killall(self.binname, as_root=True)
250
251 def start(self):
252 self.target.kick_off(self.command, as_root=True)
253
254 def stop(self):
255 self.target.killall(self.binname, signal='TERM', as_root=True)
256
257 def get_data(self, output_file):
258 temp_file = tempfile.mktemp()
259 self.target.pull(self.on_target_file, temp_file)
260 self.target.remove(self.on_target_file)
261
262 with open(temp_file, 'rb') as fh:
263 reader = csv.reader(fh)
264 headings = reader.next()
265
266 # Figure out which columns from the collected csv we actually want
267 select_columns = []
268 for chan in self.active_channels:
269 try:
270 select_columns.append(headings.index(chan.name))
271 except ValueError:
272 raise HostError('Channel "{}" is not in {}'.format(chan.name, temp_file))
273
274 with open(output_file, 'wb') as wfh:
275 write_headings = ['{}_{}'.format(c.site, c.kind)
276 for c in self.active_channels]
277 writer = csv.writer(wfh)
278 writer.writerow(write_headings)
279 for row in reader:
280 write_row = [row[c] for c in select_columns]
281 writer.writerow(write_row)
282
283 return MeasurementsCsv(output_file, self.active_channels)
284
Chris Redpath09915102015-12-12 21:46:59 +0000285 def take_measurement(self):
286 result = []
287 output = self.target.execute(self.command2).split()
288 reader=csv.reader(output)
289 headings=reader.next()
290 values = reader.next()
291 for chan in self.active_channels:
292 value = values[headings.index(chan.name)]
293 result.append(Measurement(value, chan))
Chris Redpath09915102015-12-12 21:46:59 +0000294 return result
295