| James Feist | 6ef2040 | 2019-01-07 16:45:08 -0800 | [diff] [blame] | 1 | /* | 
 | 2 | // Copyright (c) 2019 Intel Corporation | 
 | 3 | // | 
 | 4 | // Licensed under the Apache License, Version 2.0 (the "License"); | 
 | 5 | // you may not use this file except in compliance with the License. | 
 | 6 | // You may obtain a copy of the License at | 
 | 7 | // | 
 | 8 | //      http://www.apache.org/licenses/LICENSE-2.0 | 
 | 9 | // | 
 | 10 | // Unless required by applicable law or agreed to in writing, software | 
 | 11 | // distributed under the License is distributed on an "AS IS" BASIS, | 
 | 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 | 13 | // See the License for the specific language governing permissions and | 
 | 14 | // limitations under the License. | 
 | 15 | */ | 
 | 16 |  | 
 | 17 | #include "IpmbSensor.hpp" | 
 | 18 |  | 
 | 19 | #include "Utils.hpp" | 
 | 20 | #include "VariantVisitors.hpp" | 
 | 21 |  | 
 | 22 | #include <math.h> | 
 | 23 |  | 
 | 24 | #include <boost/algorithm/string.hpp> | 
 | 25 | #include <boost/algorithm/string/predicate.hpp> | 
 | 26 | #include <boost/algorithm/string/replace.hpp> | 
| Patrick Venture | 96e97db | 2019-10-31 13:44:38 -0700 | [diff] [blame] | 27 | #include <boost/container/flat_map.hpp> | 
| James Feist | 38fb598 | 2020-05-28 10:09:54 -0700 | [diff] [blame] | 28 | #include <sdbusplus/asio/connection.hpp> | 
 | 29 | #include <sdbusplus/asio/object_server.hpp> | 
 | 30 | #include <sdbusplus/bus/match.hpp> | 
 | 31 |  | 
| James Feist | 6ef2040 | 2019-01-07 16:45:08 -0800 | [diff] [blame] | 32 | #include <chrono> | 
| Patrick Venture | 96e97db | 2019-10-31 13:44:38 -0700 | [diff] [blame] | 33 | #include <functional> | 
| James Feist | 6ef2040 | 2019-01-07 16:45:08 -0800 | [diff] [blame] | 34 | #include <iostream> | 
 | 35 | #include <limits> | 
| Patrick Venture | 96e97db | 2019-10-31 13:44:38 -0700 | [diff] [blame] | 36 | #include <memory> | 
| James Feist | 6ef2040 | 2019-01-07 16:45:08 -0800 | [diff] [blame] | 37 | #include <numeric> | 
| Patrick Venture | 96e97db | 2019-10-31 13:44:38 -0700 | [diff] [blame] | 38 | #include <string> | 
 | 39 | #include <tuple> | 
 | 40 | #include <variant> | 
| James Feist | 6ef2040 | 2019-01-07 16:45:08 -0800 | [diff] [blame] | 41 | #include <vector> | 
 | 42 |  | 
 | 43 | constexpr const bool debug = false; | 
 | 44 |  | 
 | 45 | constexpr const char* configInterface = | 
 | 46 |     "xyz.openbmc_project.Configuration.IpmbSensor"; | 
 | 47 | static constexpr double ipmbMaxReading = 0xFF; | 
 | 48 | static constexpr double ipmbMinReading = 0; | 
 | 49 |  | 
 | 50 | static constexpr uint8_t meAddress = 1; | 
 | 51 | static constexpr uint8_t lun = 0; | 
 | 52 |  | 
| Vijay Khemka | 682a5cb | 2019-07-18 17:34:03 -0700 | [diff] [blame] | 53 | static constexpr const char* sensorPathPrefix = "/xyz/openbmc_project/sensors/"; | 
 | 54 |  | 
| James Feist | 6ef2040 | 2019-01-07 16:45:08 -0800 | [diff] [blame] | 55 | using IpmbMethodType = | 
 | 56 |     std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>; | 
 | 57 |  | 
| James Feist | f7e2c5d | 2019-02-13 17:27:51 -0800 | [diff] [blame] | 58 | boost::container::flat_map<std::string, std::unique_ptr<IpmbSensor>> sensors; | 
 | 59 |  | 
| James Feist | 0d4f2bd | 2019-03-05 13:15:40 -0800 | [diff] [blame] | 60 | std::unique_ptr<boost::asio::deadline_timer> initCmdTimer; | 
 | 61 |  | 
| James Feist | 6ef2040 | 2019-01-07 16:45:08 -0800 | [diff] [blame] | 62 | IpmbSensor::IpmbSensor(std::shared_ptr<sdbusplus::asio::connection>& conn, | 
 | 63 |                        boost::asio::io_service& io, | 
 | 64 |                        const std::string& sensorName, | 
 | 65 |                        const std::string& sensorConfiguration, | 
 | 66 |                        sdbusplus::asio::object_server& objectServer, | 
 | 67 |                        std::vector<thresholds::Threshold>&& thresholdData, | 
| Vijay Khemka | 682a5cb | 2019-07-18 17:34:03 -0700 | [diff] [blame] | 68 |                        uint8_t deviceAddress, std::string& sensorTypeName) : | 
| James Feist | 6ef2040 | 2019-01-07 16:45:08 -0800 | [diff] [blame] | 69 |     Sensor(boost::replace_all_copy(sensorName, " ", "_"), | 
| James Feist | 930fcde | 2019-05-28 12:58:43 -0700 | [diff] [blame] | 70 |            std::move(thresholdData), sensorConfiguration, | 
 | 71 |            "xyz.openbmc_project.Configuration.ExitAirTemp", ipmbMaxReading, | 
| James Feist | 961bf09 | 2020-07-01 16:38:12 -0700 | [diff] [blame] | 72 |            ipmbMinReading, PowerState::on), | 
 | 73 |     deviceAddress(deviceAddress), objectServer(objectServer), | 
 | 74 |     dbusConnection(conn), waitTimer(io) | 
