1d7c0da9cc83673eb1beba18c72518f7f9e43380
[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         // Intentionally unimplemented
68         HwmonCounter(const HwmonCounter &);
69         HwmonCounter &operator=(const HwmonCounter &);
70 };
71
72 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) {
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         int err = sensors_init(NULL);
209         if (err) {
210                 logg->logMessage("Failed to initialize libsensors! (%d)", err);
211                 return;
212         }
213         sensors_sysfs_no_scaling = 1;
214
215         int chip_nr = 0;
216         const sensors_chip_name *chip;
217         while ((chip = sensors_get_detected_chips(NULL, &chip_nr))) {
218                 int feature_nr = 0;
219                 const sensors_feature *feature;
220                 while ((feature = sensors_get_features(chip, &feature_nr))) {
221                         counters = new HwmonCounter(counters, getEventKey(), chip, feature);
222                 }
223         }
224 }
225
226 Hwmon::~Hwmon() {
227         while (counters != NULL) {
228                 HwmonCounter * counter = counters;
229                 counters = counter->getNext();
230                 delete counter;
231         }
232         sensors_cleanup();
233 }
234
235 HwmonCounter *Hwmon::findCounter(const Counter &counter) const {
236         for (HwmonCounter * hwmonCounter = counters; hwmonCounter != NULL; hwmonCounter = hwmonCounter->getNext()) {
237                 if (hwmonCounter->canRead() && strcmp(hwmonCounter->getName(), counter.getType()) == 0) {
238                         return hwmonCounter;
239                 }
240         }
241
242         return NULL;
243 }
244
245 bool Hwmon::claimCounter(const Counter &counter) const {
246         return findCounter(counter) != NULL;
247 }
248
249 bool Hwmon::countersEnabled() const {
250         for (HwmonCounter * counter = counters; counter != NULL; counter = counter->getNext()) {
251                 if (counter->isEnabled()) {
252                         return true;
253                 }
254         }
255         return false;
256 }
257
258 void Hwmon::resetCounters() {
259         for (HwmonCounter * counter = counters; counter != NULL; counter = counter->getNext()) {
260                 counter->setEnabled(false);
261         }
262 }
263
264 void Hwmon::setupCounter(Counter &counter) {
265         HwmonCounter *const hwmonCounter = findCounter(counter);
266         if (hwmonCounter == NULL) {
267                 counter.setEnabled(false);
268                 return;
269         }
270         hwmonCounter->setEnabled(true);
271         counter.setKey(hwmonCounter->getKey());
272 }
273
274 void Hwmon::writeCounters(mxml_node_t *root) const {
275         for (HwmonCounter * counter = counters; counter != NULL; counter = counter->getNext()) {
276                 if (!counter->canRead()) {
277                         continue;
278                 }
279                 mxml_node_t *node = mxmlNewElement(root, "counter");
280                 mxmlElementSetAttr(node, "name", counter->getName());
281         }
282 }
283
284 void Hwmon::writeEvents(mxml_node_t *root) const {
285         root = mxmlNewElement(root, "category");
286         mxmlElementSetAttr(root, "name", "hwmon");
287
288         char buf[1024];
289         for (HwmonCounter * counter = counters; counter != NULL; counter = counter->getNext()) {
290                 if (!counter->canRead()) {
291                         continue;
292                 }
293                 mxml_node_t *node = mxmlNewElement(root, "event");
294                 mxmlElementSetAttr(node, "counter", counter->getName());
295                 mxmlElementSetAttr(node, "title", counter->getTitle());
296                 if (counter->isDuplicate()) {
297                         mxmlElementSetAttrf(node, "name", "%s (0x%x)", counter->getLabel(), counter->getKey());
298                 } else {
299                         mxmlElementSetAttr(node, "name", counter->getLabel());
300                 }
301                 mxmlElementSetAttr(node, "display", counter->getDisplay());
302                 mxmlElementSetAttr(node, "units", counter->getUnit());
303                 if (counter->getModifier() != 1) {
304                         mxmlElementSetAttrf(node, "modifier", "%d", counter->getModifier());
305                 }
306                 if (strcmp(counter->getDisplay(), "average") == 0 || strcmp(counter->getDisplay(), "maximum") == 0) {
307                         mxmlElementSetAttr(node, "average_selection", "yes");
308                 }
309                 snprintf(buf, sizeof(buf), "libsensors %s sensor %s (%s)", counter->getTitle(), counter->getLabel(), counter->getName());
310                 mxmlElementSetAttr(node, "description", buf);
311         }
312 }
313
314 void Hwmon::start() {
315         for (HwmonCounter * counter = counters; counter != NULL; counter = counter->getNext()) {
316                 if (!counter->isEnabled()) {
317                         continue;
318                 }
319                 counter->read();
320         }
321 }
322
323 void Hwmon::read(Buffer * const buffer) {
324         for (HwmonCounter * counter = counters; counter != NULL; counter = counter->getNext()) {
325                 if (!counter->isEnabled()) {
326                         continue;
327                 }
328                 buffer->event(counter->getKey(), counter->read());
329         }
330 }