Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 1 | /** |
Jon Medhurst | b1d0744 | 2015-05-08 12:04:18 +0100 | [diff] [blame] | 2 | * Copyright (C) ARM Limited 2013-2015. All rights reserved. |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 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 "HwmonDriver.h" |
| 10 | |
| 11 | #include "libsensors/sensors.h" |
| 12 | |
| 13 | #include "Logging.h" |
| 14 | |
| 15 | // feature->type to input map |
| 16 | static sensors_subfeature_type getInput(const sensors_feature_type type) { |
| 17 | switch (type) { |
| 18 | case SENSORS_FEATURE_IN: return SENSORS_SUBFEATURE_IN_INPUT; |
| 19 | case SENSORS_FEATURE_FAN: return SENSORS_SUBFEATURE_FAN_INPUT; |
| 20 | case SENSORS_FEATURE_TEMP: return SENSORS_SUBFEATURE_TEMP_INPUT; |
| 21 | case SENSORS_FEATURE_POWER: return SENSORS_SUBFEATURE_POWER_INPUT; |
| 22 | case SENSORS_FEATURE_ENERGY: return SENSORS_SUBFEATURE_ENERGY_INPUT; |
| 23 | case SENSORS_FEATURE_CURR: return SENSORS_SUBFEATURE_CURR_INPUT; |
| 24 | case SENSORS_FEATURE_HUMIDITY: return SENSORS_SUBFEATURE_HUMIDITY_INPUT; |
| 25 | default: |
Jon Medhurst | b1d0744 | 2015-05-08 12:04:18 +0100 | [diff] [blame] | 26 | logg->logError("Unsupported hwmon feature %i", type); |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 27 | handleException(); |
| 28 | } |
| 29 | }; |
| 30 | |
| 31 | class HwmonCounter : public DriverCounter { |
| 32 | public: |
| 33 | HwmonCounter(DriverCounter *next, char *const name, const sensors_chip_name *chip, const sensors_feature *feature); |
| 34 | ~HwmonCounter(); |
| 35 | |
Jon Medhurst | b1d0744 | 2015-05-08 12:04:18 +0100 | [diff] [blame] | 36 | const char *getLabel() const { return mLabel; } |
| 37 | const char *getTitle() const { return mTitle; } |
| 38 | bool isDuplicate() const { return mDuplicate; } |
| 39 | const char *getDisplay() const { return mDisplay; } |
| 40 | const char *getCounterClass() const { return mCounterClass; } |
| 41 | const char *getUnit() const { return mUnit; } |
| 42 | double getMultiplier() const { return mMultiplier; } |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 43 | |
| 44 | int64_t read(); |
| 45 | |
| 46 | private: |
| 47 | void init(const sensors_chip_name *chip, const sensors_feature *feature); |
| 48 | |
Jon Medhurst | b1d0744 | 2015-05-08 12:04:18 +0100 | [diff] [blame] | 49 | const sensors_chip_name *mChip; |
| 50 | const sensors_feature *mFeature; |
| 51 | char *mLabel; |
| 52 | const char *mTitle; |
| 53 | const char *mDisplay; |
| 54 | const char *mCounterClass; |
| 55 | const char *mUnit; |
| 56 | double mPreviousValue; |
| 57 | double mMultiplier; |
| 58 | int mMonotonic: 1, |
| 59 | mDuplicate : 1; |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 60 | |
| 61 | // Intentionally unimplemented |
| 62 | HwmonCounter(const HwmonCounter &); |
| 63 | HwmonCounter &operator=(const HwmonCounter &); |
| 64 | }; |
| 65 | |
Jon Medhurst | b1d0744 | 2015-05-08 12:04:18 +0100 | [diff] [blame] | 66 | HwmonCounter::HwmonCounter(DriverCounter *next, char *const name, const sensors_chip_name *const chip, const sensors_feature *feature) : DriverCounter(next, name), mChip(chip), mFeature(feature), mDuplicate(false) { |
| 67 | mLabel = sensors_get_label(mChip, mFeature); |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 68 | |
Jon Medhurst | b1d0744 | 2015-05-08 12:04:18 +0100 | [diff] [blame] | 69 | switch (mFeature->type) { |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 70 | case SENSORS_FEATURE_IN: |
Jon Medhurst | b1d0744 | 2015-05-08 12:04:18 +0100 | [diff] [blame] | 71 | mTitle = "Voltage"; |
| 72 | mDisplay = "maximum"; |
| 73 | mCounterClass = "absolute"; |
| 74 | mUnit = "V"; |
| 75 | mMultiplier = 0.001; |
| 76 | mMonotonic = false; |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 77 | break; |
| 78 | case SENSORS_FEATURE_FAN: |
Jon Medhurst | b1d0744 | 2015-05-08 12:04:18 +0100 | [diff] [blame] | 79 | mTitle = "Fan"; |
| 80 | mDisplay = "average"; |
| 81 | mCounterClass = "absolute"; |
| 82 | mUnit = "RPM"; |
| 83 | mMultiplier = 1.0; |
| 84 | mMonotonic = false; |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 85 | break; |
| 86 | case SENSORS_FEATURE_TEMP: |
Jon Medhurst | b1d0744 | 2015-05-08 12:04:18 +0100 | [diff] [blame] | 87 | mTitle = "Temperature"; |
| 88 | mDisplay = "maximum"; |
| 89 | mCounterClass = "absolute"; |
| 90 | mUnit = "°C"; |
| 91 | mMultiplier = 0.001; |
| 92 | mMonotonic = false; |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 93 | break; |
| 94 | case SENSORS_FEATURE_POWER: |
Jon Medhurst | b1d0744 | 2015-05-08 12:04:18 +0100 | [diff] [blame] | 95 | mTitle = "Power"; |
| 96 | mDisplay = "maximum"; |
| 97 | mCounterClass = "absolute"; |
| 98 | mUnit = "W"; |
| 99 | mMultiplier = 0.000001; |
| 100 | mMonotonic = false; |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 101 | break; |
| 102 | case SENSORS_FEATURE_ENERGY: |
Jon Medhurst | b1d0744 | 2015-05-08 12:04:18 +0100 | [diff] [blame] | 103 | mTitle = "Energy"; |
| 104 | mDisplay = "accumulate"; |
| 105 | mCounterClass = "delta"; |
| 106 | mUnit = "J"; |
| 107 | mMultiplier = 0.000001; |
| 108 | mMonotonic = true; |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 109 | break; |
| 110 | case SENSORS_FEATURE_CURR: |
Jon Medhurst | b1d0744 | 2015-05-08 12:04:18 +0100 | [diff] [blame] | 111 | mTitle = "Current"; |
| 112 | mDisplay = "maximum"; |
| 113 | mCounterClass = "absolute"; |
| 114 | mUnit = "A"; |
| 115 | mMultiplier = 0.001; |
| 116 | mMonotonic = false; |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 117 | break; |
| 118 | case SENSORS_FEATURE_HUMIDITY: |
Jon Medhurst | b1d0744 | 2015-05-08 12:04:18 +0100 | [diff] [blame] | 119 | mTitle = "Humidity"; |
| 120 | mDisplay = "average"; |
| 121 | mCounterClass = "absolute"; |
| 122 | mUnit = "%"; |
| 123 | mMultiplier = 0.001; |
| 124 | mMonotonic = false; |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 125 | break; |
| 126 | default: |
Jon Medhurst | b1d0744 | 2015-05-08 12:04:18 +0100 | [diff] [blame] | 127 | logg->logError("Unsupported hwmon feature %i", mFeature->type); |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 128 | handleException(); |
| 129 | } |
| 130 | |
| 131 | for (HwmonCounter * counter = static_cast<HwmonCounter *>(next); counter != NULL; counter = static_cast<HwmonCounter *>(counter->getNext())) { |
Jon Medhurst | b1d0744 | 2015-05-08 12:04:18 +0100 | [diff] [blame] | 132 | if (strcmp(mLabel, counter->getLabel()) == 0 && strcmp(mTitle, counter->getTitle()) == 0) { |
| 133 | mDuplicate = true; |
| 134 | counter->mDuplicate = true; |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 135 | break; |
| 136 | } |
| 137 | } |
| 138 | } |
| 139 | |
| 140 | HwmonCounter::~HwmonCounter() { |
Jon Medhurst | b1d0744 | 2015-05-08 12:04:18 +0100 | [diff] [blame] | 141 | free((void *)mLabel); |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 142 | } |
| 143 | |
| 144 | int64_t HwmonCounter::read() { |
| 145 | double value; |
| 146 | double result; |
| 147 | const sensors_subfeature *subfeature; |
| 148 | |
| 149 | // Keep in sync with the read check in HwmonDriver::readEvents |
Jon Medhurst | b1d0744 | 2015-05-08 12:04:18 +0100 | [diff] [blame] | 150 | subfeature = sensors_get_subfeature(mChip, mFeature, getInput(mFeature->type)); |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 151 | if (!subfeature) { |
Jon Medhurst | b1d0744 | 2015-05-08 12:04:18 +0100 | [diff] [blame] | 152 | logg->logError("No input value for hwmon sensor %s", mLabel); |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 153 | handleException(); |
| 154 | } |
| 155 | |
Jon Medhurst | b1d0744 | 2015-05-08 12:04:18 +0100 | [diff] [blame] | 156 | if (sensors_get_value(mChip, subfeature->number, &value) != 0) { |
| 157 | logg->logError("Can't get input value for hwmon sensor %s", mLabel); |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 158 | handleException(); |
| 159 | } |
| 160 | |
Jon Medhurst | b1d0744 | 2015-05-08 12:04:18 +0100 | [diff] [blame] | 161 | result = (mMonotonic ? value - mPreviousValue : value); |
| 162 | mPreviousValue = value; |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 163 | |
| 164 | return result; |
| 165 | } |
| 166 | |
| 167 | HwmonDriver::HwmonDriver() { |
| 168 | } |
| 169 | |
| 170 | HwmonDriver::~HwmonDriver() { |
| 171 | sensors_cleanup(); |
| 172 | } |
| 173 | |
| 174 | void HwmonDriver::readEvents(mxml_node_t *const) { |
| 175 | int err = sensors_init(NULL); |
| 176 | if (err) { |
| 177 | logg->logMessage("Failed to initialize libsensors! (%d)", err); |
| 178 | return; |
| 179 | } |
| 180 | sensors_sysfs_no_scaling = 1; |
| 181 | |
| 182 | int chip_nr = 0; |
| 183 | const sensors_chip_name *chip; |
| 184 | while ((chip = sensors_get_detected_chips(NULL, &chip_nr))) { |
| 185 | int feature_nr = 0; |
| 186 | const sensors_feature *feature; |
| 187 | while ((feature = sensors_get_features(chip, &feature_nr))) { |
| 188 | // Keep in sync with HwmonCounter::read |
| 189 | // Can this counter be read? |
| 190 | double value; |
| 191 | const sensors_subfeature *const subfeature = sensors_get_subfeature(chip, feature, getInput(feature->type)); |
| 192 | if ((subfeature == NULL) || (sensors_get_value(chip, subfeature->number, &value) != 0)) { |
| 193 | continue; |
| 194 | } |
| 195 | |
| 196 | // Get the name of the counter |
| 197 | int len = sensors_snprintf_chip_name(NULL, 0, chip) + 1; |
| 198 | char *chip_name = new char[len]; |
| 199 | sensors_snprintf_chip_name(chip_name, len, chip); |
| 200 | len = snprintf(NULL, 0, "hwmon_%s_%d_%d", chip_name, chip_nr, feature->number) + 1; |
| 201 | char *const name = new char[len]; |
| 202 | snprintf(name, len, "hwmon_%s_%d_%d", chip_name, chip_nr, feature->number); |
| 203 | delete [] chip_name; |
| 204 | |
| 205 | setCounters(new HwmonCounter(getCounters(), name, chip, feature)); |
| 206 | } |
| 207 | } |
| 208 | } |
| 209 | |
| 210 | void HwmonDriver::writeEvents(mxml_node_t *root) const { |
| 211 | root = mxmlNewElement(root, "category"); |
Jon Medhurst | b1d0744 | 2015-05-08 12:04:18 +0100 | [diff] [blame] | 212 | mxmlElementSetAttr(root, "name", "Hardware Monitor"); |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 213 | |
| 214 | char buf[1024]; |
| 215 | for (HwmonCounter *counter = static_cast<HwmonCounter *>(getCounters()); counter != NULL; counter = static_cast<HwmonCounter *>(counter->getNext())) { |
| 216 | mxml_node_t *node = mxmlNewElement(root, "event"); |
| 217 | mxmlElementSetAttr(node, "counter", counter->getName()); |
| 218 | mxmlElementSetAttr(node, "title", counter->getTitle()); |
| 219 | if (counter->isDuplicate()) { |
| 220 | mxmlElementSetAttrf(node, "name", "%s (0x%x)", counter->getLabel(), counter->getKey()); |
| 221 | } else { |
| 222 | mxmlElementSetAttr(node, "name", counter->getLabel()); |
| 223 | } |
| 224 | mxmlElementSetAttr(node, "display", counter->getDisplay()); |
| 225 | mxmlElementSetAttr(node, "class", counter->getCounterClass()); |
| 226 | mxmlElementSetAttr(node, "units", counter->getUnit()); |
Jon Medhurst | b1d0744 | 2015-05-08 12:04:18 +0100 | [diff] [blame] | 227 | if (counter->getMultiplier() != 1.0) { |
| 228 | mxmlElementSetAttrf(node, "multiplier", "%lf", counter->getMultiplier()); |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 229 | } |
| 230 | if (strcmp(counter->getDisplay(), "average") == 0 || strcmp(counter->getDisplay(), "maximum") == 0) { |
| 231 | mxmlElementSetAttr(node, "average_selection", "yes"); |
| 232 | } |
| 233 | snprintf(buf, sizeof(buf), "libsensors %s sensor %s (%s)", counter->getTitle(), counter->getLabel(), counter->getName()); |
| 234 | mxmlElementSetAttr(node, "description", buf); |
| 235 | } |
| 236 | } |
| 237 | |
| 238 | void HwmonDriver::start() { |
| 239 | for (DriverCounter *counter = getCounters(); counter != NULL; counter = counter->getNext()) { |
| 240 | if (!counter->isEnabled()) { |
| 241 | continue; |
| 242 | } |
| 243 | counter->read(); |
| 244 | } |
| 245 | } |