1a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik#!/usr/bin/python
2a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik# Copyright 2016 The Chromium Authors. All rights reserved.
3a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik# Use of this source code is governed by a BSD-style license that can be
4a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik# found in the LICENSE file.
5a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
6a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
7a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik'''
8a23c9e9f6fc22fe5611def685e1984062b13b560Chris CraikThis script provides tools to map BattOrs to phones.
9a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
10a23c9e9f6fc22fe5611def685e1984062b13b560Chris CraikPhones are identified by the following string:
11a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
12a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik"Phone serial number" - Serial number of the phone. This can be
13a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craikobtained via 'adb devices' or 'usb-devices', and is not expected
14a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craikto change for a given phone.
15a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
16a23c9e9f6fc22fe5611def685e1984062b13b560Chris CraikBattOrs are identified by the following two strings:
17a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
18a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik"BattOr serial number" - Serial number of the BattOr. This can be
19a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craikobtained via 'usb-devices', and is not expected to change for
20a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craika given BattOr.
21a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
22a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik"BattOr path" - The path of the form '/dev/ttyUSB*' that is used
23a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craikto communicate with the BattOr (the battor_agent binary takes
24a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craikthis BattOr path as a parameter). The BattOr path is frequently
25a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craikreassigned by the OS, most often when the device is disconnected
26a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craikand then reconnected. Thus, the BattOr path cannot be expected
27a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craikto be stable.
28a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
29a23c9e9f6fc22fe5611def685e1984062b13b560Chris CraikIn a typical application, the user will require the BattOr path
30a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craikfor the BattOr that is plugged into a given phone. For instance,
31a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craikthe user will be running tracing on a particular phone, and will
32a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craikneed to know which BattOr path to use to communicate with the BattOr
33a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craikto get the corresponding power trace.
34a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
35a23c9e9f6fc22fe5611def685e1984062b13b560Chris CraikGetting this mapping requires two steps: (1) determining the
36a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craikmapping between phone serial numbers and BattOr serial numbers, and
37a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik(2) getting the BattOr path corresponding to a given BattOr serial
38a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craiknumber.
39a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
40a23c9e9f6fc22fe5611def685e1984062b13b560Chris CraikFor step (1), we generate a JSON file giving this mapping. This
41a23c9e9f6fc22fe5611def685e1984062b13b560Chris CraikJSON file consists of a list of items of the following form:
42a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik[{'phone': <phone serial 1>, 'battor': <battor serial 1>},
43a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik{'phone': <phone serial 2>, 'battor': <battor serial 2>}, ...]
44a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
45a23c9e9f6fc22fe5611def685e1984062b13b560Chris CraikThe default way to generate this JSON file is using the function
46a23c9e9f6fc22fe5611def685e1984062b13b560Chris CraikGenerateSerialMapFile, which generates a mapping based on assuming
47a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craikthat the system has two identical USB hubs connected to it, and
48a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craikthe phone plugged into physical port number 1 on one hub corresponds
49a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craikto the BattOr plugged into physical port number 1 on the other hub,
50a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craikand similarly with physical port numbers 2, 3, etc. This generates
51a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craikthe map file based on the structure at the time GenerateSerialMapFile called.
52a23c9e9f6fc22fe5611def685e1984062b13b560Chris CraikNote that after the map file is generated, port numbers are no longer used;
53a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craikthe user could move around the devices in the ports without affecting
54a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craikwhich phone goes with which BattOr. (Thus, if the user wanted to update the
55a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craikmapping to match the new port connections, the user would have to
56a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craikre-generate this file.)
57a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
58a23c9e9f6fc22fe5611def685e1984062b13b560Chris CraikThe script update_mapping.py will do this updating from the command line.
59a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
60a23c9e9f6fc22fe5611def685e1984062b13b560Chris CraikIf the user wanted to specify a custom mapping, the user could instead
61a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craikcreate the JSON file manually. (In this case, hubs would not be necessary
62a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craikand the physical ports connected would be irrelevant.)
63a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
64ee838d1c4002134ff5af32da272140586c4d31deJohn ReckStep (2) is conducted through the function GetBattOrPathFromPhoneSerial,
65a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craikwhich takes a serial number mapping generated via step (1) and a phone
66a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craikserial number, then gets the corresponding BattOr serial number from the
67a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craikmap and determines its BattOr path (e.g. /dev/ttyUSB0). Since BattOr paths
68a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craikcan change if devices are connected and disconnected (even if connected
69a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craikor disconnected via the same port) this function should be called to
70a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craikdetermine the BattOr path every time before connecting to the BattOr.
71a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
72a23c9e9f6fc22fe5611def685e1984062b13b560Chris CraikNote that if there is only one BattOr connected to the system, then
73ee838d1c4002134ff5af32da272140586c4d31deJohn ReckGetBattOrPathFromPhoneSerial will always return that BattOr and will ignore
74a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craikthe mapping file. Thus, if the user never has more than one BattOr connected
75a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craikto the system, the user will not need to generate mapping files.
76a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik'''
77a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
78a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
79a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craikimport json
80a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craikimport collections
81a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
82a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craikfrom battor import battor_error
83a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craikfrom devil.utils import find_usb_devices
84a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craikfrom devil.utils import usb_hubs
85a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
86a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
87ee838d1c4002134ff5af32da272140586c4d31deJohn Reckdef GetBattOrList(device_tree_map):
88a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  return [x for x in find_usb_devices.GetTTYList()
89ee838d1c4002134ff5af32da272140586c4d31deJohn Reck          if IsBattOr(x, device_tree_map)]
90a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
91a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
92ee838d1c4002134ff5af32da272140586c4d31deJohn Reckdef IsBattOr(tty_string, device_tree_map):
93a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  (bus, device) = find_usb_devices.GetBusDeviceFromTTY(tty_string)
94a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  node = device_tree_map[bus].FindDeviceNumber(device)
95a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  return '0403:6001' in node.desc
96a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
97a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
98ee838d1c4002134ff5af32da272140586c4d31deJohn Reckdef GetBattOrSerialNumbers(device_tree_map):
99a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  for x in find_usb_devices.GetTTYList():
100ee838d1c4002134ff5af32da272140586c4d31deJohn Reck    if IsBattOr(x, device_tree_map):
101a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik      (bus, device) = find_usb_devices.GetBusDeviceFromTTY(x)
102a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik      devnode = device_tree_map[bus].FindDeviceNumber(device)
103a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik      yield devnode.serial
104a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
105a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
106a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craikdef ReadSerialMapFile(filename):
107a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  """Reads JSON file giving phone-to-battor serial number map.
108a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
109a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  Parses a JSON file consisting of a list of items of the following form:
110a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  [{'phone': <phone serial 1>, 'battor': <battor serial 1>},
111a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  {'phone': <phone serial 2>, 'battor': <battor serial 2>}, ...]
112a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
113a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  indicating which phone serial numbers should be matched with
114a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  which BattOr serial numbers. Returns dictionary of the form:
115a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
116a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  {<phone serial 1>: <BattOr serial 1>,
117a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik   <phone serial 2>: <BattOr serial 2>}
118a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
119a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  Args:
120a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik      filename: Name of file to read.
121a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  """
122a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  result = {}
123a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  with open(filename, 'r') as infile:
124a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik    in_dict = json.load(infile)
125a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  for x in in_dict:
126a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik    result[x['phone']] = x['battor']
127a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  return result
128a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
129a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craikdef WriteSerialMapFile(filename, serial_map):
130a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  """Writes a map of phone serial numbers to BattOr serial numbers to file.
131a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
132a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  Writes a JSON file consisting of a list of items of the following form:
133a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  [{'phone': <phone serial 1>, 'battor': <battor serial 1>},
134a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  {'phone': <phone serial 2>, 'battor': <battor serial 2>}, ...]
135a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
136a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  indicating which phone serial numbers should be matched with
137a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  which BattOr serial numbers. Mapping is based on the physical port numbers
138a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  of the hubs that the BattOrs and phones are connected to.
139a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
140a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  Args:
141a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik      filename: Name of file to write.
142a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik      serial_map: Serial map {phone: battor}
143a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  """
144a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  result = []
145a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  for (phone, battor) in serial_map.iteritems():
146a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik    result.append({'phone': phone, 'battor': battor})
147a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  with open(filename, 'w') as outfile:
148a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik    json.dump(result, outfile)
149a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
150a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craikdef GenerateSerialMap(hub_types=None):
151a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  """Generates a map of phone serial numbers to BattOr serial numbers.
152a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
153a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  Generates a dict of:
154a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  {<phone serial 1>: <battor serial 1>,
155a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik   <phone serial 2>: <battor serial 2>}
156a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  indicating which phone serial numbers should be matched with
157a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  which BattOr serial numbers. Mapping is based on the physical port numbers
158a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  of the hubs that the BattOrs and phones are connected to.
159a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
160a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  Args:
161a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik      hub_types: List of hub types to check for. If not specified, checks
162a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik      for all defined hub types. (see usb_hubs.py for details)
163a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  """
164a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  if hub_types:
165a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik    hub_types = [usb_hubs.GetHubType(x) for x in hub_types]
166a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  else:
167a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik    hub_types = usb_hubs.ALL_HUBS
168a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
169a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  devtree = find_usb_devices.GetBusNumberToDeviceTreeMap()
170a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
171a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  # List of serial numbers in the system that represent BattOrs.
172ee838d1c4002134ff5af32da272140586c4d31deJohn Reck  battor_serials = list(GetBattOrSerialNumbers(devtree))
173a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
174a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  # If there's only one BattOr in the system, then a serial number ma
175a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  # is not necessary.
176a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  if len(battor_serials) == 1:
177a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik    return {}
178a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
179a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  # List of dictionaries, one for each hub, that maps the physical
180a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  # port number to the serial number of that hub. For instance, in a 2
181a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  # hub system, this could return [{1:'ab', 2:'cd'}, {1:'jkl', 2:'xyz'}]
182a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  # where 'ab' and 'cd' are the phone serial numbers and 'jkl' and 'xyz'
183a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  # are the BattOr serial numbers.
184a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  port_to_serial = find_usb_devices.GetAllPhysicalPortToSerialMaps(
185a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik      hub_types, device_tree_map=devtree)
186a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
187a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  class serials(object):
188a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik    def __init__(self):
189a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik      self.phone = None
190a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik      self.battor = None
191a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
192a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  # Map of {physical port number: [phone serial #, BattOr serial #]. This
193a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  # map is populated by executing the code below. For instance, in the above
194a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  # example, after the code below is executed, port_to_devices would equal
195a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  # {1: ['ab', 'jkl'], 2: ['cd', 'xyz']}
196a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  port_to_devices = collections.defaultdict(serials)
197a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  for hub in port_to_serial:
198a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik    for (port, serial) in hub.iteritems():
199a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik      if serial in battor_serials:
200a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik        if port_to_devices[port].battor is not None:
201ee838d1c4002134ff5af32da272140586c4d31deJohn Reck          raise battor_error.BattOrError('Multiple BattOrs on same port number')
202a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik        else:
203a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik          port_to_devices[port].battor = serial
204a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik      else:
205a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik        if port_to_devices[port].phone is not None:
206ee838d1c4002134ff5af32da272140586c4d31deJohn Reck          raise battor_error.BattOrError('Multiple phones on same port number')
207a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik        else:
208a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik          port_to_devices[port].phone = serial
209a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
210a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  # Turn the port_to_devices map into a map of the form
211a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  # {phone serial number: BattOr serial number}.
212a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  result = {}
213a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  for pair in port_to_devices.values():
214a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik    if pair.phone is None:
215a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik      continue
216a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik    if pair.battor is None:
217ee838d1c4002134ff5af32da272140586c4d31deJohn Reck      raise battor_error.BattOrError(
218a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik          'Phone detected with no corresponding BattOr')
219a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik    result[pair.phone] = pair.battor
220a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  return result
221a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
222a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craikdef GenerateSerialMapFile(filename, hub_types=None):
223a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  """Generates a serial map file and writes it."""
224a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  WriteSerialMapFile(filename, GenerateSerialMap(hub_types))
225a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
226a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craikdef _PhoneToPathMap(serial, serial_map, devtree):
227a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  """Maps phone serial number to TTY path, assuming serial map is provided."""
228a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  try:
229a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik    battor_serial = serial_map[serial]
230a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  except KeyError:
231ee838d1c4002134ff5af32da272140586c4d31deJohn Reck    raise battor_error.BattOrError('Serial number not found in serial map.')
232a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  for tree in devtree.values():
233a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik    for node in tree.AllNodes():
234a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik      if isinstance(node, find_usb_devices.USBDeviceNode):
235a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik        if node.serial == battor_serial:
236a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik          bus_device_to_tty = find_usb_devices.GetBusDeviceToTTYMap()
237a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik          bus_device = (node.bus_num, node.device_num)
238a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik          try:
239a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik            return bus_device_to_tty[bus_device]
240a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik          except KeyError:
241ee838d1c4002134ff5af32da272140586c4d31deJohn Reck            raise battor_error.BattOrError(
242a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik                'Device with given serial number not a BattOr '
243a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik                '(does not have TTY path)')
244a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
245a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
246ee838d1c4002134ff5af32da272140586c4d31deJohn Reckdef GetBattOrPathFromPhoneSerial(serial, serial_map=None,
247a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik                                 serial_map_file=None):
248a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  """Gets the TTY path (e.g. '/dev/ttyUSB0')  to communicate with the BattOr.
249a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
250a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  (1) If serial_map is given, it is treated as a dictionary mapping
251a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  phone serial numbers to BattOr serial numbers. This function will get the
252a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  TTY path for the given BattOr serial number.
253a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
254a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  (2) If serial_map_file is given, it is treated as the name of a
255a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  phone-to-BattOr mapping file (generated with GenerateSerialMapFile)
256a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  and this will be loaded and used as the dict to map port numbers to
257a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  BattOr serial numbers.
258a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
259a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  You can only give one of serial_map and serial_map_file.
260a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
261a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  Args:
262a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik    serial: Serial number of phone connected on the same physical port that
263a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik    the BattOr is connected to.
264a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik    serial_map: Map of phone serial numbers to BattOr serial numbers, given
265a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik    as a dictionary.
266a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik    serial_map_file: Map of phone serial numbers to BattOr serial numbers,
267a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik    given as a file.
268a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik    hub_types: List of hub types to check for. Used only if serial_map_file
269a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik    is None.
270a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
271a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  Returns:
272a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik    Device string used to communicate with device.
273a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
274a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  Raises:
275a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik    ValueError: If serial number is not given.
276ee838d1c4002134ff5af32da272140586c4d31deJohn Reck    BattOrError: If BattOr not found or unexpected USB topology.
277a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  """
278a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  # If there's only one BattOr connected to the system, just use that one.
279a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  # This allows for use on, e.g., a developer's workstation with no hubs.
280a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  devtree = find_usb_devices.GetBusNumberToDeviceTreeMap()
281ee838d1c4002134ff5af32da272140586c4d31deJohn Reck  all_battors = GetBattOrList(devtree)
282a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  if len(all_battors) == 1:
283a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik    return '/dev/' + all_battors[0]
284a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
285a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  if not serial:
286ee838d1c4002134ff5af32da272140586c4d31deJohn Reck    raise battor_error.BattOrError(
287a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik        'Two or more BattOrs connected, no serial provided')
288a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
289a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  if serial_map and serial_map_file:
290a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik    raise ValueError('Cannot specify both serial_map and serial_map_file')
291a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
292a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  if serial_map_file:
293a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik    serial_map = ReadSerialMapFile(serial_map_file)
294a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
295a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  tty_string = _PhoneToPathMap(serial, serial_map, devtree)
296a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
297a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  if not tty_string:
298ee838d1c4002134ff5af32da272140586c4d31deJohn Reck    raise battor_error.BattOrError(
299a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik        'No device with given serial number detected.')
300a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
301ee838d1c4002134ff5af32da272140586c4d31deJohn Reck  if IsBattOr(tty_string, devtree):
302a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik    return '/dev/' + tty_string
303a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  else:
304ee838d1c4002134ff5af32da272140586c4d31deJohn Reck    raise battor_error.BattOrError(
305a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik        'Device with given serial number is not a BattOr.')
306a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik
307a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craikif __name__ == '__main__':
308a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  # Main function for testing purposes
309a23c9e9f6fc22fe5611def685e1984062b13b560Chris Craik  print GenerateSerialMap()
310