Dennis Kempin | 1a8a5be | 2013-06-18 11:00:02 -0700 | [diff] [blame] | 1 | # Copyright (c) 2013 The Chromium OS Authors. All rights reserved. |
Dennis Kempin | 037675e | 2013-06-14 14:12:39 -0700 | [diff] [blame] | 2 | # Use of this source code is governed by a BSD-style license that can be |
| 3 | # found in the LICENSE file. |
| 4 | # |
Dennis Kempin | 58d9a74 | 2014-05-08 18:34:59 -0700 | [diff] [blame] | 5 | """ This module manages the platform properties in mttools/platforms. """ |
| 6 | from cros_remote import CrOSRemote |
| 7 | from util import AskUser |
| 8 | from xorg_conf import XorgInputClassParser |
Amirhossein Simjour | 9127ff1 | 2015-03-11 15:47:14 -0400 | [diff] [blame] | 9 | from util import ExecuteException |
Dennis Kempin | 1a8a5be | 2013-06-18 11:00:02 -0700 | [diff] [blame] | 10 | import json |
Dennis Kempin | 037675e | 2013-06-14 14:12:39 -0700 | [diff] [blame] | 11 | import os |
| 12 | import re |
Dennis Kempin | 1a8a5be | 2013-06-18 11:00:02 -0700 | [diff] [blame] | 13 | import sys |
Dennis Kempin | 037675e | 2013-06-14 14:12:39 -0700 | [diff] [blame] | 14 | |
| 15 | # path to current script directory |
| 16 | script_dir = os.path.dirname(os.path.realpath(__file__)) |
Dennis Kempin | 17766a6 | 2013-06-17 14:09:33 -0700 | [diff] [blame] | 17 | platforms_dir = os.path.realpath(os.path.join(script_dir, '..', 'platforms')) |
Chung-yih Wang | 35613f1 | 2014-04-25 13:57:23 +0800 | [diff] [blame] | 18 | xorg_conf_project_path = 'src/platform/xorg-conf' |
Dennis Kempin | 037675e | 2013-06-14 14:12:39 -0700 | [diff] [blame] | 19 | |
Dennis Kempin | d0b722a | 2014-04-15 11:54:48 -0700 | [diff] [blame] | 20 | props_template = """\ |
| 21 | { |
| 22 | "gestures": { |
| 23 | }, |
| 24 | "xorg": { |
| 25 | "file": "%s", |
| 26 | "identifiers": %s |
| 27 | }, |
| 28 | "ignore": [ |
| 29 | ] |
| 30 | }""" |
| 31 | |
Dennis Kempin | 037675e | 2013-06-14 14:12:39 -0700 | [diff] [blame] | 32 | class PlatformProperties(object): |
Dennis Kempin | 17766a6 | 2013-06-17 14:09:33 -0700 | [diff] [blame] | 33 | """ A class containing hardware and xorg properties for a platform. |
| 34 | |
| 35 | The class can be created from an activity log or by providing |
| 36 | the name of the platform. Information will then be read from the |
| 37 | 'platforms_dir' directory. |
Dennis Kempin | 037675e | 2013-06-14 14:12:39 -0700 | [diff] [blame] | 38 | """ |
Dennis Kempin | 1a8a5be | 2013-06-18 11:00:02 -0700 | [diff] [blame] | 39 | def __init__(self, platform=None, log=None): |
| 40 | self.required_axis = [] |
| 41 | self.has_axis = [] |
| 42 | self.device_class = "touchpad" |
Dennis Kempin | 58d9a74 | 2014-05-08 18:34:59 -0700 | [diff] [blame] | 43 | self.properties = {} |
| 44 | self.ignore_properties = [] |
Dennis Kempin | 037675e | 2013-06-14 14:12:39 -0700 | [diff] [blame] | 45 | if platform: |
| 46 | basename = os.path.join(platforms_dir, platform) |
| 47 | self.name = platform |
Dennis Kempin | 17766a6 | 2013-06-17 14:09:33 -0700 | [diff] [blame] | 48 | self.hwprops_file = basename + '.hwprops' |
| 49 | self.props_file = basename + '.props' |
Dennis Kempin | 037675e | 2013-06-14 14:12:39 -0700 | [diff] [blame] | 50 | self.xorg_parser = XorgInputClassParser() |
| 51 | self._ParseHWProperties(open(self.hwprops_file).read()) |
| 52 | self._ParseProperties(open(self.props_file).read()) |
| 53 | self._UpdateDimensions() |
Dennis Kempin | 1a8a5be | 2013-06-18 11:00:02 -0700 | [diff] [blame] | 54 | elif log: |
Dennis Kempin | 17766a6 | 2013-06-17 14:09:33 -0700 | [diff] [blame] | 55 | self.name = '' |
Dennis Kempin | 1a8a5be | 2013-06-18 11:00:02 -0700 | [diff] [blame] | 56 | if log.evdev: |
| 57 | self._ParseEvdevLog(log.evdev) |
Dennis Kempin | cd7caba | 2014-04-16 13:37:18 -0700 | [diff] [blame] | 58 | self._ParseActivityLog(log.activity) |
| 59 | |
Dennis Kempin | 037675e | 2013-06-14 14:12:39 -0700 | [diff] [blame] | 60 | |
| 61 | def _ParseActivityLog(self, activity_data): |
Dennis Kempin | 58d9a74 | 2014-05-08 18:34:59 -0700 | [diff] [blame] | 62 | """ Parse property information from an activity log.""" |
Dennis Kempin | 037675e | 2013-06-14 14:12:39 -0700 | [diff] [blame] | 63 | activity = json.loads(activity_data) |
Dennis Kempin | 17766a6 | 2013-06-17 14:09:33 -0700 | [diff] [blame] | 64 | self.properties = activity['properties'] |
Dennis Kempin | 037675e | 2013-06-14 14:12:39 -0700 | [diff] [blame] | 65 | |
Dennis Kempin | 17766a6 | 2013-06-17 14:09:33 -0700 | [diff] [blame] | 66 | hwprops = activity['hardwareProperties'] |
| 67 | self.x_min = int(hwprops['left']) |
| 68 | self.x_max = int(hwprops['right']) |
| 69 | self.x_res = int(hwprops['xResolution']) |
| 70 | self.y_min = int(hwprops['top']) |
| 71 | self.y_max = int(hwprops['bottom']) |
| 72 | self.y_res = int(hwprops['yResolution']) |
Dennis Kempin | 037675e | 2013-06-14 14:12:39 -0700 | [diff] [blame] | 73 | |
Dennis Kempin | 1a8a5be | 2013-06-18 11:00:02 -0700 | [diff] [blame] | 74 | def _ParseEvdevLog(self, evdev_data): |
Dennis Kempin | 143ef16 | 2014-04-09 13:46:50 -0700 | [diff] [blame] | 75 | # Look for embedded hwproperties in header. Format: |
| 76 | # absinfo: axis min max 0 0 res |
Andrew de los Reyes | a29db69 | 2014-07-29 10:00:27 -0700 | [diff] [blame] | 77 | abs_regex = 5 * ' ([-0-9]+)' |
Dennis Kempin | 143ef16 | 2014-04-09 13:46:50 -0700 | [diff] [blame] | 78 | xregex = re.compile('# absinfo: 53' + abs_regex) |
Dennis Kempin | 58d9a74 | 2014-05-08 18:34:59 -0700 | [diff] [blame] | 79 | xmatch = xregex.search(evdev_data) |
Dennis Kempin | 143ef16 | 2014-04-09 13:46:50 -0700 | [diff] [blame] | 80 | self.x_min = int(xmatch.group(1)) |
| 81 | self.x_max = int(xmatch.group(2)) |
| 82 | self.x_res = int(xmatch.group(5)) |
| 83 | |
| 84 | yregex = re.compile('# absinfo: 54' + abs_regex) |
Dennis Kempin | 58d9a74 | 2014-05-08 18:34:59 -0700 | [diff] [blame] | 85 | ymatch = yregex.search(evdev_data) |
Dennis Kempin | 143ef16 | 2014-04-09 13:46:50 -0700 | [diff] [blame] | 86 | self.y_min = int(ymatch.group(1)) |
| 87 | self.y_max = int(ymatch.group(2)) |
| 88 | self.y_res = int(ymatch.group(5)) |
| 89 | |
| 90 | axis_regex = re.compile('# absinfo: ([0-9]+)') |
| 91 | for match in axis_regex.finditer(evdev_data): |
| 92 | self.has_axis.append(int(match.group(1))) |
| 93 | |
| 94 | # look for axes used in the log itself. |
Dennis Kempin | 1a8a5be | 2013-06-18 11:00:02 -0700 | [diff] [blame] | 95 | # The format of ABS (0003) reports is: |
| 96 | # timestamp 0003 axis value |
| 97 | report_regex = re.compile(' 0003 ([0-9a-f]{4}) ([0-9a-f]+)') |
| 98 | for match in report_regex.finditer(evdev_data): |
| 99 | axis = int(match.group(1), 16) |
| 100 | if axis not in self.required_axis: |
| 101 | self.required_axis.append(axis) |
| 102 | |
Dennis Kempin | 143ef16 | 2014-04-09 13:46:50 -0700 | [diff] [blame] | 103 | |
Dennis Kempin | 037675e | 2013-06-14 14:12:39 -0700 | [diff] [blame] | 104 | def _ParseHWProperties(self, data): |
Dennis Kempin | 58d9a74 | 2014-05-08 18:34:59 -0700 | [diff] [blame] | 105 | """Parse x and y dimensions and resolution from hwprops file.""" |
| 106 | abs_regex = 5 * ' ([0-9\\-]+)' |
Dennis Kempin | 143ef16 | 2014-04-09 13:46:50 -0700 | [diff] [blame] | 107 | xregex = re.compile('A: 35' + abs_regex) |
Dennis Kempin | 58d9a74 | 2014-05-08 18:34:59 -0700 | [diff] [blame] | 108 | xmatch = xregex.search(data) |
Dennis Kempin | 037675e | 2013-06-14 14:12:39 -0700 | [diff] [blame] | 109 | self.x_min = int(xmatch.group(1)) |
| 110 | self.x_max = int(xmatch.group(2)) |
| 111 | self.x_res = int(xmatch.group(5)) |
| 112 | |
Dennis Kempin | 143ef16 | 2014-04-09 13:46:50 -0700 | [diff] [blame] | 113 | yregex = re.compile('A: 36' + abs_regex) |
Dennis Kempin | 58d9a74 | 2014-05-08 18:34:59 -0700 | [diff] [blame] | 114 | ymatch = yregex.search(data) |
Dennis Kempin | 037675e | 2013-06-14 14:12:39 -0700 | [diff] [blame] | 115 | self.y_min = int(ymatch.group(1)) |
| 116 | self.y_max = int(ymatch.group(2)) |
| 117 | self.y_res = int(ymatch.group(5)) |
| 118 | |
Dennis Kempin | 1a8a5be | 2013-06-18 11:00:02 -0700 | [diff] [blame] | 119 | axis_regex = re.compile('A: ([0-9a-f]+)') |
| 120 | for match in axis_regex.finditer(data): |
| 121 | self.has_axis.append(int(match.group(1), 16)) |
| 122 | |
Dennis Kempin | 037675e | 2013-06-14 14:12:39 -0700 | [diff] [blame] | 123 | def _ParseProperties(self, data): |
Dennis Kempin | 17766a6 | 2013-06-17 14:09:33 -0700 | [diff] [blame] | 124 | """ Parse properties from file and inject xorg properties. """ |
Dennis Kempin | 037675e | 2013-06-14 14:12:39 -0700 | [diff] [blame] | 125 | self.properties = {} |
Dennis Kempin | 1a8a5be | 2013-06-18 11:00:02 -0700 | [diff] [blame] | 126 | self.ignore_properties = [] |
Dennis Kempin | 037675e | 2013-06-14 14:12:39 -0700 | [diff] [blame] | 127 | data = json.loads(data) |
| 128 | |
Dennis Kempin | 17766a6 | 2013-06-17 14:09:33 -0700 | [diff] [blame] | 129 | if 'gestures' in data: |
| 130 | self.properties.update(data['gestures']) |
Dennis Kempin | 037675e | 2013-06-14 14:12:39 -0700 | [diff] [blame] | 131 | |
Dennis Kempin | 17766a6 | 2013-06-17 14:09:33 -0700 | [diff] [blame] | 132 | if 'device_class' in data: |
| 133 | self.device_class = data['device_class'] |
Dennis Kempin | 037675e | 2013-06-14 14:12:39 -0700 | [diff] [blame] | 134 | |
Dennis Kempin | 1a8a5be | 2013-06-18 11:00:02 -0700 | [diff] [blame] | 135 | if 'ignore' in data: |
| 136 | self.ignore_properties.extend(data['ignore']) |
| 137 | |
Chung-yih Wang | 35613f1 | 2014-04-25 13:57:23 +0800 | [diff] [blame] | 138 | # Sanity check: Make sure it is not used inside ebuild. |
| 139 | if os.environ.get('PN') and os.environ.get('S'): |
| 140 | raise Exception("Should not be executed inside ebuild") |
| 141 | |
| 142 | # If run on a Chromebook device, access xorg-conf files from their normal |
| 143 | # installed location. If run from inside chroot, access xorg-conf files |
| 144 | # from the xorg-conf project repository. |
| 145 | src_root = os.environ.get('CROS_WORKON_SRCROOT') |
| 146 | if src_root: |
| 147 | xorg_conf_path = os.path.join(src_root, xorg_conf_project_path) |
| 148 | else: |
Andrew de los Reyes | c012597 | 2015-01-28 10:04:44 -0800 | [diff] [blame] | 149 | xorg_conf_path = '/etc/gesture' |
| 150 | if not os.path.exists(xorg_conf_path): |
| 151 | xorg_conf_path = '/etc/X11/xorg.conf.d' |
Chung-yih Wang | 35613f1 | 2014-04-25 13:57:23 +0800 | [diff] [blame] | 152 | |
Dennis Kempin | 17766a6 | 2013-06-17 14:09:33 -0700 | [diff] [blame] | 153 | if xorg_conf_path and 'xorg' in data and 'file' in data['xorg']: |
| 154 | filename = os.path.join(xorg_conf_path, data['xorg']['file']) |
Dennis Kempin | 037675e | 2013-06-14 14:12:39 -0700 | [diff] [blame] | 155 | input_classes = self.xorg_parser.Parse(file=filename) |
Dennis Kempin | 17766a6 | 2013-06-17 14:09:33 -0700 | [diff] [blame] | 156 | if 'identifier' in data['xorg']: |
| 157 | properties = input_classes[data['xorg']['identifier']] |
Dennis Kempin | 037675e | 2013-06-14 14:12:39 -0700 | [diff] [blame] | 158 | self.properties.update(properties) |
Dennis Kempin | 17766a6 | 2013-06-17 14:09:33 -0700 | [diff] [blame] | 159 | if 'identifiers' in data['xorg']: |
| 160 | for identifier in data['xorg']['identifiers']: |
Dennis Kempin | 037675e | 2013-06-14 14:12:39 -0700 | [diff] [blame] | 161 | properties = input_classes[identifier] |
| 162 | self.properties.update(properties) |
| 163 | |
Dennis Kempin | 1a8a5be | 2013-06-18 11:00:02 -0700 | [diff] [blame] | 164 | for prop in self.ignore_properties: |
| 165 | if prop in self.properties: |
| 166 | del self.properties[prop] |
| 167 | |
Dennis Kempin | 037675e | 2013-06-14 14:12:39 -0700 | [diff] [blame] | 168 | def _UpdateDimensions(self): |
Dennis Kempin | 17766a6 | 2013-06-17 14:09:33 -0700 | [diff] [blame] | 169 | """ Update x/y min/max with xorg properties. |
| 170 | |
| 171 | CMT allows hardware properties to be overwritten by xorg properties. |
| 172 | Do the same in this class. |
Dennis Kempin | 037675e | 2013-06-14 14:12:39 -0700 | [diff] [blame] | 173 | """ |
Dennis Kempin | 17766a6 | 2013-06-17 14:09:33 -0700 | [diff] [blame] | 174 | if 'Active Area Left' in self.properties: |
| 175 | self.x_min = int(self.properties['Active Area Left']) |
| 176 | if 'Active Area Right' in self.properties: |
| 177 | self.x_max = int(self.properties['Active Area Right']) |
Dennis Kempin | 17766a6 | 2013-06-17 14:09:33 -0700 | [diff] [blame] | 178 | if 'Active Area Top' in self.properties: |
| 179 | self.y_min = int(self.properties['Active Area Top']) |
| 180 | if 'Active Area Bottom' in self.properties: |
| 181 | self.y_max = int(self.properties['Active Area Bottom']) |
Dennis Kempin | 55af9cc | 2013-06-20 15:07:21 -0700 | [diff] [blame] | 182 | |
| 183 | if 'Horizontal Resolution' in self.properties: |
| 184 | self.x_res = int(self.properties['Horizontal Resolution']) |
Dennis Kempin | 17766a6 | 2013-06-17 14:09:33 -0700 | [diff] [blame] | 185 | if 'Vertical Resolution' in self.properties: |
| 186 | self.y_res = int(self.properties['Vertical Resolution']) |
Dennis Kempin | 037675e | 2013-06-14 14:12:39 -0700 | [diff] [blame] | 187 | |
Dennis Kempin | 55af9cc | 2013-06-20 15:07:21 -0700 | [diff] [blame] | 188 | if 'SemiMT Non Linear Area Left' in self.properties: |
| 189 | self.x_min = int(self.properties['SemiMT Non Linear Area Left']) |
| 190 | if 'SemiMT Non Linear Area Right' in self.properties: |
| 191 | self.x_max = int(self.properties['SemiMT Non Linear Area Right']) |
| 192 | if 'SemiMT Non Linear Area Top' in self.properties: |
| 193 | self.y_min = int(self.properties['SemiMT Non Linear Area Top']) |
| 194 | if 'SemiMT Non Linear Area Bottom' in self.properties: |
| 195 | self.y_max = int(self.properties['SemiMT Non Linear Area Bottom']) |
| 196 | |
| 197 | |
| 198 | def Match(self, other, loose, debug=False): |
Dennis Kempin | 17766a6 | 2013-06-17 14:09:33 -0700 | [diff] [blame] | 199 | """ Compare properties and return similarity. |
| 200 | |
| 201 | Compare these properties to another PlatformProperties instance. |
| 202 | The return value is a score between 1. 0 meaning there is a big mismatch |
| 203 | and 1 meaning the properties match completely. |
| 204 | Only a selected range of properties are compared in order to |
| 205 | prevent property adjustments to cause platforms to be mismatched. |
Dennis Kempin | 037675e | 2013-06-14 14:12:39 -0700 | [diff] [blame] | 206 | """ |
| 207 | scores = [] |
| 208 | def compare(a, b, what): |
| 209 | value = abs(float(a) - float(b)) |
| 210 | if value > 0: |
Dennis Kempin | 1a8a5be | 2013-06-18 11:00:02 -0700 | [diff] [blame] | 211 | value = min(1, value / max(abs(float(a)), abs(float(b)))) |
Dennis Kempin | 037675e | 2013-06-14 14:12:39 -0700 | [diff] [blame] | 212 | scores.append(1-value) |
Dennis Kempin | 1a8a5be | 2013-06-18 11:00:02 -0700 | [diff] [blame] | 213 | if debug: |
| 214 | print "%s: %s == %s" % (what, str(a), str(b)) |
Dennis Kempin | 037675e | 2013-06-14 14:12:39 -0700 | [diff] [blame] | 215 | def compare_attr(what): |
| 216 | compare(getattr(self, what), getattr(other, what), what) |
| 217 | def compare_prop(what): |
| 218 | if what not in self.properties or what not in other.properties: |
Dennis Kempin | 1a8a5be | 2013-06-18 11:00:02 -0700 | [diff] [blame] | 219 | scores.append(0) |
| 220 | else: |
| 221 | compare(self.properties[what], other.properties[what], what) |
| 222 | def check_axis(required, available): |
| 223 | for axis in required: |
| 224 | if axis not in available: |
| 225 | scores.append(0) |
| 226 | return |
| 227 | |
Dennis Kempin | 17766a6 | 2013-06-17 14:09:33 -0700 | [diff] [blame] | 228 | compare_attr('x_min') |
| 229 | compare_attr('x_max') |
| 230 | compare_attr('x_res') |
Dennis Kempin | 55af9cc | 2013-06-20 15:07:21 -0700 | [diff] [blame] | 231 | compare_attr('y_min') |
| 232 | compare_attr('y_max') |
| 233 | compare_attr('y_res') |
| 234 | if not loose: |
| 235 | compare_prop('Pressure Calibration Offset') |
Dennis Kempin | 1a8a5be | 2013-06-18 11:00:02 -0700 | [diff] [blame] | 236 | |
| 237 | if self.required_axis: |
| 238 | if debug: |
| 239 | print "axis:", self.required_axis, "in", other.has_axis |
| 240 | check_axis(self.required_axis, other.has_axis) |
| 241 | |
| 242 | if other.required_axis: |
| 243 | if debug: |
| 244 | print "axis:", other.required_axis, "in", self.has_axis |
| 245 | check_axis(other.required_axis, self.has_axis) |
| 246 | |
Dennis Kempin | 58d9a74 | 2014-05-08 18:34:59 -0700 | [diff] [blame] | 247 | return reduce(lambda x, y: (x * y), scores) |
Dennis Kempin | 037675e | 2013-06-14 14:12:39 -0700 | [diff] [blame] | 248 | |
| 249 | class PlatformDatabase(object): |
Dennis Kempin | 17766a6 | 2013-06-17 14:09:33 -0700 | [diff] [blame] | 250 | """ Class for managing platforms. |
| 251 | |
| 252 | This class reads all available platforms from the platforms_dir and allows |
| 253 | to search for matching platforms to an activity log file. |
Dennis Kempin | 037675e | 2013-06-14 14:12:39 -0700 | [diff] [blame] | 254 | """ |
| 255 | def __init__(self): |
Dennis Kempin | 58d9a74 | 2014-05-08 18:34:59 -0700 | [diff] [blame] | 256 | platform_files = [f for f in os.listdir(platforms_dir) |
| 257 | if f.endswith('.hwprops')] |
Dennis Kempin | 037675e | 2013-06-14 14:12:39 -0700 | [diff] [blame] | 258 | self.platforms = {} |
Dennis Kempin | 58d9a74 | 2014-05-08 18:34:59 -0700 | [diff] [blame] | 259 | for filename in platform_files: |
| 260 | name = filename.replace('.hwprops', '') |
Dennis Kempin | 037675e | 2013-06-14 14:12:39 -0700 | [diff] [blame] | 261 | self.platforms[name] = PlatformProperties(platform=name) |
| 262 | |
Dennis Kempin | 55af9cc | 2013-06-20 15:07:21 -0700 | [diff] [blame] | 263 | def FindMatching(self, log, loose=True, debug=False): |
Dennis Kempin | 17766a6 | 2013-06-17 14:09:33 -0700 | [diff] [blame] | 264 | """ Find platform matching activity_data. |
| 265 | |
| 266 | Returns the PlatformProperties instance of the platform matching |
| 267 | the activity log data. This method might terminate the program in |
| 268 | case no match can be made, or the match is ambiguous. |
Dennis Kempin | 037675e | 2013-06-14 14:12:39 -0700 | [diff] [blame] | 269 | """ |
| 270 | result = None |
Dennis Kempin | 1a8a5be | 2013-06-18 11:00:02 -0700 | [diff] [blame] | 271 | properties = PlatformProperties(log=log) |
Dennis Kempin | 037675e | 2013-06-14 14:12:39 -0700 | [diff] [blame] | 272 | for name, platform in self.platforms.items(): |
Dennis Kempin | 1a8a5be | 2013-06-18 11:00:02 -0700 | [diff] [blame] | 273 | if debug: |
| 274 | print "#" * 10, name |
Dennis Kempin | 55af9cc | 2013-06-20 15:07:21 -0700 | [diff] [blame] | 275 | score = platform.Match(properties, loose, debug) |
Dennis Kempin | 1a8a5be | 2013-06-18 11:00:02 -0700 | [diff] [blame] | 276 | if debug: |
| 277 | print name, "score =", score |
Andrew de los Reyes | f56af27 | 2014-07-21 14:32:21 -0700 | [diff] [blame] | 278 | if score > 0.96: |
Dennis Kempin | 037675e | 2013-06-14 14:12:39 -0700 | [diff] [blame] | 279 | if result: |
Dennis Kempin | 55af9cc | 2013-06-20 15:07:21 -0700 | [diff] [blame] | 280 | if loose: |
| 281 | if debug: |
| 282 | print "-" * 10, "Multiple matches. Try strict" |
| 283 | return self.FindMatching(log, False, debug) |
Dennis Kempin | 17766a6 | 2013-06-17 14:09:33 -0700 | [diff] [blame] | 284 | print ('multiple matching platforms:', result.name, |
| 285 | 'and', platform.name) |
Dennis Kempin | 19e972b | 2013-06-20 13:21:38 -0700 | [diff] [blame] | 286 | return None |
Dennis Kempin | 037675e | 2013-06-14 14:12:39 -0700 | [diff] [blame] | 287 | result = platform |
| 288 | if not result: |
Dennis Kempin | 17766a6 | 2013-06-17 14:09:33 -0700 | [diff] [blame] | 289 | print 'cannot find matching platform' |
Dennis Kempin | 19e972b | 2013-06-20 13:21:38 -0700 | [diff] [blame] | 290 | return None |
Dennis Kempin | 037675e | 2013-06-14 14:12:39 -0700 | [diff] [blame] | 291 | return result |
Dennis Kempin | d0b722a | 2014-04-15 11:54:48 -0700 | [diff] [blame] | 292 | |
| 293 | @staticmethod |
| 294 | def RegisterPlatformFromDevice(ip): |
| 295 | # get list of multitouch devices |
| 296 | remote = CrOSRemote(ip) |
Amirhossein Simjour | 9127ff1 | 2015-03-11 15:47:14 -0400 | [diff] [blame] | 297 | inputcontrolexist = True |
| 298 | try: |
| 299 | devices = remote.SafeExecute( |
| 300 | "/opt/google/input/inputcontrol -t multitouch --names", |
| 301 | verbose=True) |
| 302 | except ExecuteException: |
| 303 | inputcontrolexist = False |
| 304 | if inputcontrolexist: |
| 305 | # Each line has the format: |
| 306 | # id: Device Name |
| 307 | # devices[*][0] will have the id |
| 308 | # devices[*][1] will have the name |
| 309 | devices = devices.splitlines() |
| 310 | devices = [l.split(":", 1) for l in devices] |
Dennis Kempin | d0b722a | 2014-04-15 11:54:48 -0700 | [diff] [blame] | 311 | |
Amirhossein Simjour | 9127ff1 | 2015-03-11 15:47:14 -0400 | [diff] [blame] | 312 | # select one device from list |
| 313 | idx = AskUser.Select([d[1] for d in devices], |
| 314 | "Which device would you like to register?") |
| 315 | device_id = devices[idx][0] |
Dennis Kempin | d0b722a | 2014-04-15 11:54:48 -0700 | [diff] [blame] | 316 | |
Amirhossein Simjour | 9127ff1 | 2015-03-11 15:47:14 -0400 | [diff] [blame] | 317 | # read hardware properties |
| 318 | hwprops = remote.SafeExecute( |
| 319 | "/opt/google/input/inputcontrol --id %s --hwprops" % device_id, |
| 320 | verbose=True) |
| 321 | else: |
| 322 | devices = remote.SafeExecute( |
| 323 | "ls /dev/input/ | grep event", |
| 324 | verbose=True) |
| 325 | devices = devices.splitlines() |
| 326 | touchdevices = [] |
| 327 | for d in devices: |
| 328 | device_desc_evemu = remote.SafeExecute( |
| 329 | "evemu-describe /dev/input/%s |grep N:" % d, |
| 330 | verbose=False) |
| 331 | event_number = (d.split("event", 1))[1] |
| 332 | device_desc_evemu = device_desc_evemu.split("N:",1)[1] |
| 333 | if "Touchpad" in device_desc_evemu: |
| 334 | touchdevices.append([event_number, device_desc_evemu]) |
| 335 | |
| 336 | idx = AskUser.Select([t[1] for t in touchdevices], |
| 337 | "Which device would you like to register?") |
| 338 | device_id = touchdevices[idx][0] |
| 339 | hwprops = remote.SafeExecute( |
| 340 | "evemu-describe /dev/input/event%s" % touchdevices[idx][0], |
| 341 | verbose=True) |
Dennis Kempin | d0b722a | 2014-04-15 11:54:48 -0700 | [diff] [blame] | 342 | if not hwprops: |
Amirhossein Simjour | 9127ff1 | 2015-03-11 15:47:14 -0400 | [diff] [blame] | 343 | print "Please update your device to latest canary or:" |
| 344 | print " emerge-${BOARD} inputcontrol" |
| 345 | print " cros deploy $DEVICE_IP inputcontrol" |
| 346 | return None |
| 347 | |
Dennis Kempin | d0b722a | 2014-04-15 11:54:48 -0700 | [diff] [blame] | 348 | |
Dennis Kempin | cd7caba | 2014-04-16 13:37:18 -0700 | [diff] [blame] | 349 | xorg_files = [ |
Dennis Kempin | 58d9a74 | 2014-05-08 18:34:59 -0700 | [diff] [blame] | 350 | "/etc/X11/xorg.conf.d/60-touchpad-cmt-*.conf", |
| 351 | "/etc/X11/xorg.conf.d/50-touchpad-cmt-*.conf", |
Amirhossein Simjour | 9127ff1 | 2015-03-11 15:47:14 -0400 | [diff] [blame] | 352 | "/etc/X11/xorg.conf.d/40-touchpad-cmt.conf", |
| 353 | "/etc/gesture/60-touchpad-cmt-*.conf", |
| 354 | "/etc/gesture/50-touchpad-cmt-*.conf", |
| 355 | "/etc/gesture/40-touchpad-cmt.conf" |
Dennis Kempin | cd7caba | 2014-04-16 13:37:18 -0700 | [diff] [blame] | 356 | ] |
| 357 | |
| 358 | for pattern in xorg_files: |
| 359 | # find filename of xorg configuration file |
Dennis Kempin | 58d9a74 | 2014-05-08 18:34:59 -0700 | [diff] [blame] | 360 | xorg_file = remote.Execute("ls " + pattern, verbose=False) |
Dennis Kempin | cd7caba | 2014-04-16 13:37:18 -0700 | [diff] [blame] | 361 | if not xorg_file: |
| 362 | continue |
| 363 | xorg_file = xorg_file.strip() |
| 364 | |
| 365 | # extract identifiers |
Dennis Kempin | d0b722a | 2014-04-15 11:54:48 -0700 | [diff] [blame] | 366 | print "Selecting Xorg identifiers from", xorg_file |
| 367 | conf = remote.Read(xorg_file) |
Dennis Kempin | cd7caba | 2014-04-16 13:37:18 -0700 | [diff] [blame] | 368 | all_ids = [] |
Dennis Kempin | 58d9a74 | 2014-05-08 18:34:59 -0700 | [diff] [blame] | 369 | for match in re.finditer("Identifier\\s+\"([a-zA-Z0-9-_ ]+)\"", conf): |
Dennis Kempin | cd7caba | 2014-04-16 13:37:18 -0700 | [diff] [blame] | 370 | all_ids.append(match.group(1)) |
Dennis Kempin | d0b722a | 2014-04-15 11:54:48 -0700 | [diff] [blame] | 371 | |
Dennis Kempin | cd7caba | 2014-04-16 13:37:18 -0700 | [diff] [blame] | 372 | # ask user to select |
Dennis Kempin | 58d9a74 | 2014-05-08 18:34:59 -0700 | [diff] [blame] | 373 | idxs = AskUser.SelectMulti( |
| 374 | all_ids, "Which xorg identifiers apply to this device?", |
| 375 | allow_none=True) |
Dennis Kempin | cd7caba | 2014-04-16 13:37:18 -0700 | [diff] [blame] | 376 | ids = [all_ids[i] for i in idxs] |
| 377 | if ids: |
| 378 | break |
Dennis Kempin | d0b722a | 2014-04-15 11:54:48 -0700 | [diff] [blame] | 379 | |
Dennis Kempin | d0b722a | 2014-04-15 11:54:48 -0700 | [diff] [blame] | 380 | if not ids: |
Dennis Kempin | cd7caba | 2014-04-16 13:37:18 -0700 | [diff] [blame] | 381 | print "Please configure the platform properties manually" |
| 382 | xorg_file = "todo: add correct xorg conf file" |
| 383 | ids = ["todo: add correct xorg identifier"] |
Dennis Kempin | d0b722a | 2014-04-15 11:54:48 -0700 | [diff] [blame] | 384 | |
Dennis Kempin | 58d9a74 | 2014-05-08 18:34:59 -0700 | [diff] [blame] | 385 | ids_string = "[" + ", ".join(["\"%s\"" % i for i in ids]) + "]" |
Dennis Kempin | d0b722a | 2014-04-15 11:54:48 -0700 | [diff] [blame] | 386 | xorg_file = os.path.basename(xorg_file) |
| 387 | |
| 388 | sys.stdout.write("Please name this platform: ") |
| 389 | sys.stdout.flush() |
| 390 | platform_name = sys.stdin.readline().strip() |
| 391 | |
| 392 | # write platform info to files |
| 393 | hwprops_file = os.path.join(platforms_dir, platform_name + ".hwprops") |
| 394 | props_file = os.path.join(platforms_dir, platform_name + ".props") |
| 395 | |
| 396 | open(hwprops_file, "w").write(hwprops) |
| 397 | open(props_file, "w").write(props_template % (xorg_file, ids_string)) |
| 398 | |
| 399 | print "Created files: " |
| 400 | print " ", hwprops_file |
| 401 | print " ", props_file |
| 402 | |
| 403 | return platform_name |