diff options
Diffstat (limited to 'tools/gator/daemon/Hwmon.cpp')
-rw-r--r-- | tools/gator/daemon/Hwmon.cpp | 277 |
1 files changed, 277 insertions, 0 deletions
diff --git a/tools/gator/daemon/Hwmon.cpp b/tools/gator/daemon/Hwmon.cpp new file mode 100644 index 000000000000..9603411ecd13 --- /dev/null +++ b/tools/gator/daemon/Hwmon.cpp @@ -0,0 +1,277 @@ +/** + * Copyright (C) ARM Limited 2013. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "Hwmon.h" + +#include "libsensors/sensors.h" + +#include "Buffer.h" +#include "Counter.h" +#include "Logging.h" +#include "SessionData.h" + +class HwmonCounter { +public: + HwmonCounter(HwmonCounter *next, int key, const sensors_chip_name *chip, const sensors_feature *feature); + ~HwmonCounter(); + + HwmonCounter *getNext() const { return next; } + int getKey() const { return key; } + bool isEnabled() const { return enabled; } + const char *getName() const { return name; } + const char *getLabel() const { return label; } + const char *getTitle() const { return title; } + const char *getDisplay() const { return display; } + const char *getUnit() const { return unit; } + int getModifier() const { return modifier; } + + void setEnabled(const bool enabled) { this->enabled = enabled; } + + double read(); + +private: + void init(const sensors_chip_name *chip, const sensors_feature *feature); + + HwmonCounter *const next; + const int key; + bool enabled; + + const sensors_chip_name *chip; + const sensors_feature *feature; + + char *name; + char *label; + const char *title; + const char *display; + const char *unit; + int modifier; + bool monotonic; + double previous_value; + + sensors_subfeature_type input; +}; + +HwmonCounter::HwmonCounter(HwmonCounter *next, int key, const sensors_chip_name *chip, const sensors_feature *feature) : next(next), key(key), enabled(false), chip(chip), feature(feature) { + + int len = sensors_snprintf_chip_name(NULL, 0, chip) + 1; + char *chip_name = new char[len]; + sensors_snprintf_chip_name(chip_name, len, chip); + + len = snprintf(NULL, 0, "hwmon_%s_%d", chip_name, feature->number) + 1; + name = new char[len]; + len = snprintf(name, len, "hwmon_%s_%d", chip_name, feature->number); + + delete [] chip_name; + + label = sensors_get_label(chip, feature); + + switch (feature->type) { + case SENSORS_FEATURE_IN: + title = "Voltage"; + input = SENSORS_SUBFEATURE_IN_INPUT; + display = "average"; + unit = "V"; + modifier = 1000; + monotonic = false; + break; + case SENSORS_FEATURE_FAN: + title = "Fan"; + input = SENSORS_SUBFEATURE_FAN_INPUT; + display = "average"; + unit = "RPM"; + modifier = 1; + monotonic = false; + break; + case SENSORS_FEATURE_TEMP: + title = "Temperature"; + input = SENSORS_SUBFEATURE_TEMP_INPUT; + display = "maximum"; + unit = "°C"; + modifier = 1000; + monotonic = false; + break; + case SENSORS_FEATURE_POWER: + title = "Power"; + input = SENSORS_SUBFEATURE_POWER_INPUT; + display = "average"; + unit = "W"; + modifier = 1000000; + monotonic = false; + break; + case SENSORS_FEATURE_ENERGY: + title = "Energy"; + input = SENSORS_SUBFEATURE_ENERGY_INPUT; + display = "accumulate"; + unit = "J"; + modifier = 1000000; + monotonic = true; + break; + case SENSORS_FEATURE_CURR: + title = "Current"; + input = SENSORS_SUBFEATURE_CURR_INPUT; + display = "average"; + unit = "A"; + modifier = 1000; + monotonic = false; + break; + case SENSORS_FEATURE_HUMIDITY: + title = "Humidity"; + input = SENSORS_SUBFEATURE_HUMIDITY_INPUT; + display = "average"; + unit = "%"; + modifier = 1000; + monotonic = false; + break; + default: + logg->logError(__FILE__, __LINE__, "Unsupported hwmon feature %i", feature->type); + handleException(); + } +} + +HwmonCounter::~HwmonCounter() { + free((void *)label); + delete [] name; +} + +double HwmonCounter::read() { + double value; + double result; + const sensors_subfeature *subfeature; + + subfeature = sensors_get_subfeature(chip, feature, input); + if (!subfeature) { + logg->logError(__FILE__, __LINE__, "No input value for hwmon sensor %s", label); + handleException(); + } + + if (sensors_get_value(chip, subfeature->number, &value) != 0) { + logg->logError(__FILE__, __LINE__, "Can't get input value for hwmon sensor %s", label); + handleException(); + } + + result = (monotonic ? value - previous_value : value); + previous_value = value; + + return result; +} + + +Hwmon::Hwmon() : counters(NULL) { + int err = sensors_init(NULL); + if (err) { + logg->logMessage("Failed to initialize libsensors! (%d)", err); + return; + } + sensors_sysfs_no_scaling = 1; + + int chip_nr = 0; + const sensors_chip_name *chip; + while ((chip = sensors_get_detected_chips(NULL, &chip_nr))) { + int feature_nr = 0; + const sensors_feature *feature; + while ((feature = sensors_get_features(chip, &feature_nr))) { + counters = new HwmonCounter(counters, getEventKey(), chip, feature); + } + } +} + +Hwmon::~Hwmon() { + while (counters != NULL) { + HwmonCounter * counter = counters; + counters = counter->getNext(); + delete counter; + } + sensors_cleanup(); +} + +HwmonCounter *Hwmon::findCounter(const Counter &counter) const { + for (HwmonCounter * hwmonCounter = counters; hwmonCounter != NULL; hwmonCounter = hwmonCounter->getNext()) { + if (strcmp(hwmonCounter->getName(), counter.getType()) == 0) { + return hwmonCounter; + } + } + + return NULL; +} + +bool Hwmon::claimCounter(const Counter &counter) const { + return findCounter(counter) != NULL; +} + +bool Hwmon::countersEnabled() const { + for (HwmonCounter * counter = counters; counter != NULL; counter = counter->getNext()) { + if (counter->isEnabled()) { + return true; + } + } + return false; +} + +void Hwmon::resetCounters() { + for (HwmonCounter * counter = counters; counter != NULL; counter = counter->getNext()) { + counter->setEnabled(false); + } +} + +void Hwmon::setupCounter(Counter &counter) { + HwmonCounter *const hwmonCounter = findCounter(counter); + if (hwmonCounter == NULL) { + counter.setEnabled(false); + return; + } + hwmonCounter->setEnabled(true); + counter.setKey(hwmonCounter->getKey()); +} + +void Hwmon::writeCounters(mxml_node_t *root) const { + for (HwmonCounter * counter = counters; counter != NULL; counter = counter->getNext()) { + mxml_node_t *node = mxmlNewElement(root, "counter"); + mxmlElementSetAttr(node, "name", counter->getName()); + } +} + +void Hwmon::writeEvents(mxml_node_t *root) const { + root = mxmlNewElement(root, "category"); + mxmlElementSetAttr(root, "name", "hwmon"); + + char buf[1024]; + for (HwmonCounter * counter = counters; counter != NULL; counter = counter->getNext()) { + mxml_node_t *node = mxmlNewElement(root, "event"); + mxmlElementSetAttr(node, "counter", counter->getName()); + mxmlElementSetAttr(node, "title", counter->getTitle()); + mxmlElementSetAttr(node, "name", counter->getLabel()); + mxmlElementSetAttr(node, "display", counter->getDisplay()); + mxmlElementSetAttr(node, "units", counter->getUnit()); + if (counter->getModifier() != 1) { + mxmlElementSetAttrf(node, "modifier", "%d", counter->getModifier()); + } + if (strcmp(counter->getDisplay(), "average") == 0 || strcmp(counter->getDisplay(), "maximum") == 0) { + mxmlElementSetAttr(node, "average_selection", "yes"); + } + snprintf(buf, sizeof(buf), "libsensors %s sensor %s (%s)", counter->getTitle(), counter->getLabel(), counter->getName()); + mxmlElementSetAttr(node, "description", buf); + } +} + +void Hwmon::start() { + for (HwmonCounter * counter = counters; counter != NULL; counter = counter->getNext()) { + if (!counter->isEnabled()) { + continue; + } + counter->read(); + } +} + +void Hwmon::read(Buffer * const buffer) { + for (HwmonCounter * counter = counters; counter != NULL; counter = counter->getNext()) { + if (!counter->isEnabled()) { + continue; + } + buffer->event(counter->getKey(), counter->read()); + } +} |