blob: d8353b006e63d1196d0bddf31e3b422be945ea03 [file] [log] [blame]
Jon Medhurst96b56152014-10-30 18:01:15 +00001/**
Jon Medhurstb1d07442015-05-08 12:04:18 +01002 * Copyright (C) ARM Limited 2013-2015. All rights reserved.
Jon Medhurst96b56152014-10-30 18:01:15 +00003 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "HwmonDriver.h"
10
11#include "libsensors/sensors.h"
12
13#include "Logging.h"
14
15// feature->type to input map
16static sensors_subfeature_type getInput(const sensors_feature_type type) {
17 switch (type) {
18 case SENSORS_FEATURE_IN: return SENSORS_SUBFEATURE_IN_INPUT;
19 case SENSORS_FEATURE_FAN: return SENSORS_SUBFEATURE_FAN_INPUT;
20 case SENSORS_FEATURE_TEMP: return SENSORS_SUBFEATURE_TEMP_INPUT;
21 case SENSORS_FEATURE_POWER: return SENSORS_SUBFEATURE_POWER_INPUT;
22 case SENSORS_FEATURE_ENERGY: return SENSORS_SUBFEATURE_ENERGY_INPUT;
23 case SENSORS_FEATURE_CURR: return SENSORS_SUBFEATURE_CURR_INPUT;
24 case SENSORS_FEATURE_HUMIDITY: return SENSORS_SUBFEATURE_HUMIDITY_INPUT;
25 default:
Jon Medhurstb1d07442015-05-08 12:04:18 +010026 logg->logError("Unsupported hwmon feature %i", type);
Jon Medhurst96b56152014-10-30 18:01:15 +000027 handleException();
28 }
29};
30
31class HwmonCounter : public DriverCounter {
32public:
33 HwmonCounter(DriverCounter *next, char *const name, const sensors_chip_name *chip, const sensors_feature *feature);
34 ~HwmonCounter();
35
Jon Medhurstb1d07442015-05-08 12:04:18 +010036 const char *getLabel() const { return mLabel; }
37 const char *getTitle() const { return mTitle; }
38 bool isDuplicate() const { return mDuplicate; }
39 const char *getDisplay() const { return mDisplay; }
40 const char *getCounterClass() const { return mCounterClass; }
41 const char *getUnit() const { return mUnit; }
42 double getMultiplier() const { return mMultiplier; }
Jon Medhurst96b56152014-10-30 18:01:15 +000043
44 int64_t read();
45
46private:
47 void init(const sensors_chip_name *chip, const sensors_feature *feature);
48
Jon Medhurstb1d07442015-05-08 12:04:18 +010049 const sensors_chip_name *mChip;
50 const sensors_feature *mFeature;
51 char *mLabel;
52 const char *mTitle;
53 const char *mDisplay;
54 const char *mCounterClass;
55 const char *mUnit;
56 double mPreviousValue;
57 double mMultiplier;
58 int mMonotonic: 1,
59 mDuplicate : 1;
Jon Medhurst96b56152014-10-30 18:01:15 +000060
61 // Intentionally unimplemented
62 HwmonCounter(const HwmonCounter &);
63 HwmonCounter &operator=(const HwmonCounter &);
64};
65
Jon Medhurstb1d07442015-05-08 12:04:18 +010066HwmonCounter::HwmonCounter(DriverCounter *next, char *const name, const sensors_chip_name *const chip, const sensors_feature *feature) : DriverCounter(next, name), mChip(chip), mFeature(feature), mDuplicate(false) {
67 mLabel = sensors_get_label(mChip, mFeature);
Jon Medhurst96b56152014-10-30 18:01:15 +000068
Jon Medhurstb1d07442015-05-08 12:04:18 +010069 switch (mFeature->type) {
Jon Medhurst96b56152014-10-30 18:01:15 +000070 case SENSORS_FEATURE_IN:
Jon Medhurstb1d07442015-05-08 12:04:18 +010071 mTitle = "Voltage";
72 mDisplay = "maximum";
73 mCounterClass = "absolute";
74 mUnit = "V";
75 mMultiplier = 0.001;
76 mMonotonic = false;
Jon Medhurst96b56152014-10-30 18:01:15 +000077 break;
78 case SENSORS_FEATURE_FAN:
Jon Medhurstb1d07442015-05-08 12:04:18 +010079 mTitle = "Fan";
80 mDisplay = "average";
81 mCounterClass = "absolute";
82 mUnit = "RPM";
83 mMultiplier = 1.0;
84 mMonotonic = false;
Jon Medhurst96b56152014-10-30 18:01:15 +000085 break;
86 case SENSORS_FEATURE_TEMP:
Jon Medhurstb1d07442015-05-08 12:04:18 +010087 mTitle = "Temperature";
88 mDisplay = "maximum";
89 mCounterClass = "absolute";
90 mUnit = "°C";
91 mMultiplier = 0.001;
92 mMonotonic = false;
Jon Medhurst96b56152014-10-30 18:01:15 +000093 break;
94 case SENSORS_FEATURE_POWER:
Jon Medhurstb1d07442015-05-08 12:04:18 +010095 mTitle = "Power";
96 mDisplay = "maximum";
97 mCounterClass = "absolute";
98 mUnit = "W";
99 mMultiplier = 0.000001;
100 mMonotonic = false;
Jon Medhurst96b56152014-10-30 18:01:15 +0000101 break;
102 case SENSORS_FEATURE_ENERGY:
Jon Medhurstb1d07442015-05-08 12:04:18 +0100103 mTitle = "Energy";
104 mDisplay = "accumulate";
105 mCounterClass = "delta";
106 mUnit = "J";
107 mMultiplier = 0.000001;
108 mMonotonic = true;
Jon Medhurst96b56152014-10-30 18:01:15 +0000109 break;
110 case SENSORS_FEATURE_CURR:
Jon Medhurstb1d07442015-05-08 12:04:18 +0100111 mTitle = "Current";
112 mDisplay = "maximum";
113 mCounterClass = "absolute";
114 mUnit = "A";
115 mMultiplier = 0.001;
116 mMonotonic = false;
Jon Medhurst96b56152014-10-30 18:01:15 +0000117 break;
118 case SENSORS_FEATURE_HUMIDITY:
Jon Medhurstb1d07442015-05-08 12:04:18 +0100119 mTitle = "Humidity";
120 mDisplay = "average";
121 mCounterClass = "absolute";
122 mUnit = "%";
123 mMultiplier = 0.001;
124 mMonotonic = false;
Jon Medhurst96b56152014-10-30 18:01:15 +0000125 break;
126 default:
Jon Medhurstb1d07442015-05-08 12:04:18 +0100127 logg->logError("Unsupported hwmon feature %i", mFeature->type);
Jon Medhurst96b56152014-10-30 18:01:15 +0000128 handleException();
129 }
130
131 for (HwmonCounter * counter = static_cast<HwmonCounter *>(next); counter != NULL; counter = static_cast<HwmonCounter *>(counter->getNext())) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100132 if (strcmp(mLabel, counter->getLabel()) == 0 && strcmp(mTitle, counter->getTitle()) == 0) {
133 mDuplicate = true;
134 counter->mDuplicate = true;
Jon Medhurst96b56152014-10-30 18:01:15 +0000135 break;
136 }
137 }
138}
139
140HwmonCounter::~HwmonCounter() {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100141 free((void *)mLabel);
Jon Medhurst96b56152014-10-30 18:01:15 +0000142}
143
144int64_t HwmonCounter::read() {
145 double value;
146 double result;
147 const sensors_subfeature *subfeature;
148
149 // Keep in sync with the read check in HwmonDriver::readEvents
Jon Medhurstb1d07442015-05-08 12:04:18 +0100150 subfeature = sensors_get_subfeature(mChip, mFeature, getInput(mFeature->type));
Jon Medhurst96b56152014-10-30 18:01:15 +0000151 if (!subfeature) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100152 logg->logError("No input value for hwmon sensor %s", mLabel);
Jon Medhurst96b56152014-10-30 18:01:15 +0000153 handleException();
154 }
155
Jon Medhurstb1d07442015-05-08 12:04:18 +0100156 if (sensors_get_value(mChip, subfeature->number, &value) != 0) {
157 logg->logError("Can't get input value for hwmon sensor %s", mLabel);
Jon Medhurst96b56152014-10-30 18:01:15 +0000158 handleException();
159 }
160
Jon Medhurstb1d07442015-05-08 12:04:18 +0100161 result = (mMonotonic ? value - mPreviousValue : value);
162 mPreviousValue = value;
Jon Medhurst96b56152014-10-30 18:01:15 +0000163
164 return result;
165}
166
167HwmonDriver::HwmonDriver() {
168}
169
170HwmonDriver::~HwmonDriver() {
171 sensors_cleanup();
172}
173
174void HwmonDriver::readEvents(mxml_node_t *const) {
175 int err = sensors_init(NULL);
176 if (err) {
177 logg->logMessage("Failed to initialize libsensors! (%d)", err);
178 return;
179 }
180 sensors_sysfs_no_scaling = 1;
181
182 int chip_nr = 0;
183 const sensors_chip_name *chip;
184 while ((chip = sensors_get_detected_chips(NULL, &chip_nr))) {
185 int feature_nr = 0;
186 const sensors_feature *feature;
187 while ((feature = sensors_get_features(chip, &feature_nr))) {
188 // Keep in sync with HwmonCounter::read
189 // Can this counter be read?
190 double value;
191 const sensors_subfeature *const subfeature = sensors_get_subfeature(chip, feature, getInput(feature->type));
192 if ((subfeature == NULL) || (sensors_get_value(chip, subfeature->number, &value) != 0)) {
193 continue;
194 }
195
196 // Get the name of the counter
197 int len = sensors_snprintf_chip_name(NULL, 0, chip) + 1;
198 char *chip_name = new char[len];
199 sensors_snprintf_chip_name(chip_name, len, chip);
200 len = snprintf(NULL, 0, "hwmon_%s_%d_%d", chip_name, chip_nr, feature->number) + 1;
201 char *const name = new char[len];
202 snprintf(name, len, "hwmon_%s_%d_%d", chip_name, chip_nr, feature->number);
203 delete [] chip_name;
204
205 setCounters(new HwmonCounter(getCounters(), name, chip, feature));
206 }
207 }
208}
209
210void HwmonDriver::writeEvents(mxml_node_t *root) const {
211 root = mxmlNewElement(root, "category");
Jon Medhurstb1d07442015-05-08 12:04:18 +0100212 mxmlElementSetAttr(root, "name", "Hardware Monitor");
Jon Medhurst96b56152014-10-30 18:01:15 +0000213
214 char buf[1024];
215 for (HwmonCounter *counter = static_cast<HwmonCounter *>(getCounters()); counter != NULL; counter = static_cast<HwmonCounter *>(counter->getNext())) {
216 mxml_node_t *node = mxmlNewElement(root, "event");
217 mxmlElementSetAttr(node, "counter", counter->getName());
218 mxmlElementSetAttr(node, "title", counter->getTitle());
219 if (counter->isDuplicate()) {
220 mxmlElementSetAttrf(node, "name", "%s (0x%x)", counter->getLabel(), counter->getKey());
221 } else {
222 mxmlElementSetAttr(node, "name", counter->getLabel());
223 }
224 mxmlElementSetAttr(node, "display", counter->getDisplay());
225 mxmlElementSetAttr(node, "class", counter->getCounterClass());
226 mxmlElementSetAttr(node, "units", counter->getUnit());
Jon Medhurstb1d07442015-05-08 12:04:18 +0100227 if (counter->getMultiplier() != 1.0) {
228 mxmlElementSetAttrf(node, "multiplier", "%lf", counter->getMultiplier());
Jon Medhurst96b56152014-10-30 18:01:15 +0000229 }
230 if (strcmp(counter->getDisplay(), "average") == 0 || strcmp(counter->getDisplay(), "maximum") == 0) {
231 mxmlElementSetAttr(node, "average_selection", "yes");
232 }
233 snprintf(buf, sizeof(buf), "libsensors %s sensor %s (%s)", counter->getTitle(), counter->getLabel(), counter->getName());
234 mxmlElementSetAttr(node, "description", buf);
235 }
236}
237
238void HwmonDriver::start() {
239 for (DriverCounter *counter = getCounters(); counter != NULL; counter = counter->getNext()) {
240 if (!counter->isEnabled()) {
241 continue;
242 }
243 counter->read();
244 }
245}