| James Feist | 6ef2040 | 2019-01-07 16:45:08 -0800 | [diff] [blame] | 75 | { | 
| Vijay Khemka | 682a5cb | 2019-07-18 17:34:03 -0700 | [diff] [blame] | 76 |     std::string dbusPath = sensorPathPrefix + sensorTypeName + "/" + name; | 
 | 77 |  | 
| James Feist | 6ef2040 | 2019-01-07 16:45:08 -0800 | [diff] [blame] | 78 |     sensorInterface = objectServer.add_interface( | 
| Vijay Khemka | 682a5cb | 2019-07-18 17:34:03 -0700 | [diff] [blame] | 79 |         dbusPath, "xyz.openbmc_project.Sensor.Value"); | 
| James Feist | 6ef2040 | 2019-01-07 16:45:08 -0800 | [diff] [blame] | 80 |  | 
 | 81 |     if (thresholds::hasWarningInterface(thresholds)) | 
 | 82 |     { | 
 | 83 |         thresholdInterfaceWarning = objectServer.add_interface( | 
| Vijay Khemka | 682a5cb | 2019-07-18 17:34:03 -0700 | [diff] [blame] | 84 |             dbusPath, "xyz.openbmc_project.Sensor.Threshold.Warning"); | 
| James Feist | 6ef2040 | 2019-01-07 16:45:08 -0800 | [diff] [blame] | 85 |     } | 
 | 86 |     if (thresholds::hasCriticalInterface(thresholds)) | 
 | 87 |     { | 
 | 88 |         thresholdInterfaceCritical = objectServer.add_interface( | 
| Vijay Khemka | 682a5cb | 2019-07-18 17:34:03 -0700 | [diff] [blame] | 89 |             dbusPath, "xyz.openbmc_project.Sensor.Threshold.Critical"); | 
| James Feist | 6ef2040 | 2019-01-07 16:45:08 -0800 | [diff] [blame] | 90 |     } | 
| James Feist | 2adc95c | 2019-09-30 14:55:28 -0700 | [diff] [blame] | 91 |     association = objectServer.add_interface(dbusPath, association::interface); | 
| James Feist | 6ef2040 | 2019-01-07 16:45:08 -0800 | [diff] [blame] | 92 | } | 
 | 93 |  | 
 | 94 | IpmbSensor::~IpmbSensor() | 
 | 95 | { | 
 | 96 |     waitTimer.cancel(); | 
 | 97 |     objectServer.remove_interface(thresholdInterfaceWarning); | 
 | 98 |     objectServer.remove_interface(thresholdInterfaceCritical); | 
 | 99 |     objectServer.remove_interface(sensorInterface); | 
| James Feist | 078f232 | 2019-03-08 11:09:05 -0800 | [diff] [blame] | 100 |     objectServer.remove_interface(association); | 
| James Feist | 6ef2040 | 2019-01-07 16:45:08 -0800 | [diff] [blame] | 101 | } | 
 | 102 |  | 
 | 103 | void IpmbSensor::init(void) | 
 | 104 | { | 
| James Feist | 6ef2040 | 2019-01-07 16:45:08 -0800 | [diff] [blame] | 105 |     loadDefaults(); | 
| Adrian Ambrożewicz | 45e9277 | 2020-06-04 13:59:55 +0200 | [diff] [blame] | 106 |     setInitialProperties(dbusConnection); | 
| James Feist | 6ef2040 | 2019-01-07 16:45:08 -0800 | [diff] [blame] | 107 |     if (initCommand) | 
 | 108 |     { | 
| James Feist | f7e2c5d | 2019-02-13 17:27:51 -0800 | [diff] [blame] | 109 |         runInitCmd(); | 
 | 110 |     } | 
 | 111 |     read(); | 
 | 112 | } | 
 | 113 |  | 
 | 114 | void IpmbSensor::runInitCmd() | 
 | 115 | { | 
 | 116 |     if (initCommand) | 
 | 117 |     { | 
| James Feist | 6ef2040 | 2019-01-07 16:45:08 -0800 | [diff] [blame] | 118 |         dbusConnection->async_method_call( | 
 | 119 |             [this](boost::system::error_code ec, | 
 | 120 |                    const IpmbMethodType& response) { | 
 | 121 |                 const int& status = std::get<0>(response); | 
 | 122 |  | 
 | 123 |                 if (ec || status) | 
 | 124 |                 { | 
 | 125 |                     std::cerr | 
 | 126 |                         << "Error setting init command for device: " << name | 
 | 127 |                         << "\n"; | 
 | 128 |                 } | 
| James Feist | 6ef2040 | 2019-01-07 16:45:08 -0800 | [diff] [blame] | 129 |             }, | 
 | 130 |             "xyz.openbmc_project.Ipmi.Channel.Ipmb", | 
 | 131 |             "/xyz/openbmc_project/Ipmi/Channel/Ipmb", "org.openbmc.Ipmb", | 
 | 132 |             "sendRequest", commandAddress, netfn, lun, *initCommand, initData); | 
 | 133 |     } | 
| James Feist | 6ef2040 | 2019-01-07 16:45:08 -0800 | [diff] [blame] | 134 | } | 
 | 135 |  | 
 | 136 | void IpmbSensor::loadDefaults() | 
 | 137 | { | 
 | 138 |     if (type == IpmbType::meSensor) | 
 | 139 |     { | 
 | 140 |         commandAddress = meAddress; | 
| Adrian Ambrożewicz | 58e02ef | 2020-08-06 14:42:38 +0200 | [diff] [blame] | 141 |         netfn = ipmi::sensor::netFn; | 
 | 142 |         command = ipmi::sensor::getSensorReading; | 
| James Feist | 6ef2040 | 2019-01-07 16:45:08 -0800 | [diff] [blame] | 143 |         commandData = {deviceAddress}; | 
| James Feist | d7ae29a | 2020-06-25 15:42:46 -0700 | [diff] [blame] | 144 |         readingFormat = ReadingFormat::byte0; | 
| James Feist | 6ef2040 | 2019-01-07 16:45:08 -0800 | [diff] [blame] | 145 |     } | 
 | 146 |     else if (type == IpmbType::PXE1410CVR) | 
 | 147 |     { | 
 | 148 |         commandAddress = meAddress; | 
| Adrian Ambrożewicz | 58e02ef | 2020-08-06 14:42:38 +0200 | [diff] [blame] | 149 |         netfn = ipmi::me_bridge::netFn; | 
 | 150 |         command = ipmi::me_bridge::sendRawPmbus; | 
 | 151 |         initCommand = ipmi::me_bridge::sendRawPmbus; | 
| James Feist | d7ae29a | 2020-06-25 15:42:46 -0700 | [diff] [blame] | 152 |         // pmbus read temp | 
 | 153 |         commandData = {0x57, 0x01, 0x00, 0x16, 0x3,  deviceAddress, 0x00, | 
 | 154 |                        0x00, 0x00, 0x00, 0x01, 0x02, 0x8d}; | 
 | 155 |         // goto page 0 | 
| James Feist | 6ef2040 | 2019-01-07 16:45:08 -0800 | [diff] [blame] | 156 |         initData = {0x57, 0x01, 0x00, 0x14, 0x03, deviceAddress, 0x00, | 
| James Feist | d7ae29a | 2020-06-25 15:42:46 -0700 | [diff] [blame] | 157 |                     0x00, 0x00, 0x00, 0x02, 0x00, 0x00,          0x00}; | 
| James Feist | e4a970d | 2020-08-19 11:21:58 -0700 | [diff] [blame] | 158 |         readingFormat = ReadingFormat::elevenBit; | 
| James Feist | 6ef2040 | 2019-01-07 16:45:08 -0800 | [diff] [blame] | 159 |     } | 
 | 160 |     else if (type == IpmbType::IR38363VR) | 
 | 161 |     { | 
 | 162 |         commandAddress = meAddress; | 
| Adrian Ambrożewicz | 58e02ef | 2020-08-06 14:42:38 +0200 | [diff] [blame] | 163 |         netfn = ipmi::me_bridge::netFn; | 
 | 164 |         command = ipmi::me_bridge::sendRawPmbus; | 
| James Feist | d7ae29a | 2020-06-25 15:42:46 -0700 | [diff] [blame] | 165 |         // pmbus read temp | 
| James Feist | 6ef2040 | 2019-01-07 16:45:08 -0800 | [diff] [blame] | 166 |         commandData = {0x57, 0x01, 0x00, 0x16, 0x03, deviceAddress, 00, | 
 | 167 |                        0x00, 0x00, 0x00, 0x01, 0x02, 0x8D}; | 
| James Feist | d7ae29a | 2020-06-25 15:42:46 -0700 | [diff] [blame] | 168 |         readingFormat = ReadingFormat::elevenBitShift; | 
| James Feist | 6ef2040 | 2019-01-07 16:45:08 -0800 | [diff] [blame] | 169 |     } | 
| Vijay Khemka | 682a5cb | 2019-07-18 17:34:03 -0700 | [diff] [blame] | 170 |     else if (type == IpmbType::ADM1278HSC) | 
 | 171 |     { | 
 | 172 |         commandAddress = meAddress; | 
 | 173 |         switch (subType) | 
 | 174 |         { | 
 | 175 |             case IpmbSubType::temp: | 
 | 176 |             case IpmbSubType::curr: | 
 | 177 |                 uint8_t snsNum; | 
 | 178 |                 if (subType == IpmbSubType::temp) | 
 | 179 |                     snsNum = 0x8d; | 
 | 180 |                 else | 
 | 181 |                     snsNum = 0x8c; | 
| Adrian Ambrożewicz | 58e02ef | 2020-08-06 14:42:38 +0200 | [diff] [blame] | 182 |                 netfn = ipmi::me_bridge::netFn; | 
 | 183 |                 command = ipmi::me_bridge::sendRawPmbus; | 
| Vijay Khemka | 682a5cb | 2019-07-18 17:34:03 -0700 | [diff] [blame] | 184 |                 commandData = {0x57, 0x01, 0x00, 0x86, deviceAddress, | 
 | 185 |                                0x00, 0x00, 0x01, 0x02, snsNum}; | 
| James Feist | d7ae29a | 2020-06-25 15:42:46 -0700 | [diff] [blame] | 186 |                 readingFormat = ReadingFormat::elevenBit; | 
| Vijay Khemka | 682a5cb | 2019-07-18 17:34:03 -0700 | [diff] [blame] | 187 |                 break; | 
 | 188 |             case IpmbSubType::power: | 
 | 189 |             case IpmbSubType::volt: | 
| Adrian Ambrożewicz | 58e02ef | 2020-08-06 14:42:38 +0200 | [diff] [blame] | 190 |                 netfn = ipmi::sensor::netFn; | 
 | 191 |                 command = ipmi::sensor::getSensorReading; | 
| Vijay Khemka | 682a5cb | 2019-07-18 17:34:03 -0700 | [diff] [blame] | 192 |                 commandData = {deviceAddress}; | 
| James Feist | d7ae29a | 2020-06-25 15:42:46 -0700 | [diff] [blame] | 193 |                 readingFormat = ReadingFormat::byte0; | 
| Vijay Khemka | 682a5cb | 2019-07-18 17:34:03 -0700 | [diff] [blame] | 194 |                 break; | 
 | 195 |             default: | 
 | 196 |                 throw std::runtime_error("Invalid sensor type"); | 
 | 197 |         } | 
 | 198 |     } | 
| James Feist | 6ef2040 | 2019-01-07 16:45:08 -0800 | [diff] [blame] | 199 |     else if (type == IpmbType::mpsVR) | 
 | 200 |     { | 
 | 201 |         commandAddress = meAddress; | 
| Adrian Ambrożewicz | 58e02ef | 2020-08-06 14:42:38 +0200 | [diff] [blame] | 202 |         netfn = ipmi::me_bridge::netFn; | 
 | 203 |         command = ipmi::me_bridge::sendRawPmbus; | 
 | 204 |         initCommand = ipmi::me_bridge::sendRawPmbus; | 
| James Feist | d7ae29a | 2020-06-25 15:42:46 -0700 | [diff] [blame] | 205 |         // pmbus read temp | 
| James Feist | 6ef2040 | 2019-01-07 16:45:08 -0800 | [diff] [blame] | 206 |         commandData = {0x57, 0x01, 0x00, 0x16, 0x3,  deviceAddress, 0x00, | 
 | 207 |                        0x00, 0x00, 0x00, 0x01, 0x02, 0x8d}; | 
| James Feist | d7ae29a | 2020-06-25 15:42:46 -0700 | [diff] [blame] | 208 |         // goto page 0 | 
| James Feist | 6ef2040 | 2019-01-07 16:45:08 -0800 | [diff] [blame] | 209 |         initData = {0x57, 0x01, 0x00, 0x14, 0x03, deviceAddress, 0x00, | 
 | 210 |                     0x00, 0x00, 0x00, 0x02, 0x00, 0x00,          0x00}; | 
| James Feist | d7ae29a | 2020-06-25 15:42:46 -0700 | [diff] [blame] | 211 |         readingFormat = ReadingFormat::byte3; | 
| James Feist | 6ef2040 | 2019-01-07 16:45:08 -0800 | [diff] [blame] | 212 |     } | 
 | 213 |     else | 
 | 214 |     { | 
 | 215 |         throw std::runtime_error("Invalid sensor type"); | 
 | 216 |     } | 
| Adrian Ambrożewicz | 45e9277 | 2020-06-04 13:59:55 +0200 | [diff] [blame] | 217 |  | 
 | 218 |     if (subType == IpmbSubType::util) | 
 | 219 |     { | 
 | 220 |         // Utilization need to be scaled to percent | 
 | 221 |         maxValue = 100; | 
 | 222 |         minValue = 0; | 
 | 223 |     } | 
| James Feist | 6ef2040 | 2019-01-07 16:45:08 -0800 | [diff] [blame] | 224 | } | 
 | 225 |  | 
 | 226 | void IpmbSensor::checkThresholds(void) | 
 | 227 | { | 
| James Feist | 6ef2040 | 2019-01-07 16:45:08 -0800 | [diff] [blame] | 228 |     thresholds::checkThresholds(this); | 
 | 229 | } | 
 | 230 |  | 
