Sergei Trofimov | 4e6afe9 | 2015-10-09 09:30:04 +0100 | [diff] [blame] | 1 | # 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 | # |
| 15 | from __future__ import division |
| 16 | import re |
| 17 | |
| 18 | from devlib.instrument import Instrument, Measurement, INSTANTANEOUS |
| 19 | from devlib.exception import TargetError |
| 20 | |
| 21 | |
| 22 | class 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 | |
| 65 | def _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() |