Home | History | Annotate | Download | only in platform
      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 #
     15 from __future__ import division
     16 import os
     17 import tempfile
     18 import csv
     19 import time
     20 import pexpect
     21 
     22 from devlib.platform import Platform
     23 from devlib.instrument import Instrument, InstrumentChannel, MeasurementsCsv, Measurement,  CONTINUOUS,  INSTANTANEOUS
     24 from devlib.exception import TargetError, HostError
     25 from devlib.host import PACKAGE_BIN_DIRECTORY
     26 from devlib.utils.serial_port import open_serial_connection
     27 
     28 
     29 class 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                  model=None,
     37                  modules=None,
     38 
     39                  # serial settings
     40                  serial_port='/dev/ttyS0',
     41                  baudrate=115200,
     42 
     43                  # VExpress MicroSD mount point
     44                  vemsd_mount=None,
     45 
     46                  # supported: dtr, reboottxt
     47                  hard_reset_method=None,
     48                  # supported: uefi, uefi-shell, u-boot, bootmon
     49                  bootloader=None,
     50                  # supported: vemsd
     51                  flash_method='vemsd',
     52 
     53                  image=None,
     54                  fdt=None,
     55                  initrd=None,
     56                  bootargs=None,
     57 
     58                  uefi_entry=None,  # only used if bootloader is "uefi"
     59                  ready_timeout=60,
     60                  ):
     61         super(VersatileExpressPlatform, self).__init__(name,
     62                                                        core_names,
     63                                                        core_clusters,
     64                                                        big_core,
     65                                                        model,
     66                                                        modules)
     67         self.serial_port = serial_port
     68         self.baudrate = baudrate
     69         self.vemsd_mount = vemsd_mount
     70         self.image = image
     71         self.fdt = fdt
     72         self.initrd = initrd
     73         self.bootargs = bootargs
     74         self.uefi_entry = uefi_entry
     75         self.ready_timeout = ready_timeout
     76         self.bootloader = None
     77         self.hard_reset_method = None
     78         self._set_bootloader(bootloader)
     79         self._set_hard_reset_method(hard_reset_method)
     80         self._set_flash_method(flash_method)
     81 
     82     def init_target_connection(self, target):
     83         if target.os == 'android':
     84             self._init_android_target(target)
     85         else:
     86             self._init_linux_target(target)
     87 
     88     def _init_android_target(self, target):
     89         if target.connection_settings.get('device') is None:
     90             addr = self._get_target_ip_address(target)
     91             target.connection_settings['device'] = addr + ':5555'
     92 
     93     def _init_linux_target(self, target):
     94         if target.connection_settings.get('host') is None:
     95             addr = self._get_target_ip_address(target)
     96             target.connection_settings['host'] = addr
     97 
     98     def _get_target_ip_address(self, target):
     99         with open_serial_connection(port=self.serial_port,
    100                                     baudrate=self.baudrate,
    101                                     timeout=30,
    102                                     init_dtr=0) as tty:
    103             tty.sendline('')
    104             self.logger.debug('Waiting for the Android shell prompt.')
    105             tty.expect(target.shell_prompt)
    106 
    107             self.logger.debug('Waiting for IP address...')
    108             wait_start_time = time.time()
    109             while True:
    110                 tty.sendline('ip addr list eth0')
    111                 time.sleep(1)
    112                 try:
    113                     tty.expect(r'inet ([1-9]\d*.\d+.\d+.\d+)', timeout=10)
    114                     return tty.match.group(1)
    115                 except pexpect.TIMEOUT:
    116                     pass  # We have our own timeout -- see below.
    117                 if (time.time() - wait_start_time) > self.ready_timeout:
    118                     raise TargetError('Could not acquire IP address.')
    119 
    120     def _set_hard_reset_method(self, hard_reset_method):
    121         if hard_reset_method == 'dtr':
    122             self.modules.append({'vexpress-dtr': {'port': self.serial_port,
    123                                                   'baudrate': self.baudrate,
    124                                                   }})
    125         elif hard_reset_method == 'reboottxt':
    126             self.modules.append({'vexpress-reboottxt': {'port': self.serial_port,
    127                                                         'baudrate': self.baudrate,
    128                                                         'path': self.vemsd_mount,
    129                                                         }})
    130         else:
    131             ValueError('Invalid hard_reset_method: {}'.format(hard_reset_method))
    132 
    133     def _set_bootloader(self, bootloader):
    134         self.bootloader = bootloader
    135         if self.bootloader == 'uefi':
    136             self.modules.append({'vexpress-uefi': {'port': self.serial_port,
    137                                                    'baudrate': self.baudrate,
    138                                                    'image': self.image,
    139                                                    'fdt': self.fdt,
    140                                                    'initrd': self.initrd,
    141                                                    'bootargs': self.bootargs,
    142                                                    }})
    143         elif self.bootloader == 'uefi-shell':
    144             self.modules.append({'vexpress-uefi-shell': {'port': self.serial_port,
    145                                                          'baudrate': self.baudrate,
    146                                                          'image': self.image,
    147                                                          'bootargs': self.bootargs,
    148                                                          }})
    149         elif self.bootloader == 'u-boot':
    150             uboot_env = None
    151             if self.bootargs:
    152                 uboot_env = {'bootargs': self.bootargs}
    153             self.modules.append({'vexpress-u-boot': {'port': self.serial_port,
    154                                                      'baudrate': self.baudrate,
    155                                                      'env': uboot_env,
    156                                                      }})
    157         elif self.bootloader == 'bootmon':
    158             self.modules.append({'vexpress-bootmon': {'port': self.serial_port,
    159                                                       'baudrate': self.baudrate,
    160                                                       'image': self.image,
    161                                                       'fdt': self.fdt,
    162                                                       'initrd': self.initrd,
    163                                                       'bootargs': self.bootargs,
    164                                                       }})
    165         else:
    166             ValueError('Invalid hard_reset_method: {}'.format(bootloader))
    167 
    168     def _set_flash_method(self, flash_method):
    169         if flash_method == 'vemsd':
    170             self.modules.append({'vexpress-vemsd': {'vemsd_mount': self.vemsd_mount}})
    171         else:
    172             ValueError('Invalid flash_method: {}'.format(flash_method))
    173 
    174 
    175 class Juno(VersatileExpressPlatform):
    176 
    177     def __init__(self,
    178                  vemsd_mount='/media/JUNO',
    179                  baudrate=115200,
    180                  bootloader='u-boot',
    181                  hard_reset_method='dtr',
    182                  **kwargs
    183                  ):
    184         super(Juno, self).__init__('juno',
    185                                    vemsd_mount=vemsd_mount,
    186                                    baudrate=baudrate,
    187                                    bootloader=bootloader,
    188                                    hard_reset_method=hard_reset_method,
    189                                    **kwargs)
    190 
    191 
    192 class TC2(VersatileExpressPlatform):
    193 
    194     def __init__(self,
    195                  vemsd_mount='/media/VEMSD',
    196                  baudrate=38400,
    197                  bootloader='bootmon',
    198                  hard_reset_method='reboottxt',
    199                  **kwargs
    200                  ):
    201         super(TC2, self).__init__('tc2',
    202                                   vemsd_mount=vemsd_mount,
    203                                   baudrate=baudrate,
    204                                   bootloader=bootloader,
    205                                   hard_reset_method=hard_reset_method,
    206                                   **kwargs)
    207 
    208 
    209 class JunoEnergyInstrument(Instrument):
    210 
    211     binname = 'readenergy'
    212     mode = CONTINUOUS | INSTANTANEOUS
    213 
    214     _channels = [
    215         InstrumentChannel('sys', 'current'),
    216         InstrumentChannel('a57', 'current'),
    217         InstrumentChannel('a53', 'current'),
    218         InstrumentChannel('gpu', 'current'),
    219         InstrumentChannel('sys', 'voltage'),
    220         InstrumentChannel('a57', 'voltage'),
    221         InstrumentChannel('a53', 'voltage'),
    222         InstrumentChannel('gpu', 'voltage'),
    223         InstrumentChannel('sys', 'power'),
    224         InstrumentChannel('a57', 'power'),
    225         InstrumentChannel('a53', 'power'),
    226         InstrumentChannel('gpu', 'power'),
    227         InstrumentChannel('sys', 'energy'),
    228         InstrumentChannel('a57', 'energy'),
    229         InstrumentChannel('a53', 'energy'),
    230         InstrumentChannel('gpu', 'energy'),
    231     ]
    232 
    233     def __init__(self, target):
    234         super(JunoEnergyInstrument, self).__init__(target)
    235         self.on_target_file = None
    236         self.command = None
    237         self.binary = self.target.bin(self.binname)
    238         for chan in self._channels:
    239             self.channels[chan.name] = chan
    240         self.on_target_file = self.target.tempfile('energy', '.csv')
    241         self.sample_rate_hz = 10 # DEFAULT_PERIOD is 100[ms] in readenergy.c
    242         self.command = '{} -o {}'.format(self.binary, self.on_target_file)
    243         self.command2 = '{}'.format(self.binary)
    244 
    245     def setup(self):
    246         self.binary = self.target.install(os.path.join(PACKAGE_BIN_DIRECTORY,
    247                                                        self.target.abi, self.binname))
    248 
    249     def reset(self, sites=None, kinds=None):
    250         super(JunoEnergyInstrument, self).reset(sites, kinds)
    251         self.target.killall(self.binname, as_root=True)
    252 
    253     def start(self):
    254         self.target.kick_off(self.command, as_root=True)
    255 
    256     def stop(self):
    257         self.target.killall(self.binname, signal='TERM', as_root=True)
    258 
    259     def get_data(self, output_file):
    260         temp_file = tempfile.mktemp()
    261         self.target.pull(self.on_target_file, temp_file)
    262         self.target.remove(self.on_target_file)
    263 
    264         with open(temp_file, 'rb') as fh:
    265             reader = csv.reader(fh)
    266             headings = reader.next()
    267 
    268             # Figure out which columns from the collected csv we actually want
    269             select_columns = []
    270             for chan in self.active_channels:
    271                 try:
    272                     select_columns.append(headings.index(chan.name))
    273                 except ValueError:
    274                     raise HostError('Channel "{}" is not in {}'.format(chan.name, temp_file))
    275 
    276             with open(output_file, 'wb') as wfh:
    277                 write_headings = ['{}_{}'.format(c.site, c.kind)
    278                                   for c in self.active_channels]
    279                 writer = csv.writer(wfh)
    280                 writer.writerow(write_headings)
    281                 for row in reader:
    282                     write_row = [row[c] for c in select_columns]
    283                     writer.writerow(write_row)
    284 
    285         return MeasurementsCsv(output_file, self.active_channels)
    286 
    287     def take_measurement(self):
    288         result = []
    289         output = self.target.execute(self.command2).split()
    290         reader=csv.reader(output)
    291         headings=reader.next()
    292         values = reader.next()
    293         for chan in self.active_channels:
    294             value = values[headings.index(chan.name)]
    295             result.append(Measurement(value, chan))
    296         return result
    297 
    298