| James Feist | 961bf09 | 2020-07-01 16:38:12 -0700 | [diff] [blame] | 231 | bool IpmbSensor::processReading(const std::vector<uint8_t>& data, double& resp) | 
| James Feist | d7ae29a | 2020-06-25 15:42:46 -0700 | [diff] [blame] | 232 | { | 
 | 233 |  | 
 | 234 |     switch (readingFormat) | 
 | 235 |     { | 
 | 236 |         case (ReadingFormat::byte0): | 
| James Feist | e4a970d | 2020-08-19 11:21:58 -0700 | [diff] [blame] | 237 |         { | 
| Adrian Ambrożewicz | 58e02ef | 2020-08-06 14:42:38 +0200 | [diff] [blame] | 238 |             if (command == ipmi::sensor::getSensorReading && | 
 | 239 |                 !ipmi::sensor::isValid(data)) | 
| James Feist | cf4238e | 2020-07-28 16:40:03 -0700 | [diff] [blame] | 240 |             { | 
 | 241 |                 return false; | 
 | 242 |             } | 
| James Feist | 961bf09 | 2020-07-01 16:38:12 -0700 | [diff] [blame] | 243 |             resp = data[0]; | 
 | 244 |             return true; | 
| James Feist | e4a970d | 2020-08-19 11:21:58 -0700 | [diff] [blame] | 245 |         } | 
| James Feist | d7ae29a | 2020-06-25 15:42:46 -0700 | [diff] [blame] | 246 |         case (ReadingFormat::byte3): | 
| James Feist | e4a970d | 2020-08-19 11:21:58 -0700 | [diff] [blame] | 247 |         { | 
| James Feist | d7ae29a | 2020-06-25 15:42:46 -0700 | [diff] [blame] | 248 |             if (data.size() < 4) | 
 | 249 |             { | 
| James Feist | 961bf09 | 2020-07-01 16:38:12 -0700 | [diff] [blame] | 250 |                 if (!errCount) | 
 | 251 |                 { | 
 | 252 |                     std::cerr << "Invalid data length returned for " << name | 
 | 253 |                               << "\n"; | 
 | 254 |                 } | 
 | 255 |                 return false; | 
| James Feist | d7ae29a | 2020-06-25 15:42:46 -0700 | [diff] [blame] | 256 |             } | 
| James Feist | 961bf09 | 2020-07-01 16:38:12 -0700 | [diff] [blame] | 257 |             resp = data[3]; | 
 | 258 |             return true; | 
| James Feist | e4a970d | 2020-08-19 11:21:58 -0700 | [diff] [blame] | 259 |         } | 
| James Feist | d7ae29a | 2020-06-25 15:42:46 -0700 | [diff] [blame] | 260 |         case (ReadingFormat::elevenBit): | 
| James Feist | e4a970d | 2020-08-19 11:21:58 -0700 | [diff] [blame] | 261 |         { | 
| James Feist | d7ae29a | 2020-06-25 15:42:46 -0700 | [diff] [blame] | 262 |             if (data.size() < 5) | 
 | 263 |             { | 
| James Feist | 961bf09 | 2020-07-01 16:38:12 -0700 | [diff] [blame] | 264 |                 if (!errCount) | 
 | 265 |                 { | 
 | 266 |                     std::cerr << "Invalid data length returned for " << name | 
 | 267 |                               << "\n"; | 
 | 268 |                 } | 
 | 269 |                 return false; | 
| James Feist | d7ae29a | 2020-06-25 15:42:46 -0700 | [diff] [blame] | 270 |             } | 
 | 271 |  | 
| James Feist | e4a970d | 2020-08-19 11:21:58 -0700 | [diff] [blame] | 272 |             int16_t value = ((data[4] << 8) | data[3]); | 
 | 273 |             constexpr const size_t shift = 16 - 11; // 11bit into 16bit | 
 | 274 |             value <<= shift; | 
 | 275 |             value >>= shift; | 
 | 276 |             resp = value; | 
| James Feist | 961bf09 | 2020-07-01 16:38:12 -0700 | [diff] [blame] | 277 |             return true; | 
| James Feist | e4a970d | 2020-08-19 11:21:58 -0700 | [diff] [blame] | 278 |         } | 
| James Feist | d7ae29a | 2020-06-25 15:42:46 -0700 | [diff] [blame] | 279 |         case (ReadingFormat::elevenBitShift): | 
| James Feist | e4a970d | 2020-08-19 11:21:58 -0700 | [diff] [blame] | 280 |         { | 
| James Feist | d7ae29a | 2020-06-25 15:42:46 -0700 | [diff] [blame] | 281 |             if (data.size() < 5) | 
 | 282 |             { | 
| James Feist | 961bf09 | 2020-07-01 16:38:12 -0700 | [diff] [blame] | 283 |                 if (!errCount) | 
 | 284 |                 { | 
 | 285 |                     std::cerr << "Invalid data length returned for " << name | 
 | 286 |                               << "\n"; | 
 | 287 |                 } | 
 | 288 |                 return false; | 
| James Feist | d7ae29a | 2020-06-25 15:42:46 -0700 | [diff] [blame] | 289 |             } | 
 | 290 |  | 
| James Feist | 961bf09 | 2020-07-01 16:38:12 -0700 | [diff] [blame] | 291 |             resp = ((data[4] << 8) | data[3]) >> 3; | 
 | 292 |             return true; | 
| James Feist | e4a970d | 2020-08-19 11:21:58 -0700 | [diff] [blame] | 293 |         } | 
| James Feist | d7ae29a | 2020-06-25 15:42:46 -0700 | [diff] [blame] | 294 |         default: | 
 | 295 |             throw std::runtime_error("Invalid reading type"); | 
 | 296 |     } | 
 | 297 | } | 
 | 298 |  | 
