/** * 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()); } }