| # Copyright 2015 ARM Limited |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| # |
| from __future__ import division |
| import re |
| |
| from devlib.instrument import Instrument, Measurement, INSTANTANEOUS |
| from devlib.exception import TargetError |
| |
| |
| class HwmonInstrument(Instrument): |
| |
| name = 'hwmon' |
| mode = INSTANTANEOUS |
| |
| # sensor kind --> (meaure, standard unit conversion) |
| measure_map = { |
| 'temp': ('temperature', lambda x: x / 1000), |
| 'in': ('voltage', lambda x: x / 1000), |
| 'curr': ('current', lambda x: x / 1000), |
| 'power': ('power', lambda x: x / 1000000), |
| 'energy': ('energy', lambda x: x / 1000000), |
| } |
| |
| def __init__(self, target): |
| if not hasattr(target, 'hwmon'): |
| raise TargetError('Target does not support HWMON') |
| super(HwmonInstrument, self).__init__(target) |
| |
| self.logger.debug('Discovering available HWMON sensors...') |
| for ts in self.target.hwmon.sensors: |
| try: |
| ts.get_file('input') |
| measure = self.measure_map.get(ts.kind)[0] |
| if measure: |
| self.logger.debug('\tAdding sensor {}'.format(ts.name)) |
| self.add_channel(_guess_site(ts), measure, sensor=ts) |
| else: |
| self.logger.debug('\tSkipping sensor {} (unknown kind "{}")'.format(ts.name, ts.kind)) |
| except ValueError: |
| message = 'Skipping sensor {} because it does not have an input file' |
| self.logger.debug(message.format(ts.name)) |
| continue |
| |
| def take_measurement(self): |
| result = [] |
| for chan in self.active_channels: |
| convert = self.measure_map[chan.sensor.kind][1] |
| value = convert(chan.sensor.get('input')) |
| result.append(Measurement(value, chan)) |
| return result |
| |
| |
| def _guess_site(sensor): |
| """ |
| HWMON does not specify a standard for labeling its sensors, or for |
| device/item split (the implication is that each hwmon device a separate chip |
| with possibly several sensors on it, but not everyone adheres to that, e.g., |
| with some mobile devices splitting a chip's sensors across multiple hwmon |
| devices. This function processes name/label of the senors to attempt to |
| identify the best "candidate" for the site to which the sensor belongs. |
| """ |
| if sensor.name == sensor.label: |
| # If no label has been specified for the sensor (in which case, it |
| # defaults to the sensor's name), assume that the "site" of the sensor |
| # is identified by the HWMON device |
| text = sensor.device.name |
| else: |
| # If a label has been specified, assume multiple sensors controlled by |
| # the same device and the label identifies the site. |
| text = sensor.label |
| # strip out sensor kind suffix, if any, as that does not indicate a site |
| for kind in ['volt', 'in', 'curr', 'power', 'energy', |
| 'temp', 'voltage', 'temperature', 'current']: |
| if kind in text.lower(): |
| regex = re.compile(r'_*{}\d*_*'.format(kind), re.I) |
| text = regex.sub('', text) |
| return text.strip() |