| James Feist | 6ef2040 | 2019-01-07 16:45:08 -0800 | [diff] [blame] | 299 | void IpmbSensor::read(void) | 
 | 300 | { | 
 | 301 |     static constexpr size_t pollTime = 1; // in seconds | 
 | 302 |  | 
 | 303 |     waitTimer.expires_from_now(boost::posix_time::seconds(pollTime)); | 
 | 304 |     waitTimer.async_wait([this](const boost::system::error_code& ec) { | 
 | 305 |         if (ec == boost::asio::error::operation_aborted) | 
 | 306 |         { | 
 | 307 |             return; // we're being canceled | 
 | 308 |         } | 
| Adrian Ambrożewicz | 623723b | 2020-07-29 12:53:54 +0200 | [diff] [blame] | 309 |         if (!readingStateGood()) | 
| James Feist | 6ef2040 | 2019-01-07 16:45:08 -0800 | [diff] [blame] | 310 |         { | 
| Adrian Ambrożewicz | 623723b | 2020-07-29 12:53:54 +0200 | [diff] [blame] | 311 |             updateValue(std::numeric_limits<double>::quiet_NaN()); | 
| James Feist | 6ef2040 | 2019-01-07 16:45:08 -0800 | [diff] [blame] | 312 |             read(); | 
 | 313 |             return; | 
 | 314 |         } | 
 | 315 |         dbusConnection->async_method_call( | 
 | 316 |             [this](boost::system::error_code ec, | 
 | 317 |                    const IpmbMethodType& response) { | 
 | 318 |                 const int& status = std::get<0>(response); | 
 | 319 |                 if (ec || status) | 
 | 320 |                 { | 
| James Feist | 961bf09 | 2020-07-01 16:38:12 -0700 | [diff] [blame] | 321 |                     incrementError(); | 
| James Feist | 6ef2040 | 2019-01-07 16:45:08 -0800 | [diff] [blame] | 322 |                     read(); | 
 | 323 |                     return; | 
 | 324 |                 } | 
 | 325 |                 const std::vector<uint8_t>& data = std::get<5>(response); | 
 | 326 |                 if constexpr (debug) | 
 | 327 |                 { | 
 | 328 |                     std::cout << name << ": "; | 
 | 329 |                     for (size_t d : data) | 
 | 330 |                     { | 
 | 331 |                         std::cout << d << " "; | 
 | 332 |                     } | 
 | 333 |                     std::cout << "\n"; | 
 | 334 |                 } | 
| James Feist | d7ae29a | 2020-06-25 15:42:46 -0700 | [diff] [blame] | 335 |                 if (data.empty()) | 
| James Feist | 6ef2040 | 2019-01-07 16:45:08 -0800 | [diff] [blame] | 336 |                 { | 
| James Feist | 961bf09 | 2020-07-01 16:38:12 -0700 | [diff] [blame] | 337 |                     incrementError(); | 
| James Feist | d7ae29a | 2020-06-25 15:42:46 -0700 | [diff] [blame] | 338 |                     read(); | 
 | 339 |                     return; | 
| James Feist | 6ef2040 | 2019-01-07 16:45:08 -0800 | [diff] [blame] | 340 |                 } | 
| James Feist | 961bf09 | 2020-07-01 16:38:12 -0700 | [diff] [blame] | 341 |  | 
 | 342 |                 double value = 0; | 
 | 343 |  | 
 | 344 |                 if (!processReading(data, value)) | 
 | 345 |                 { | 
 | 346 |                     incrementError(); | 
 | 347 |                     read(); | 
 | 348 |                     return; | 
 | 349 |                 } | 
| Zhikui Ren | d3da128 | 2020-09-11 17:02:01 -0700 | [diff] [blame^] | 350 |                 else | 
 | 351 |                 { | 
 | 352 |                     // rawValue only used in debug logging | 
 | 353 |                     // up to 5th byte in data are used to derive value | 
 | 354 |                     size_t end = std::min(sizeof(uint64_t), data.size()); | 
 | 355 |                     uint64_t rawData = 0; | 
 | 356 |                     for (size_t i = 0; i < end; i++) | 
 | 357 |                     { | 
 | 358 |                         reinterpret_cast<uint8_t*>(&rawData)[i] = data[i]; | 
 | 359 |                     } | 
 | 360 |                     rawValue = static_cast<double>(rawData); | 
 | 361 |                 } | 
| Vijay Khemka | 682a5cb | 2019-07-18 17:34:03 -0700 | [diff] [blame] | 362 |  | 
 | 363 |                 /* Adjust value as per scale and offset */ | 
 | 364 |                 value = (value * scaleVal) + offsetVal; | 
| James Feist | 6ef2040 | 2019-01-07 16:45:08 -0800 | [diff] [blame] | 365 |                 updateValue(value); | 
 | 366 |                 read(); | 
 | 367 |             }, | 
 | 368 |             "xyz.openbmc_project.Ipmi.Channel.Ipmb", | 
 | 369 |             "/xyz/openbmc_project/Ipmi/Channel/Ipmb", "org.openbmc.Ipmb", | 
 | 370 |             "sendRequest", commandAddress, netfn, lun, command, commandData); | 
 | 371 |     }); | 
 | 372 | } | 
 | 373 | void createSensors( | 
 | 374 |     boost::asio::io_service& io, sdbusplus::asio::object_server& objectServer, | 
 | 375 |     boost::container::flat_map<std::string, std::unique_ptr<IpmbSensor>>& | 
 | 376 |         sensors, | 
 | 377 |     std::shared_ptr<sdbusplus::asio::connection>& dbusConnection) | 
 | 378 | { | 
 | 379 |     if (!dbusConnection) | 
 | 380 |     { | 
 | 381 |         std::cerr << "Connection not created\n"; | 
 | 382 |         return; | 
 | 383 |     } | 
 | 384 |     dbusConnection->async_method_call( | 
 | 385 |         [&](boost::system::error_code ec, const ManagedObjectType& resp) { | 
 | 386 |             if (ec) | 
 | 387 |             { | 
 | 388 |                 std::cerr << "Error contacting entity manager\n"; | 
 | 389 |                 return; | 
 | 390 |             } | 
 | 391 |             for (const auto& pathPair : resp) | 
 | 392 |             { | 
 | 393 |                 for (const auto& entry : pathPair.second) | 
 | 394 |                 { | 
 | 395 |                     if (entry.first != configInterface) | 
 | 396 |                     { | 
 | 397 |                         continue; | 
 | 398 |                     } | 
 | 399 |                     std::string name = | 
 | 400 |                         loadVariant<std::string>(entry.second, "Name"); | 
 | 401 |  | 
 | 402 |                     std::vector<thresholds::Threshold> sensorThresholds; | 
 | 403 |                     if (!parseThresholdsFromConfig(pathPair.second, | 
 | 404 |                                                    sensorThresholds)) | 
 | 405 |                     { | 
 | 406 |                         std::cerr << "error populating thresholds for " << name | 
 | 407 |                                   << "\n"; | 
 | 408 |                     } | 
 | 409 |                     uint8_t deviceAddress = | 
 | 410 |                         loadVariant<uint8_t>(entry.second, "Address"); | 
 | 411 |  | 
 | 412 |                     std::string sensorClass = | 
 | 413 |                         loadVariant<std::string>(entry.second, "Class"); | 
| Vijay Khemka | 682a5cb | 2019-07-18 17:34:03 -0700 | [diff] [blame] | 414 |  | 
 | 415 |                     /* Default sensor type is "temperature" */ | 
 | 416 |                     std::string sensorTypeName = "temperature"; | 
 | 417 |                     auto findType = entry.second.find("SensorType"); | 
 | 418 |                     if (findType != entry.second.end()) | 
 | 419 |                     { | 
 | 420 |                         sensorTypeName = std::visit(VariantToStringVisitor(), | 
 | 421 |                                                     findType->second); | 
 | 422 |                     } | 
 | 423 |  | 
| James Feist | 6ef2040 | 2019-01-07 16:45:08 -0800 | [diff] [blame] | 424 |                     auto& sensor = sensors[name]; | 
 | 425 |                     sensor = std::make_unique<IpmbSensor>( | 
 | 426 |                         dbusConnection, io, name, pathPair.first, objectServer, | 
| Vijay Khemka | 682a5cb | 2019-07-18 17:34:03 -0700 | [diff] [blame] | 427 |                         std::move(sensorThresholds), deviceAddress, | 
 | 428 |                         sensorTypeName); | 
 | 429 |  | 
 | 430 |                     /* Initialize scale and offset value */ | 
 | 431 |                     sensor->scaleVal = 1; | 
 | 432 |                     sensor->offsetVal = 0; | 
 | 433 |  | 
 | 434 |                     auto findScaleVal = entry.second.find("ScaleValue"); | 
 | 435 |                     if (findScaleVal != entry.second.end()) | 
 | 436 |                     { | 
 | 437 |                         sensor->scaleVal = std::visit(VariantToDoubleVisitor(), | 
 | 438 |                                                       findScaleVal->second); | 
 | 439 |                     } | 
 | 440 |  | 
 | 441 |                     auto findOffsetVal = entry.second.find("OffsetValue"); | 
 | 442 |                     if (findOffsetVal != entry.second.end()) | 
 | 443 |                     { | 
 | 444 |                         sensor->offsetVal = std::visit(VariantToDoubleVisitor(), | 
 | 445 |                                                        findOffsetVal->second); | 
 | 446 |                     } | 
| James Feist | 6ef2040 | 2019-01-07 16:45:08 -0800 | [diff] [blame] | 447 |  | 
| James Feist | fc94b21 | 2019-02-06 16:14:51 -0800 | [diff] [blame] | 448 |                     auto findPowerState = entry.second.find("PowerState"); | 
 | 449 |  | 
 | 450 |                     if (findPowerState != entry.second.end()) | 
 | 451 |                     { | 
 | 452 |                         std::string powerState = std::visit( | 
 | 453 |                             VariantToStringVisitor(), findPowerState->second); | 
 | 454 |  | 
 | 455 |                         setReadState(powerState, sensor->readState); | 
 | 456 |                     } | 
 | 457 |  | 
| James Feist | 6ef2040 | 2019-01-07 16:45:08 -0800 | [diff] [blame] | 458 |                     if (sensorClass == "PxeBridgeTemp") | 
 | 459 |                     { | 
 | 460 |                         sensor->type = IpmbType::PXE1410CVR; | 
 | 461 |                     } | 
 | 462 |                     else if (sensorClass == "IRBridgeTemp") | 
 | 463 |                     { | 
 | 464 |                         sensor->type = IpmbType::IR38363VR; | 
 | 465 |                     } | 
| Vijay Khemka | 682a5cb | 2019-07-18 17:34:03 -0700 | [diff] [blame] | 466 |                     else if (sensorClass == "HSCBridge") | 
 | 467 |                     { | 
 | 468 |                         sensor->type = IpmbType::ADM1278HSC; | 
 | 469 |                     } | 
| James Feist | 6ef2040 | 2019-01-07 16:45:08 -0800 | [diff] [blame] | 470 |                     else if (sensorClass == "MpsBridgeTemp") | 
 | 471 |                     { | 
 | 472 |                         sensor->type = IpmbType::mpsVR; | 
 | 473 |                     } | 
| Adrian Ambrożewicz | 45e9277 | 2020-06-04 13:59:55 +0200 | [diff] [blame] | 474 |                     else if (sensorClass == "METemp" || | 
 | 475 |                              sensorClass == "MESensor") | 
| James Feist | 6ef2040 | 2019-01-07 16:45:08 -0800 | [diff] [blame] | 476 |                     { | 
 | 477 |                         sensor->type = IpmbType::meSensor; | 
 | 478 |                     } | 
 | 479 |                     else | 
 | 480 |                     { | 
 | 481 |                         std::cerr << "Invalid class " << sensorClass << "\n"; | 
 | 482 |                         continue; | 
 | 483 |                     } | 
| Vijay Khemka | 682a5cb | 2019-07-18 17:34:03 -0700 | [diff] [blame] | 484 |  | 
 | 485 |                     if (sensorTypeName == "voltage") | 
 | 486 |                     { | 
 | 487 |                         sensor->subType = IpmbSubType::volt; | 
 | 488 |                     } | 
 | 489 |                     else if (sensorTypeName == "power") | 
 | 490 |                     { | 
 | 491 |                         sensor->subType = IpmbSubType::power; | 
 | 492 |                     } | 
 | 493 |                     else if (sensorTypeName == "current") | 
 | 494 |                     { | 
 | 495 |                         sensor->subType = IpmbSubType::curr; | 
 | 496 |                     } | 
| Adrian Ambrożewicz | 45e9277 | 2020-06-04 13:59:55 +0200 | [diff] [blame] | 497 |                     else if (sensorTypeName == "utilization") | 
 | 498 |                     { | 
 | 499 |                         sensor->subType = IpmbSubType::util; | 
 | 500 |                     } | 
| Vijay Khemka | 682a5cb | 2019-07-18 17:34:03 -0700 | [diff] [blame] | 501 |                     else | 
 | 502 |                     { | 
 | 503 |                         sensor->subType = IpmbSubType::temp; | 
 | 504 |                     } | 
| James Feist | 6ef2040 | 2019-01-07 16:45:08 -0800 | [diff] [blame] | 505 |                     sensor->init(); | 
 | 506 |                 } | 
 | 507 |             } | 
 | 508 |         }, | 
 | 509 |         entityManagerName, "/", "org.freedesktop.DBus.ObjectManager", | 
 | 510 |         "GetManagedObjects"); | 
 | 511 | } | 
 | 512 |  | 
