778f30755dfe14a99bbb42f0ecf01051a5cb9851
[firefly-linux-kernel-4.4.55.git] / tools / gator / daemon / Hwmon.cpp
1 /**
2  * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3  *
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 "Hwmon.h"
10
11 #include "libsensors/sensors.h"
12
13 #include "Buffer.h"
14 #include "Counter.h"
15 #include "Logging.h"
16 #include "SessionData.h"
17
18 class HwmonCounter {
19 public:
20         HwmonCounter(HwmonCounter *next, const sensors_chip_name *chip, const sensors_feature *feature);
21         ~HwmonCounter();
22
23         HwmonCounter *getNext() const { return next; }
24         int getKey() const { return key; }
25         bool isEnabled() const { return enabled; }
26         const char *getName() const { return name; }
27         const char *getLabel() const { return label; }
28         const char *getTitle() const { return title; }
29         bool isDuplicate() const { return duplicate; }
30         const char *getDisplay() const { return display; }
31         const char *getUnit() const { return unit; }
32         int getModifier() const { return modifier; }
33
34         void setEnabled(const bool enabled) {
35                 this->enabled = enabled;
36                 // canRead will clear enabled if the counter is not readable
37                 canRead();
38         }
39
40         double read();
41         bool canRead();
42
43 private:
44         void init(const sensors_chip_name *chip, const sensors_feature *feature);
45
46         HwmonCounter *const next;
47         const int key;
48         int polled : 1,
49                 readable : 1,
50                 enabled : 1,
51                 monotonic: 1,
52                 duplicate : 1;
53
54         const sensors_chip_name *chip;
55         const sensors_feature *feature;
56
57         char *name;
58         char *label;
59         const char *title;
60         const char *display;
61         const char *unit;
62         int modifier;
63         double previous_value;
64
65         sensors_subfeature_type input;
66
67         // Intentionally unimplemented
68         HwmonCounter(const HwmonCounter &);
69         HwmonCounter &operator=(const HwmonCounter &);
70 };
71
72 HwmonCounter::HwmonCounter(HwmonCounter *next, const sensors_chip_name *chip, const sensors_feature *feature) : next(next), key(getEventKey()), polled(false), readable(false), enabled(false), duplicate(false), chip(chip), feature(feature) {
73
74         int len = sensors_snprintf_chip_name(NULL, 0, chip) + 1;
75         char *chip_name = new char[len];
76         sensors_snprintf_chip_name(chip_name, len, chip);
77
78         len = snprintf(NULL, 0, "hwmon_%s_%d", chip_name, feature->number) + 1;
79         name = new char[len];
80         snprintf(name, len, "hwmon_%s_%d", chip_name, feature->number);
81
82         delete [] chip_name;
83
84         label = sensors_get_label(chip, feature);
85
86         switch (feature->type) {
87         case SENSORS_FEATURE_IN:
88                 title = "Voltage";
89                 input = SENSORS_SUBFEATURE_IN_INPUT;
90                 display = "average";
91                 unit = "V";
92                 modifier = 1000;
93                 monotonic = false;
94                 break;
95         case SENSORS_FEATURE_FAN:
96                 title = "Fan";
97                 input = SENSORS_SUBFEATURE_FAN_INPUT;
98                 display = "average";
99                 unit = "RPM";
100                 modifier = 1;
101                 monotonic = false;
102                 break;
103         case SENSORS_FEATURE_TEMP:
104                 title = "Temperature";
105                 input = SENSORS_SUBFEATURE_TEMP_INPUT;
106                 display = "maximum";
107                 unit = "°C";
108                 modifier = 1000;
109                 monotonic = false;
110                 break;
111         case SENSORS_FEATURE_POWER:
112                 title = "Power";
113                 input = SENSORS_SUBFEATURE_POWER_INPUT;
114                 display = "average";
115                 unit = "W";
116                 modifier = 1000000;
117                 monotonic = false;
118                 break;
119         case SENSORS_FEATURE_ENERGY:
120                 title = "Energy";
121                 input = SENSORS_SUBFEATURE_ENERGY_INPUT;
122                 display = "accumulate";
123                 unit = "J";
124                 modifier = 1000000;
125                 monotonic = true;
126                 break;
127         case SENSORS_FEATURE_CURR:
128                 title = "Current";
129                 input = SENSORS_SUBFEATURE_CURR_INPUT;
130                 display = "average";
131                 unit = "A";
132                 modifier = 1000;
133                 monotonic = false;
134                 break;
135         case SENSORS_FEATURE_HUMIDITY:
136                 title = "Humidity";
137                 input = SENSORS_SUBFEATURE_HUMIDITY_INPUT;
138                 display = "average";
139                 unit = "%";
140                 modifier = 1000;
141                 monotonic = false;
142                 break;
143         default:
144                 logg->logError(__FILE__, __LINE__, "Unsupported hwmon feature %i", feature->type);
145                 handleException();
146         }
147
148         for (HwmonCounter * counter = next; counter != NULL; counter = counter->getNext()) {
149                 if (strcmp(label, counter->getLabel()) == 0 && strcmp(title, counter->getTitle()) == 0) {
150                         duplicate = true;
151                         counter->duplicate = true;
152                         break;
153                 }
154         }
155 }
156
157 HwmonCounter::~HwmonCounter() {
158         free((void *)label);
159         delete [] name;
160 }
161
162 double HwmonCounter::read() {
163         double value;
164         double result;
165         const sensors_subfeature *subfeature;
166
167         // Keep in sync with canRead
168         subfeature = sensors_get_subfeature(chip, feature, input);
169         if (!subfeature) {
170                 logg->logError(__FILE__, __LINE__, "No input value for hwmon sensor %s", label);
171                 handleException();
172         }
173
174         if (sensors_get_value(chip, subfeature->number, &value) != 0) {
175                 logg->logError(__FILE__, __LINE__, "Can't get input value for hwmon sensor %s", label);
176                 handleException();
177         }
178
179         result = (monotonic ? value - previous_value : value);
180         previous_value = value;
181
182         return result;
183 }
184
185 bool HwmonCounter::canRead() {
186         if (!polled) {
187                 double value;
188                 const sensors_subfeature *subfeature;
189                 bool result = true;
190
191                 subfeature = sensors_get_subfeature(chip, feature, input);
192                 if (!subfeature) {
193                         result = false;
194                 } else {
195                         result = sensors_get_value(chip, subfeature->number, &value) == 0;
196                 }
197
198                 polled = true;
199                 readable = result;
200         }
201
202         enabled &= readable;
203
204         return readable;
205 }
206
207 Hwmon::Hwmon() : counters(NULL) {
208 }
209
210 Hwmon::~Hwmon() {
211         while (counters != NULL) {
212                 HwmonCounter * counter = counters;
213                 counters = counter->getNext();
214                 delete counter;
215         }
216         sensors_cleanup();
217 }
218
219 void Hwmon::setup() {
220         // hwmon does not currently work with perf
221         if (gSessionData->perf.isSetup()) {
222                 return;
223         }
224
225         int err = sensors_init(NULL);
226         if (err) {
227                 logg->logMessage("Failed to initialize libsensors! (%d)", err);
228                 return;
229         }
230         sensors_sysfs_no_scaling = 1;
231
232         int chip_nr = 0;
233         const sensors_chip_name *chip;
234         while ((chip = sensors_get_detected_chips(NULL, &chip_nr))) {
235                 int feature_nr = 0;
236                 const sensors_feature *feature;
237                 while ((feature = sensors_get_features(chip, &feature_nr))) {
238                         counters = new HwmonCounter(counters, chip, feature);
239                 }
240         }
241 }
242
243 HwmonCounter *Hwmon::findCounter(const Counter &counter) const {
244         for (HwmonCounter * hwmonCounter = counters; hwmonCounter != NULL; hwmonCounter = hwmonCounter->getNext()) {
245                 if (hwmonCounter->canRead() && strcmp(hwmonCounter->getName(), counter.getType()) == 0) {
246                         return hwmonCounter;
247                 }
248         }
249
250         return NULL;
251 }
252
253 bool Hwmon::claimCounter(const Counter &counter) const {
254         return findCounter(counter) != NULL;
255 }
256
257 bool Hwmon::countersEnabled() const {
258         for (HwmonCounter * counter = counters; counter != NULL; counter = counter->getNext()) {
259                 if (counter->isEnabled()) {
260                         return true;
261                 }
262         }
263         return false;
264 }
265
266 void Hwmon::resetCounters() {
267         for (HwmonCounter * counter = counters; counter != NULL; counter = counter->getNext()) {
268                 counter->setEnabled(false);
269         }
270 }
271
272 void Hwmon::setupCounter(Counter &counter) {
273         HwmonCounter *const hwmonCounter = findCounter(counter);
274         if (hwmonCounter == NULL) {
275                 counter.setEnabled(false);
276                 return;
277         }
278         hwmonCounter->setEnabled(true);
279         counter.setKey(hwmonCounter->getKey());
280 }
281
282 int Hwmon::writeCounters(mxml_node_t *root) const {
283         int count = 0;
284         for (HwmonCounter * counter = counters; counter != NULL; counter = counter->getNext()) {
285                 if (!counter->canRead()) {
286                         continue;
287                 }
288                 mxml_node_t *node = mxmlNewElement(root, "counter");
289                 mxmlElementSetAttr(node, "name", counter->getName());
290                 ++count;
291         }
292
293         return count;
294 }
295
296 void Hwmon::writeEvents(mxml_node_t *root) const {
297         root = mxmlNewElement(root, "category");
298         mxmlElementSetAttr(root, "name", "hwmon");
299
300         char buf[1024];
301         for (HwmonCounter * counter = counters; counter != NULL; counter = counter->getNext()) {
302                 if (!counter->canRead()) {
303                         continue;
304                 }
305                 mxml_node_t *node = mxmlNewElement(root, "event");
306                 mxmlElementSetAttr(node, "counter", counter->getName());
307                 mxmlElementSetAttr(node, "title", counter->getTitle());
308                 if (counter->isDuplicate()) {
309                         mxmlElementSetAttrf(node, "name", "%s (0x%x)", counter->getLabel(), counter->getKey());
310                 } else {
311                         mxmlElementSetAttr(node, "name", counter->getLabel());
312                 }
313                 mxmlElementSetAttr(node, "display", counter->getDisplay());
314                 mxmlElementSetAttr(node, "units", counter->getUnit());
315                 if (counter->getModifier() != 1) {
316                         mxmlElementSetAttrf(node, "modifier", "%d", counter->getModifier());
317                 }
318                 if (strcmp(counter->getDisplay(), "average") == 0 || strcmp(counter->getDisplay(), "maximum") == 0) {
319                         mxmlElementSetAttr(node, "average_selection", "yes");
320                 }
321                 snprintf(buf, sizeof(buf), "libsensors %s sensor %s (%s)", counter->getTitle(), counter->getLabel(), counter->getName());
322                 mxmlElementSetAttr(node, "description", buf);
323         }
324 }
325
326 void Hwmon::start() {
327         for (HwmonCounter * counter = counters; counter != NULL; counter = counter->getNext()) {
328                 if (!counter->isEnabled()) {
329                         continue;
330                 }
331                 counter->read();
332         }
333 }
334
335 void Hwmon::read(Buffer * const buffer) {
336         for (HwmonCounter * counter = counters; counter != NULL; counter = counter->getNext()) {
337                 if (!counter->isEnabled()) {
338                         continue;
339                 }
340                 buffer->event(counter->getKey(), counter->read());
341         }
342 }