diff options
Diffstat (limited to 'systrace/catapult/devil/devil/utils/battor_device_mapping.py')
-rwxr-xr-x | systrace/catapult/devil/devil/utils/battor_device_mapping.py | 309 |
1 files changed, 0 insertions, 309 deletions
diff --git a/systrace/catapult/devil/devil/utils/battor_device_mapping.py b/systrace/catapult/devil/devil/utils/battor_device_mapping.py deleted file mode 100755 index 8cabb83..0000000 --- a/systrace/catapult/devil/devil/utils/battor_device_mapping.py +++ /dev/null @@ -1,309 +0,0 @@ -#!/usr/bin/python -# Copyright 2016 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - - -''' -This script provides tools to map BattOrs to phones. - -Phones are identified by the following string: - -"Phone serial number" - Serial number of the phone. This can be -obtained via 'adb devices' or 'usb-devices', and is not expected -to change for a given phone. - -BattOrs are identified by the following two strings: - -"BattOr serial number" - Serial number of the BattOr. This can be -obtained via 'usb-devices', and is not expected to change for -a given BattOr. - -"BattOr path" - The path of the form '/dev/ttyUSB*' that is used -to communicate with the BattOr (the battor_agent binary takes -this BattOr path as a parameter). The BattOr path is frequently -reassigned by the OS, most often when the device is disconnected -and then reconnected. Thus, the BattOr path cannot be expected -to be stable. - -In a typical application, the user will require the BattOr path -for the BattOr that is plugged into a given phone. For instance, -the user will be running tracing on a particular phone, and will -need to know which BattOr path to use to communicate with the BattOr -to get the corresponding power trace. - -Getting this mapping requires two steps: (1) determining the -mapping between phone serial numbers and BattOr serial numbers, and -(2) getting the BattOr path corresponding to a given BattOr serial -number. - -For step (1), we generate a JSON file giving this mapping. This -JSON file consists of a list of items of the following form: -[{'phone': <phone serial 1>, 'battor': <battor serial 1>}, -{'phone': <phone serial 2>, 'battor': <battor serial 2>}, ...] - -The default way to generate this JSON file is using the function -GenerateSerialMapFile, which generates a mapping based on assuming -that the system has two identical USB hubs connected to it, and -the phone plugged into physical port number 1 on one hub corresponds -to the BattOr plugged into physical port number 1 on the other hub, -and similarly with physical port numbers 2, 3, etc. This generates -the map file based on the structure at the time GenerateSerialMapFile called. -Note that after the map file is generated, port numbers are no longer used; -the user could move around the devices in the ports without affecting -which phone goes with which BattOr. (Thus, if the user wanted to update the -mapping to match the new port connections, the user would have to -re-generate this file.) - -The script update_mapping.py will do this updating from the command line. - -If the user wanted to specify a custom mapping, the user could instead -create the JSON file manually. (In this case, hubs would not be necessary -and the physical ports connected would be irrelevant.) - -Step (2) is conducted through the function GetBattOrPathFromPhoneSerial, -which takes a serial number mapping generated via step (1) and a phone -serial number, then gets the corresponding BattOr serial number from the -map and determines its BattOr path (e.g. /dev/ttyUSB0). Since BattOr paths -can change if devices are connected and disconnected (even if connected -or disconnected via the same port) this function should be called to -determine the BattOr path every time before connecting to the BattOr. - -Note that if there is only one BattOr connected to the system, then -GetBattOrPathFromPhoneSerial will always return that BattOr and will ignore -the mapping file. Thus, if the user never has more than one BattOr connected -to the system, the user will not need to generate mapping files. -''' - - -import json -import collections - -from battor import battor_error -from devil.utils import find_usb_devices -from devil.utils import usb_hubs - - -def GetBattOrList(device_tree_map): - return [x for x in find_usb_devices.GetTTYList() - if IsBattOr(x, device_tree_map)] - - -def IsBattOr(tty_string, device_tree_map): - (bus, device) = find_usb_devices.GetBusDeviceFromTTY(tty_string) - node = device_tree_map[bus].FindDeviceNumber(device) - return '0403:6001' in node.desc - - -def GetBattOrSerialNumbers(device_tree_map): - for x in find_usb_devices.GetTTYList(): - if IsBattOr(x, device_tree_map): - (bus, device) = find_usb_devices.GetBusDeviceFromTTY(x) - devnode = device_tree_map[bus].FindDeviceNumber(device) - yield devnode.serial - - -def ReadSerialMapFile(filename): - """Reads JSON file giving phone-to-battor serial number map. - - Parses a JSON file consisting of a list of items of the following form: - [{'phone': <phone serial 1>, 'battor': <battor serial 1>}, - {'phone': <phone serial 2>, 'battor': <battor serial 2>}, ...] - - indicating which phone serial numbers should be matched with - which BattOr serial numbers. Returns dictionary of the form: - - {<phone serial 1>: <BattOr serial 1>, - <phone serial 2>: <BattOr serial 2>} - - Args: - filename: Name of file to read. - """ - result = {} - with open(filename, 'r') as infile: - in_dict = json.load(infile) - for x in in_dict: - result[x['phone']] = x['battor'] - return result - -def WriteSerialMapFile(filename, serial_map): - """Writes a map of phone serial numbers to BattOr serial numbers to file. - - Writes a JSON file consisting of a list of items of the following form: - [{'phone': <phone serial 1>, 'battor': <battor serial 1>}, - {'phone': <phone serial 2>, 'battor': <battor serial 2>}, ...] - - indicating which phone serial numbers should be matched with - which BattOr serial numbers. Mapping is based on the physical port numbers - of the hubs that the BattOrs and phones are connected to. - - Args: - filename: Name of file to write. - serial_map: Serial map {phone: battor} - """ - result = [] - for (phone, battor) in serial_map.iteritems(): - result.append({'phone': phone, 'battor': battor}) - with open(filename, 'w') as outfile: - json.dump(result, outfile) - -def GenerateSerialMap(hub_types=None): - """Generates a map of phone serial numbers to BattOr serial numbers. - - Generates a dict of: - {<phone serial 1>: <battor serial 1>, - <phone serial 2>: <battor serial 2>} - indicating which phone serial numbers should be matched with - which BattOr serial numbers. Mapping is based on the physical port numbers - of the hubs that the BattOrs and phones are connected to. - - Args: - hub_types: List of hub types to check for. If not specified, checks - for all defined hub types. (see usb_hubs.py for details) - """ - if hub_types: - hub_types = [usb_hubs.GetHubType(x) for x in hub_types] - else: - hub_types = usb_hubs.ALL_HUBS - - devtree = find_usb_devices.GetBusNumberToDeviceTreeMap() - - # List of serial numbers in the system that represent BattOrs. - battor_serials = list(GetBattOrSerialNumbers(devtree)) - - # If there's only one BattOr in the system, then a serial number ma - # is not necessary. - if len(battor_serials) == 1: - return {} - - # List of dictionaries, one for each hub, that maps the physical - # port number to the serial number of that hub. For instance, in a 2 - # hub system, this could return [{1:'ab', 2:'cd'}, {1:'jkl', 2:'xyz'}] - # where 'ab' and 'cd' are the phone serial numbers and 'jkl' and 'xyz' - # are the BattOr serial numbers. - port_to_serial = find_usb_devices.GetAllPhysicalPortToSerialMaps( - hub_types, device_tree_map=devtree) - - class serials(object): - def __init__(self): - self.phone = None - self.battor = None - - # Map of {physical port number: [phone serial #, BattOr serial #]. This - # map is populated by executing the code below. For instance, in the above - # example, after the code below is executed, port_to_devices would equal - # {1: ['ab', 'jkl'], 2: ['cd', 'xyz']} - port_to_devices = collections.defaultdict(serials) - for hub in port_to_serial: - for (port, serial) in hub.iteritems(): - if serial in battor_serials: - if port_to_devices[port].battor is not None: - raise battor_error.BattOrError('Multiple BattOrs on same port number') - else: - port_to_devices[port].battor = serial - else: - if port_to_devices[port].phone is not None: - raise battor_error.BattOrError('Multiple phones on same port number') - else: - port_to_devices[port].phone = serial - - # Turn the port_to_devices map into a map of the form - # {phone serial number: BattOr serial number}. - result = {} - for pair in port_to_devices.values(): - if pair.phone is None: - continue - if pair.battor is None: - raise battor_error.BattOrError( - 'Phone detected with no corresponding BattOr') - result[pair.phone] = pair.battor - return result - -def GenerateSerialMapFile(filename, hub_types=None): - """Generates a serial map file and writes it.""" - WriteSerialMapFile(filename, GenerateSerialMap(hub_types)) - -def _PhoneToPathMap(serial, serial_map, devtree): - """Maps phone serial number to TTY path, assuming serial map is provided.""" - try: - battor_serial = serial_map[serial] - except KeyError: - raise battor_error.BattOrError('Serial number not found in serial map.') - for tree in devtree.values(): - for node in tree.AllNodes(): - if isinstance(node, find_usb_devices.USBDeviceNode): - if node.serial == battor_serial: - bus_device_to_tty = find_usb_devices.GetBusDeviceToTTYMap() - bus_device = (node.bus_num, node.device_num) - try: - return bus_device_to_tty[bus_device] - except KeyError: - raise battor_error.BattOrError( - 'Device with given serial number not a BattOr ' - '(does not have TTY path)') - - -def GetBattOrPathFromPhoneSerial(serial, serial_map=None, - serial_map_file=None): - """Gets the TTY path (e.g. '/dev/ttyUSB0') to communicate with the BattOr. - - (1) If serial_map is given, it is treated as a dictionary mapping - phone serial numbers to BattOr serial numbers. This function will get the - TTY path for the given BattOr serial number. - - (2) If serial_map_file is given, it is treated as the name of a - phone-to-BattOr mapping file (generated with GenerateSerialMapFile) - and this will be loaded and used as the dict to map port numbers to - BattOr serial numbers. - - You can only give one of serial_map and serial_map_file. - - Args: - serial: Serial number of phone connected on the same physical port that - the BattOr is connected to. - serial_map: Map of phone serial numbers to BattOr serial numbers, given - as a dictionary. - serial_map_file: Map of phone serial numbers to BattOr serial numbers, - given as a file. - hub_types: List of hub types to check for. Used only if serial_map_file - is None. - - Returns: - Device string used to communicate with device. - - Raises: - ValueError: If serial number is not given. - BattOrError: If BattOr not found or unexpected USB topology. - """ - # If there's only one BattOr connected to the system, just use that one. - # This allows for use on, e.g., a developer's workstation with no hubs. - devtree = find_usb_devices.GetBusNumberToDeviceTreeMap() - all_battors = GetBattOrList(devtree) - if len(all_battors) == 1: - return '/dev/' + all_battors[0] - - if not serial: - raise battor_error.BattOrError( - 'Two or more BattOrs connected, no serial provided') - - if serial_map and serial_map_file: - raise ValueError('Cannot specify both serial_map and serial_map_file') - - if serial_map_file: - serial_map = ReadSerialMapFile(serial_map_file) - - tty_string = _PhoneToPathMap(serial, serial_map, devtree) - - if not tty_string: - raise battor_error.BattOrError( - 'No device with given serial number detected.') - - if IsBattOr(tty_string, devtree): - return '/dev/' + tty_string - else: - raise battor_error.BattOrError( - 'Device with given serial number is not a BattOr.') - -if __name__ == '__main__': - # Main function for testing purposes - print GenerateSerialMap() |