| James Feist | f7e2c5d | 2019-02-13 17:27:51 -0800 | [diff] [blame] | 513 | void reinitSensors(sdbusplus::message::message& message) | 
 | 514 | { | 
| James Feist | 0d4f2bd | 2019-03-05 13:15:40 -0800 | [diff] [blame] | 515 |     constexpr const size_t reinitWaitSeconds = 2; | 
| James Feist | f7e2c5d | 2019-02-13 17:27:51 -0800 | [diff] [blame] | 516 |     std::string objectName; | 
| James Feist | 52497fd | 2019-06-07 13:01:33 -0700 | [diff] [blame] | 517 |     boost::container::flat_map<std::string, std::variant<std::string>> values; | 
| James Feist | f7e2c5d | 2019-02-13 17:27:51 -0800 | [diff] [blame] | 518 |     message.read(objectName, values); | 
| James Feist | 0d4f2bd | 2019-03-05 13:15:40 -0800 | [diff] [blame] | 519 |  | 
| James Feist | 52497fd | 2019-06-07 13:01:33 -0700 | [diff] [blame] | 520 |     auto findStatus = values.find(power::property); | 
 | 521 |     if (findStatus != values.end()) | 
| James Feist | f7e2c5d | 2019-02-13 17:27:51 -0800 | [diff] [blame] | 522 |     { | 
| James Feist | 52497fd | 2019-06-07 13:01:33 -0700 | [diff] [blame] | 523 |         bool powerStatus = boost::ends_with( | 
 | 524 |             std::get<std::string>(findStatus->second), "Running"); | 
| James Feist | f7e2c5d | 2019-02-13 17:27:51 -0800 | [diff] [blame] | 525 |         if (powerStatus) | 
 | 526 |         { | 
| James Feist | 0d4f2bd | 2019-03-05 13:15:40 -0800 | [diff] [blame] | 527 |             if (!initCmdTimer) | 
| James Feist | f7e2c5d | 2019-02-13 17:27:51 -0800 | [diff] [blame] | 528 |             { | 
| James Feist | 0d4f2bd | 2019-03-05 13:15:40 -0800 | [diff] [blame] | 529 |                 // this should be impossible | 
 | 530 |                 return; | 
| James Feist | f7e2c5d | 2019-02-13 17:27:51 -0800 | [diff] [blame] | 531 |             } | 
| James Feist | 0d4f2bd | 2019-03-05 13:15:40 -0800 | [diff] [blame] | 532 |             // we seem to send this command too fast sometimes, wait before | 
 | 533 |             // sending | 
 | 534 |             initCmdTimer->expires_from_now( | 
 | 535 |                 boost::posix_time::seconds(reinitWaitSeconds)); | 
 | 536 |  | 
 | 537 |             initCmdTimer->async_wait([](const boost::system::error_code ec) { | 
 | 538 |                 if (ec == boost::asio::error::operation_aborted) | 
 | 539 |                 { | 
 | 540 |                     return; // we're being canceled | 
 | 541 |                 } | 
 | 542 |  | 
 | 543 |                 for (const auto& sensor : sensors) | 
 | 544 |                 { | 
 | 545 |                     if (sensor.second) | 
 | 546 |                     { | 
 | 547 |                         sensor.second->runInitCmd(); | 
 | 548 |                     } | 
 | 549 |                 } | 
 | 550 |             }); | 
| James Feist | f7e2c5d | 2019-02-13 17:27:51 -0800 | [diff] [blame] | 551 |         } | 
 | 552 |     } | 
 | 553 | } | 
 | 554 |  | 
