• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#    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
23from devlib.instrument import Instrument, InstrumentChannel, MeasurementsCsv, Measurement,  CONTINUOUS,  INSTANTANEOUS
24from 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':
148            uboot_env = None
149            if self.bootargs:
150                uboot_env = {'bootargs': self.bootargs}
151            self.modules.append({'vexpress-u-boot': {'port': self.serial_port,
152                                                     'baudrate': self.baudrate,
153                                                     'env': uboot_env,
154                                                     }})
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,
204                                  **kwargs)
205
206
207class JunoEnergyInstrument(Instrument):
208
209    binname = 'readenergy'
210    mode = CONTINUOUS | INSTANTANEOUS
211
212    _channels = [
213        InstrumentChannel('sys_curr', 'sys', 'current'),
214        InstrumentChannel('a57_curr', 'a57', 'current'),
215        InstrumentChannel('a53_curr', 'a53', 'current'),
216        InstrumentChannel('gpu_curr', 'gpu', 'current'),
217        InstrumentChannel('sys_volt', 'sys', 'voltage'),
218        InstrumentChannel('a57_volt', 'a57', 'voltage'),
219        InstrumentChannel('a53_volt', 'a53', 'voltage'),
220        InstrumentChannel('gpu_volt', 'gpu', 'voltage'),
221        InstrumentChannel('sys_pow', 'sys', 'power'),
222        InstrumentChannel('a57_pow', 'a57', 'power'),
223        InstrumentChannel('a53_pow', 'a53', 'power'),
224        InstrumentChannel('gpu_pow', 'gpu', 'power'),
225        InstrumentChannel('sys_cenr', 'sys', 'energy'),
226        InstrumentChannel('a57_cenr', 'a57', 'energy'),
227        InstrumentChannel('a53_cenr', 'a53', 'energy'),
228        InstrumentChannel('gpu_cenr', 'gpu', 'energy'),
229    ]
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')
239        self.sample_rate_hz = 10 # DEFAULT_PERIOD is 100[ms] in readenergy.c
240        self.command = '{} -o {}'.format(self.binary, self.on_target_file)
241        self.command2 = '{}'.format(self.binary)
242
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
285    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))
294        return result
295
296