blob: ae49f40ee8ee60bcfde62ef98b8935aff68b346c [file] [log] [blame]
Sergei Trofimov4e6afe92015-10-09 09:30:04 +01001# 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#
15from __future__ import division
16import re
17
18from devlib.instrument import Instrument, Measurement, INSTANTANEOUS
19from devlib.exception import TargetError
20
21
22class HwmonInstrument(Instrument):
23
24 name = 'hwmon'
25 mode = INSTANTANEOUS
26
27 # sensor kind --> (meaure, standard unit conversion)
28 measure_map = {
29 'temp': ('temperature', lambda x: x / 1000),
30 'in': ('voltage', lambda x: x / 1000),
31 'curr': ('current', lambda x: x / 1000),
32 'power': ('power', lambda x: x / 1000000),
33 'energy': ('energy', lambda x: x / 1000000),
34 }
35
36 def __init__(self, target):
37 if not hasattr(target, 'hwmon'):
38 raise TargetError('Target does not support HWMON')
39 super(HwmonInstrument, self).__init__(target)
40
41 self.logger.debug('Discovering available HWMON sensors...')
42 for ts in self.target.hwmon.sensors:
43 try:
44 ts.get_file('input')
45 measure = self.measure_map.get(ts.kind)[0]
46 if measure:
47 self.logger.debug('\tAdding sensor {}'.format(ts.name))
48 self.add_channel(_guess_site(ts), measure, name=ts.name, sensor=ts)
49 else:
50 self.logger.debug('\tSkipping sensor {} (unknown kind "{}")'.format(ts.name, ts.kind))
51 except ValueError:
52 message = 'Skipping sensor {} because it does not have an input file'
53 self.logger.debug(message.format(ts.name))
54 continue
55
56 def take_measurement(self):
57 result = []
58 for chan in self.active_channels:
59 convert = self.measure_map[chan.sensor.kind][1]
60 value = convert(chan.sensor.get('input'))
61 result.append(Measurement(value, chan))
62 return result
63
64
65def _guess_site(sensor):
66 """
67 HWMON does not specify a standard for labeling its sensors, or for
68 device/item split (the implication is that each hwmon device a separate chip
69 with possibly several sensors on it, but not everyone adheres to that, e.g.,
70 with some mobile devices splitting a chip's sensors across multiple hwmon
71 devices. This function processes name/label of the senors to attempt to
72 identify the best "candidate" for the site to which the sensor belongs.
73 """
74 if sensor.name == sensor.label:
75 # If no label has been specified for the sensor (in which case, it
76 # defaults to the sensor's name), assume that the "site" of the sensor
77 # is identified by the HWMON device
78 text = sensor.device.name
79 else:
80 # If a label has been specified, assume multiple sensors controlled by
81 # the same device and the label identifies the site.
82 text = sensor.label
83 # strip out sensor kind suffix, if any, as that does not indicate a site
84 for kind in ['volt', 'in', 'curr', 'power', 'energy',
85 'temp', 'voltage', 'temperature', 'current']:
86 if kind in text.lower():
87 regex = re.compile(r'_*{}\d*_*'.format(kind), re.I)
88 text = regex.sub('', text)
89 return text.strip()