| James Feist | b6c0b91 | 2019-07-09 12:21:44 -0700 | [diff] [blame] | 555 | int main() | 
| James Feist | 6ef2040 | 2019-01-07 16:45:08 -0800 | [diff] [blame] | 556 | { | 
 | 557 |  | 
 | 558 |     boost::asio::io_service io; | 
 | 559 |     auto systemBus = std::make_shared<sdbusplus::asio::connection>(io); | 
 | 560 |     systemBus->request_name("xyz.openbmc_project.IpmbSensor"); | 
 | 561 |     sdbusplus::asio::object_server objectServer(systemBus); | 
| James Feist | 6ef2040 | 2019-01-07 16:45:08 -0800 | [diff] [blame] | 562 |  | 
| James Feist | 0d4f2bd | 2019-03-05 13:15:40 -0800 | [diff] [blame] | 563 |     initCmdTimer = std::make_unique<boost::asio::deadline_timer>(io); | 
 | 564 |  | 
| James Feist | 6ef2040 | 2019-01-07 16:45:08 -0800 | [diff] [blame] | 565 |     io.post([&]() { createSensors(io, objectServer, sensors, systemBus); }); | 
 | 566 |  | 
 | 567 |     boost::asio::deadline_timer configTimer(io); | 
 | 568 |  | 
 | 569 |     std::function<void(sdbusplus::message::message&)> eventHandler = | 
| James Feist | b6c0b91 | 2019-07-09 12:21:44 -0700 | [diff] [blame] | 570 |         [&](sdbusplus::message::message&) { | 
| James Feist | 6ef2040 | 2019-01-07 16:45:08 -0800 | [diff] [blame] | 571 |             configTimer.expires_from_now(boost::posix_time::seconds(1)); | 
 | 572 |             // create a timer because normally multiple properties change | 
 | 573 |             configTimer.async_wait([&](const boost::system::error_code& ec) { | 
 | 574 |                 if (ec == boost::asio::error::operation_aborted) | 
 | 575 |                 { | 
 | 576 |                     return; // we're being canceled | 
 | 577 |                 } | 
 | 578 |                 createSensors(io, objectServer, sensors, systemBus); | 
 | 579 |                 if (sensors.empty()) | 
 | 580 |                 { | 
 | 581 |                     std::cout << "Configuration not detected\n"; | 
 | 582 |                 } | 
 | 583 |             }); | 
 | 584 |         }; | 
 | 585 |  | 
| James Feist | f7e2c5d | 2019-02-13 17:27:51 -0800 | [diff] [blame] | 586 |     sdbusplus::bus::match::match configMatch( | 
| James Feist | 6ef2040 | 2019-01-07 16:45:08 -0800 | [diff] [blame] | 587 |         static_cast<sdbusplus::bus::bus&>(*systemBus), | 
 | 588 |         "type='signal',member='PropertiesChanged',path_namespace='" + | 
 | 589 |             std::string(inventoryPath) + "',arg0namespace='" + configInterface + | 
 | 590 |             "'", | 
 | 591 |         eventHandler); | 
 | 592 |  | 
| James Feist | f7e2c5d | 2019-02-13 17:27:51 -0800 | [diff] [blame] | 593 |     sdbusplus::bus::match::match powerChangeMatch( | 
 | 594 |         static_cast<sdbusplus::bus::bus&>(*systemBus), | 
| James Feist | 52497fd | 2019-06-07 13:01:33 -0700 | [diff] [blame] | 595 |         "type='signal',interface='" + std::string(properties::interface) + | 
 | 596 |             "',path='" + std::string(power::path) + "',arg0='" + | 
 | 597 |             std::string(power::interface) + "'", | 
| James Feist | f7e2c5d | 2019-02-13 17:27:51 -0800 | [diff] [blame] | 598 |         reinitSensors); | 
 | 599 |  | 
| James Feist | 6ef2040 | 2019-01-07 16:45:08 -0800 | [diff] [blame] | 600 |     io.run(); | 
 | 601 | } |