blob: 1b88546846a60cf509208526df8af3a39ce41539 [file] [log] [blame]
Dennis Kempin037675e2013-06-14 14:12:39 -07001# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4#
Dennis Kempin17766a62013-06-17 14:09:33 -07005""" This module manages the platform properties in mttools/platforms """
Dennis Kempin037675e2013-06-14 14:12:39 -07006import os
7import re
8import json
9from xorg_conf import XorgInputClassParser
10
11# path to current script directory
12script_dir = os.path.dirname(os.path.realpath(__file__))
Dennis Kempin17766a62013-06-17 14:09:33 -070013platforms_dir = os.path.realpath(os.path.join(script_dir, '..', 'platforms'))
14xorg_conf_path = os.path.realpath(os.path.join(script_dir, '..',
15 '..', 'xorg-conf'))
Dennis Kempin037675e2013-06-14 14:12:39 -070016
17class PlatformProperties(object):
Dennis Kempin17766a62013-06-17 14:09:33 -070018 """ A class containing hardware and xorg properties for a platform.
19
20 The class can be created from an activity log or by providing
21 the name of the platform. Information will then be read from the
22 'platforms_dir' directory.
Dennis Kempin037675e2013-06-14 14:12:39 -070023 """
24 def __init__(self, platform=None, activity_data=None):
25 if platform:
26 basename = os.path.join(platforms_dir, platform)
27 self.name = platform
Dennis Kempin17766a62013-06-17 14:09:33 -070028 self.hwprops_file = basename + '.hwprops'
29 self.props_file = basename + '.props'
Dennis Kempin037675e2013-06-14 14:12:39 -070030 self.xorg_parser = XorgInputClassParser()
31 self._ParseHWProperties(open(self.hwprops_file).read())
32 self._ParseProperties(open(self.props_file).read())
33 self._UpdateDimensions()
34 elif activity_data:
Dennis Kempin17766a62013-06-17 14:09:33 -070035 self.name = ''
Dennis Kempin037675e2013-06-14 14:12:39 -070036 self._ParseActivityLog(activity_data)
37
38 def _ParseActivityLog(self, activity_data):
Dennis Kempin17766a62013-06-17 14:09:33 -070039 """ Parse property information from an activity log """
Dennis Kempin037675e2013-06-14 14:12:39 -070040 activity = json.loads(activity_data)
Dennis Kempin17766a62013-06-17 14:09:33 -070041 self.properties = activity['properties']
Dennis Kempin037675e2013-06-14 14:12:39 -070042
Dennis Kempin17766a62013-06-17 14:09:33 -070043 hwprops = activity['hardwareProperties']
44 self.x_min = int(hwprops['left'])
45 self.x_max = int(hwprops['right'])
46 self.x_res = int(hwprops['xResolution'])
47 self.y_min = int(hwprops['top'])
48 self.y_max = int(hwprops['bottom'])
49 self.y_res = int(hwprops['yResolution'])
Dennis Kempin037675e2013-06-14 14:12:39 -070050
51 def _ParseHWProperties(self, data):
Dennis Kempin17766a62013-06-17 14:09:33 -070052 """ Parse x and y dimensions and resolution from hwprops file """
53 xregex = re.compile('A: 35 ([0-9\-]+) ([0-9\-]+) ([0-9\-]+) ' +
54 '([0-9\-]+) ([0-9\-]+)')
Dennis Kempin037675e2013-06-14 14:12:39 -070055 xmatch = xregex.search(data);
56 self.x_min = int(xmatch.group(1))
57 self.x_max = int(xmatch.group(2))
58 self.x_res = int(xmatch.group(5))
59
Dennis Kempin17766a62013-06-17 14:09:33 -070060 yregex = re.compile('A: 36 ([0-9\-]+) ([0-9\-]+) ([0-9\-]+) ' +
61 '([0-9\-]+) ([0-9\-]+)')
Dennis Kempin037675e2013-06-14 14:12:39 -070062 ymatch = yregex.search(data);
63 self.y_min = int(ymatch.group(1))
64 self.y_max = int(ymatch.group(2))
65 self.y_res = int(ymatch.group(5))
66
67 def _ParseProperties(self, data):
Dennis Kempin17766a62013-06-17 14:09:33 -070068 """ Parse properties from file and inject xorg properties. """
Dennis Kempin037675e2013-06-14 14:12:39 -070069 self.properties = {}
70 data = json.loads(data)
71
Dennis Kempin17766a62013-06-17 14:09:33 -070072 if 'gestures' in data:
73 self.properties.update(data['gestures'])
Dennis Kempin037675e2013-06-14 14:12:39 -070074
Dennis Kempin17766a62013-06-17 14:09:33 -070075 if 'device_class' in data:
76 self.device_class = data['device_class']
Dennis Kempin037675e2013-06-14 14:12:39 -070077
Dennis Kempin17766a62013-06-17 14:09:33 -070078 if xorg_conf_path and 'xorg' in data and 'file' in data['xorg']:
79 filename = os.path.join(xorg_conf_path, data['xorg']['file'])
Dennis Kempin037675e2013-06-14 14:12:39 -070080 input_classes = self.xorg_parser.Parse(file=filename)
Dennis Kempin17766a62013-06-17 14:09:33 -070081 if 'identifier' in data['xorg']:
82 properties = input_classes[data['xorg']['identifier']]
Dennis Kempin037675e2013-06-14 14:12:39 -070083 self.properties.update(properties)
Dennis Kempin17766a62013-06-17 14:09:33 -070084 if 'identifiers' in data['xorg']:
85 for identifier in data['xorg']['identifiers']:
Dennis Kempin037675e2013-06-14 14:12:39 -070086 properties = input_classes[identifier]
87 self.properties.update(properties)
88
89 def _UpdateDimensions(self):
Dennis Kempin17766a62013-06-17 14:09:33 -070090 """ Update x/y min/max with xorg properties.
91
92 CMT allows hardware properties to be overwritten by xorg properties.
93 Do the same in this class.
Dennis Kempin037675e2013-06-14 14:12:39 -070094 """
Dennis Kempin17766a62013-06-17 14:09:33 -070095 if 'Active Area Left' in self.properties:
96 self.x_min = int(self.properties['Active Area Left'])
97 if 'Active Area Right' in self.properties:
98 self.x_max = int(self.properties['Active Area Right'])
99 if 'Horizontal Resolution' in self.properties:
100 self.x_res = int(self.properties['Horizontal Resolution'])
101 if 'Active Area Top' in self.properties:
102 self.y_min = int(self.properties['Active Area Top'])
103 if 'Active Area Bottom' in self.properties:
104 self.y_max = int(self.properties['Active Area Bottom'])
105 if 'Vertical Resolution' in self.properties:
106 self.y_res = int(self.properties['Vertical Resolution'])
Dennis Kempin037675e2013-06-14 14:12:39 -0700107
108 def Match(self, other):
Dennis Kempin17766a62013-06-17 14:09:33 -0700109 """ Compare properties and return similarity.
110
111 Compare these properties to another PlatformProperties instance.
112 The return value is a score between 1. 0 meaning there is a big mismatch
113 and 1 meaning the properties match completely.
114 Only a selected range of properties are compared in order to
115 prevent property adjustments to cause platforms to be mismatched.
Dennis Kempin037675e2013-06-14 14:12:39 -0700116 """
117 scores = []
118 def compare(a, b, what):
119 value = abs(float(a) - float(b))
120 if value > 0:
121 value = min(1, value / abs(float(a)), abs(float(b)))
122 scores.append(1-value)
123 def compare_attr(what):
124 compare(getattr(self, what), getattr(other, what), what)
125 def compare_prop(what):
126 if what not in self.properties or what not in other.properties:
127 return 0
128 compare(self.properties[what], other.properties[what], what)
Dennis Kempin17766a62013-06-17 14:09:33 -0700129 compare_attr('x_min')
130 compare_attr('x_max')
131 compare_attr('x_res')
132 compare_prop('Pressure Calibration Offset')
Dennis Kempin037675e2013-06-14 14:12:39 -0700133 return reduce(lambda x,y: (x * y), scores)
134
135class PlatformDatabase(object):
Dennis Kempin17766a62013-06-17 14:09:33 -0700136 """ Class for managing platforms.
137
138 This class reads all available platforms from the platforms_dir and allows
139 to search for matching platforms to an activity log file.
Dennis Kempin037675e2013-06-14 14:12:39 -0700140 """
141 def __init__(self):
142 platform_files = [ f for f in os.listdir(platforms_dir)
Dennis Kempin17766a62013-06-17 14:09:33 -0700143 if f.endswith('.hwprops') ]
Dennis Kempin037675e2013-06-14 14:12:39 -0700144 self.platforms = {}
145 for file in platform_files:
Dennis Kempin17766a62013-06-17 14:09:33 -0700146 name = file.replace('.hwprops', '')
Dennis Kempin037675e2013-06-14 14:12:39 -0700147 self.platforms[name] = PlatformProperties(platform=name)
148
149 def FindMatching(self, activity_data):
Dennis Kempin17766a62013-06-17 14:09:33 -0700150 """ Find platform matching activity_data.
151
152 Returns the PlatformProperties instance of the platform matching
153 the activity log data. This method might terminate the program in
154 case no match can be made, or the match is ambiguous.
Dennis Kempin037675e2013-06-14 14:12:39 -0700155 """
156 result = None
157 properties = PlatformProperties(activity_data=activity_data)
158 for name, platform in self.platforms.items():
159 score = platform.Match(properties)
160 if score > 0.9:
161 if result:
Dennis Kempin17766a62013-06-17 14:09:33 -0700162 print ('multiple matching platforms:', result.name,
163 'and', platform.name)
Dennis Kempin037675e2013-06-14 14:12:39 -0700164 sys.exit(-1)
165 result = platform
166 if not result:
Dennis Kempin17766a62013-06-17 14:09:33 -0700167 print 'cannot find matching platform'
168 sys.exit(-1)
Dennis Kempin037675e2013-06-14 14:12:39 -0700169 return result