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