16714a25aSJames Feist /* 26714a25aSJames Feist // Copyright (c) 2017 Intel Corporation 36714a25aSJames Feist // 46714a25aSJames Feist // Licensed under the Apache License, Version 2.0 (the "License"); 56714a25aSJames Feist // you may not use this file except in compliance with the License. 66714a25aSJames Feist // You may obtain a copy of the License at 76714a25aSJames Feist // 86714a25aSJames Feist // http://www.apache.org/licenses/LICENSE-2.0 96714a25aSJames Feist // 106714a25aSJames Feist // Unless required by applicable law or agreed to in writing, software 116714a25aSJames Feist // distributed under the License is distributed on an "AS IS" BASIS, 126714a25aSJames Feist // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136714a25aSJames Feist // See the License for the specific language governing permissions and 146714a25aSJames Feist // limitations under the License. 156714a25aSJames Feist */ 166714a25aSJames Feist 178a57ec09SEd Tanous #include <HwmonTempSensor.hpp> 188a57ec09SEd Tanous #include <Utils.hpp> 196714a25aSJames Feist #include <boost/algorithm/string/predicate.hpp> 206714a25aSJames Feist #include <boost/algorithm/string/replace.hpp> 2196e97db7SPatrick Venture #include <boost/container/flat_map.hpp> 226714a25aSJames Feist #include <boost/container/flat_set.hpp> 2338fb5983SJames Feist #include <sdbusplus/asio/connection.hpp> 2438fb5983SJames Feist #include <sdbusplus/asio/object_server.hpp> 2538fb5983SJames Feist #include <sdbusplus/bus/match.hpp> 2638fb5983SJames Feist 2738fb5983SJames Feist #include <array> 287dd6443bSJae Hyun Yoo #include <charconv> 2924f02f24SJames Feist #include <filesystem> 306714a25aSJames Feist #include <fstream> 3196e97db7SPatrick Venture #include <functional> 3296e97db7SPatrick Venture #include <memory> 336714a25aSJames Feist #include <regex> 3496e97db7SPatrick Venture #include <stdexcept> 3596e97db7SPatrick Venture #include <string> 3696e97db7SPatrick Venture #include <utility> 3796e97db7SPatrick Venture #include <variant> 3896e97db7SPatrick Venture #include <vector> 396714a25aSJames Feist 4087bc67f7SJeff Lin static constexpr float pollRateDefault = 0.5; 416714a25aSJames Feist 42544e7dc5SBruce Mitchell static constexpr double maxValuePressure = 120000; // Pascals 43544e7dc5SBruce Mitchell static constexpr double minValuePressure = 30000; // Pascals 44544e7dc5SBruce Mitchell 453ec41c53SBruce Mitchell static constexpr double maxValueRelativeHumidity = 100; // PercentRH 463ec41c53SBruce Mitchell static constexpr double minValueRelativeHumidity = 0; // PercentRH 473ec41c53SBruce Mitchell 48544e7dc5SBruce Mitchell static constexpr double maxValueTemperature = 127; // DegreesC 49544e7dc5SBruce Mitchell static constexpr double minValueTemperature = -128; // DegreesC 50544e7dc5SBruce Mitchell 51cf3bce6eSJames Feist namespace fs = std::filesystem; 5266558235SBrandon Kim static auto sensorTypes{ 534786334fSPotin Lai std::to_array<const char*>({"xyz.openbmc_project.Configuration.DPS310", 544786334fSPotin Lai "xyz.openbmc_project.Configuration.EMC1412", 558b3f7d40SAlex Qiu "xyz.openbmc_project.Configuration.EMC1413", 56381636e2SGilbert Chen "xyz.openbmc_project.Configuration.EMC1414", 574786334fSPotin Lai "xyz.openbmc_project.Configuration.HDC1080", 584786334fSPotin Lai "xyz.openbmc_project.Configuration.JC42", 594786334fSPotin Lai "xyz.openbmc_project.Configuration.LM75A", 604786334fSPotin Lai "xyz.openbmc_project.Configuration.LM95234", 618b3f7d40SAlex Qiu "xyz.openbmc_project.Configuration.MAX31725", 628b3f7d40SAlex Qiu "xyz.openbmc_project.Configuration.MAX31730", 6316e7af1dSJason Ling "xyz.openbmc_project.Configuration.MAX6581", 643840d0adSJosh Lehan "xyz.openbmc_project.Configuration.MAX6654", 655770a6fdSOskar Senft "xyz.openbmc_project.Configuration.NCT7802", 66*7c97730bSZev Weiss "xyz.openbmc_project.Configuration.NCT6779", 678fb0a013SJosh Lehan "xyz.openbmc_project.Configuration.SBTSI", 684786334fSPotin Lai "xyz.openbmc_project.Configuration.SI7020", 6955ab2afbSJohn Wang "xyz.openbmc_project.Configuration.TMP112", 703546adb9SPatrick Venture "xyz.openbmc_project.Configuration.TMP175", 718b3f7d40SAlex Qiu "xyz.openbmc_project.Configuration.TMP421", 728b3f7d40SAlex Qiu "xyz.openbmc_project.Configuration.TMP441", 737ea918f2SZev Weiss "xyz.openbmc_project.Configuration.TMP75", 744786334fSPotin Lai "xyz.openbmc_project.Configuration.W83773G"})}; 756714a25aSJames Feist 76544e7dc5SBruce Mitchell static struct SensorParams 77544e7dc5SBruce Mitchell getSensorParameters(const std::filesystem::path& path) 78544e7dc5SBruce Mitchell { 79544e7dc5SBruce Mitchell // offset is to default to 0 and scale to 1, see lore 80544e7dc5SBruce Mitchell // https://lore.kernel.org/linux-iio/5c79425f-6e88-36b6-cdfe-4080738d039f@metafoo.de/ 81544e7dc5SBruce Mitchell struct SensorParams tmpSensorParameters = {.minValue = minValueTemperature, 82544e7dc5SBruce Mitchell .maxValue = maxValueTemperature, 83544e7dc5SBruce Mitchell .offsetValue = 0.0, 84544e7dc5SBruce Mitchell .scaleValue = 1.0, 855a86e562SBruce Mitchell .units = 865a86e562SBruce Mitchell sensor_paths::unitDegreesC, 87544e7dc5SBruce Mitchell .typeName = "temperature"}; 88544e7dc5SBruce Mitchell 89544e7dc5SBruce Mitchell // For IIO RAW sensors we get a raw_value, an offset, and scale 90544e7dc5SBruce Mitchell // to compute the value = (raw_value + offset) * scale 91544e7dc5SBruce Mitchell // with a _raw IIO device we need to get the 92544e7dc5SBruce Mitchell // offsetValue and scaleValue from the driver 93544e7dc5SBruce Mitchell // these are used to compute the reading in 94544e7dc5SBruce Mitchell // units that have yet to be scaled for D-Bus. 95544e7dc5SBruce Mitchell const std::string pathStr = path.string(); 96544e7dc5SBruce Mitchell if (pathStr.ends_with("_raw")) 97544e7dc5SBruce Mitchell { 98544e7dc5SBruce Mitchell std::string pathOffsetStr = 99544e7dc5SBruce Mitchell pathStr.substr(0, pathStr.size() - 4) + "_offset"; 100544e7dc5SBruce Mitchell std::optional<double> tmpOffsetValue = readFile(pathOffsetStr, 1.0); 101544e7dc5SBruce Mitchell // In case there is nothing to read skip this device 102544e7dc5SBruce Mitchell // This is not an error condition see lore 103544e7dc5SBruce Mitchell // https://lore.kernel.org/linux-iio/5c79425f-6e88-36b6-cdfe-4080738d039f@metafoo.de/ 104544e7dc5SBruce Mitchell if (tmpOffsetValue) 105544e7dc5SBruce Mitchell { 106544e7dc5SBruce Mitchell tmpSensorParameters.offsetValue = *tmpOffsetValue; 107544e7dc5SBruce Mitchell } 108544e7dc5SBruce Mitchell 109544e7dc5SBruce Mitchell std::string pathScaleStr = 110544e7dc5SBruce Mitchell pathStr.substr(0, pathStr.size() - 4) + "_scale"; 111544e7dc5SBruce Mitchell std::optional<double> tmpScaleValue = readFile(pathScaleStr, 1.0); 112544e7dc5SBruce Mitchell // In case there is nothing to read skip this device 113544e7dc5SBruce Mitchell // This is not an error condition see lore 114544e7dc5SBruce Mitchell // https://lore.kernel.org/linux-iio/5c79425f-6e88-36b6-cdfe-4080738d039f@metafoo.de/ 115544e7dc5SBruce Mitchell if (tmpScaleValue) 116544e7dc5SBruce Mitchell { 117544e7dc5SBruce Mitchell tmpSensorParameters.scaleValue = *tmpScaleValue; 118544e7dc5SBruce Mitchell } 119544e7dc5SBruce Mitchell } 120544e7dc5SBruce Mitchell 121544e7dc5SBruce Mitchell // Temperatures are read in milli degrees Celsius, we need 122544e7dc5SBruce Mitchell // degrees Celsius. Pressures are read in kilopascal, we need 123544e7dc5SBruce Mitchell // Pascals. On D-Bus for Open BMC we use the International 124544e7dc5SBruce Mitchell // System of Units without prefixes. Links to the kernel 125544e7dc5SBruce Mitchell // documentation: 126544e7dc5SBruce Mitchell // https://www.kernel.org/doc/Documentation/hwmon/sysfs-interface 127544e7dc5SBruce Mitchell // https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-bus-iio 128544e7dc5SBruce Mitchell if (path.filename() == "in_pressure_input" || 129544e7dc5SBruce Mitchell path.filename() == "in_pressure_raw") 130544e7dc5SBruce Mitchell { 131544e7dc5SBruce Mitchell tmpSensorParameters.minValue = minValuePressure; 132544e7dc5SBruce Mitchell tmpSensorParameters.maxValue = maxValuePressure; 133544e7dc5SBruce Mitchell // Pressures are read in kilopascal, we need Pascals. 134544e7dc5SBruce Mitchell tmpSensorParameters.scaleValue *= 1000.0; 135544e7dc5SBruce Mitchell tmpSensorParameters.typeName = "pressure"; 1365a86e562SBruce Mitchell tmpSensorParameters.units = sensor_paths::unitPascals; 137544e7dc5SBruce Mitchell } 1383ec41c53SBruce Mitchell else if (path.filename() == "in_humidityrelative_input" || 1393ec41c53SBruce Mitchell path.filename() == "in_humidityrelative_raw") 1403ec41c53SBruce Mitchell { 1413ec41c53SBruce Mitchell tmpSensorParameters.minValue = minValueRelativeHumidity; 1423ec41c53SBruce Mitchell tmpSensorParameters.maxValue = maxValueRelativeHumidity; 1433ec41c53SBruce Mitchell // Relative Humidity are read in milli-percent, we need percent. 1443ec41c53SBruce Mitchell tmpSensorParameters.scaleValue *= 0.001; 1453ec41c53SBruce Mitchell tmpSensorParameters.typeName = "humidity"; 1463ec41c53SBruce Mitchell tmpSensorParameters.units = "PercentRH"; 1473ec41c53SBruce Mitchell } 148544e7dc5SBruce Mitchell else 149544e7dc5SBruce Mitchell { 150544e7dc5SBruce Mitchell // Temperatures are read in milli degrees Celsius, 151544e7dc5SBruce Mitchell // we need degrees Celsius. 152544e7dc5SBruce Mitchell tmpSensorParameters.scaleValue *= 0.001; 153544e7dc5SBruce Mitchell } 154544e7dc5SBruce Mitchell 155544e7dc5SBruce Mitchell return tmpSensorParameters; 156544e7dc5SBruce Mitchell } 157544e7dc5SBruce Mitchell 1589f3a74edSJayashree Dhanapal struct SensorConfigKey 1599f3a74edSJayashree Dhanapal { 1609f3a74edSJayashree Dhanapal uint64_t bus; 1619f3a74edSJayashree Dhanapal uint64_t addr; 1629f3a74edSJayashree Dhanapal bool operator<(const SensorConfigKey& other) const 1639f3a74edSJayashree Dhanapal { 1649f3a74edSJayashree Dhanapal if (bus != other.bus) 1659f3a74edSJayashree Dhanapal { 1669f3a74edSJayashree Dhanapal return bus < other.bus; 1679f3a74edSJayashree Dhanapal } 1689f3a74edSJayashree Dhanapal return addr < other.addr; 1699f3a74edSJayashree Dhanapal } 1709f3a74edSJayashree Dhanapal }; 1719f3a74edSJayashree Dhanapal 1729f3a74edSJayashree Dhanapal struct SensorConfig 1739f3a74edSJayashree Dhanapal { 1749f3a74edSJayashree Dhanapal std::string sensorPath; 1759f3a74edSJayashree Dhanapal SensorData sensorData; 1769f3a74edSJayashree Dhanapal std::string interface; 1779f3a74edSJayashree Dhanapal SensorBaseConfigMap config; 1789f3a74edSJayashree Dhanapal std::vector<std::string> name; 1799f3a74edSJayashree Dhanapal }; 1809f3a74edSJayashree Dhanapal 1819f3a74edSJayashree Dhanapal using SensorConfigMap = 1829f3a74edSJayashree Dhanapal boost::container::flat_map<SensorConfigKey, SensorConfig>; 1839f3a74edSJayashree Dhanapal 1849f3a74edSJayashree Dhanapal static SensorConfigMap 1859f3a74edSJayashree Dhanapal buildSensorConfigMap(const ManagedObjectType& sensorConfigs) 1869f3a74edSJayashree Dhanapal { 1879f3a74edSJayashree Dhanapal SensorConfigMap configMap; 1889f3a74edSJayashree Dhanapal for (const std::pair<sdbusplus::message::object_path, SensorData>& sensor : 1899f3a74edSJayashree Dhanapal sensorConfigs) 1909f3a74edSJayashree Dhanapal { 1919f3a74edSJayashree Dhanapal for (const std::pair<std::string, SensorBaseConfigMap>& cfgmap : 1929f3a74edSJayashree Dhanapal sensor.second) 1939f3a74edSJayashree Dhanapal { 1949f3a74edSJayashree Dhanapal const SensorBaseConfigMap& cfg = cfgmap.second; 1959f3a74edSJayashree Dhanapal auto busCfg = cfg.find("Bus"); 1969f3a74edSJayashree Dhanapal auto addrCfg = cfg.find("Address"); 1979f3a74edSJayashree Dhanapal if ((busCfg == cfg.end()) || (addrCfg == cfg.end())) 1989f3a74edSJayashree Dhanapal { 1999f3a74edSJayashree Dhanapal continue; 2009f3a74edSJayashree Dhanapal } 2019f3a74edSJayashree Dhanapal 2029f3a74edSJayashree Dhanapal if ((!std::get_if<uint64_t>(&busCfg->second)) || 2039f3a74edSJayashree Dhanapal (!std::get_if<uint64_t>(&addrCfg->second))) 2049f3a74edSJayashree Dhanapal { 2059f3a74edSJayashree Dhanapal std::cerr << sensor.first.str << " Bus or Address invalid\n"; 2069f3a74edSJayashree Dhanapal continue; 2079f3a74edSJayashree Dhanapal } 2089f3a74edSJayashree Dhanapal 2099f3a74edSJayashree Dhanapal std::vector<std::string> hwmonNames; 2109f3a74edSJayashree Dhanapal auto nameCfg = cfg.find("Name"); 2119f3a74edSJayashree Dhanapal if (nameCfg != cfg.end()) 2129f3a74edSJayashree Dhanapal { 2139f3a74edSJayashree Dhanapal hwmonNames.push_back(std::get<std::string>(nameCfg->second)); 2149f3a74edSJayashree Dhanapal size_t i = 1; 2159f3a74edSJayashree Dhanapal while (true) 2169f3a74edSJayashree Dhanapal { 2179f3a74edSJayashree Dhanapal auto sensorNameCfg = cfg.find("Name" + std::to_string(i)); 2189f3a74edSJayashree Dhanapal if (sensorNameCfg == cfg.end()) 2199f3a74edSJayashree Dhanapal { 2209f3a74edSJayashree Dhanapal break; 2219f3a74edSJayashree Dhanapal } 2229f3a74edSJayashree Dhanapal hwmonNames.push_back( 2239f3a74edSJayashree Dhanapal std::get<std::string>(sensorNameCfg->second)); 2249f3a74edSJayashree Dhanapal i++; 2259f3a74edSJayashree Dhanapal } 2269f3a74edSJayashree Dhanapal } 2279f3a74edSJayashree Dhanapal 2289f3a74edSJayashree Dhanapal SensorConfigKey key = {std::get<uint64_t>(busCfg->second), 2299f3a74edSJayashree Dhanapal std::get<uint64_t>(addrCfg->second)}; 2309f3a74edSJayashree Dhanapal SensorConfig val = {sensor.first.str, sensor.second, cfgmap.first, 2319f3a74edSJayashree Dhanapal cfg, hwmonNames}; 2329f3a74edSJayashree Dhanapal 2339f3a74edSJayashree Dhanapal auto [it, inserted] = configMap.emplace(key, std::move(val)); 2349f3a74edSJayashree Dhanapal if (!inserted) 2359f3a74edSJayashree Dhanapal { 2369f3a74edSJayashree Dhanapal std::cerr << sensor.first.str 2379f3a74edSJayashree Dhanapal << ": ignoring duplicate entry for {" << key.bus 2389f3a74edSJayashree Dhanapal << ", 0x" << std::hex << key.addr << std::dec 2399f3a74edSJayashree Dhanapal << "}\n"; 2409f3a74edSJayashree Dhanapal } 2419f3a74edSJayashree Dhanapal } 2429f3a74edSJayashree Dhanapal } 2439f3a74edSJayashree Dhanapal return configMap; 2449f3a74edSJayashree Dhanapal } 2459f3a74edSJayashree Dhanapal 2466714a25aSJames Feist void createSensors( 2476714a25aSJames Feist boost::asio::io_service& io, sdbusplus::asio::object_server& objectServer, 248f3fd1915SYong Li boost::container::flat_map<std::string, std::shared_ptr<HwmonTempSensor>>& 2496714a25aSJames Feist sensors, 2506714a25aSJames Feist std::shared_ptr<sdbusplus::asio::connection>& dbusConnection, 2515591cf08SJames Feist const std::shared_ptr<boost::container::flat_set<std::string>>& 2526714a25aSJames Feist sensorsChanged) 2536714a25aSJames Feist { 254df515159SJames Feist auto getter = std::make_shared<GetSensorConfiguration>( 255df515159SJames Feist dbusConnection, 2568a17c303SEd Tanous [&io, &objectServer, &sensors, &dbusConnection, 2578a17c303SEd Tanous sensorsChanged](const ManagedObjectType& sensorConfigurations) { 2586714a25aSJames Feist bool firstScan = sensorsChanged == nullptr; 259df515159SJames Feist 2609f3a74edSJayashree Dhanapal SensorConfigMap configMap = 2619f3a74edSJayashree Dhanapal buildSensorConfigMap(sensorConfigurations); 2629f3a74edSJayashree Dhanapal 263544e7dc5SBruce Mitchell // IIO _raw devices look like this on sysfs: 264544e7dc5SBruce Mitchell // /sys/bus/iio/devices/iio:device0/in_temp_raw 265544e7dc5SBruce Mitchell // /sys/bus/iio/devices/iio:device0/in_temp_offset 266544e7dc5SBruce Mitchell // /sys/bus/iio/devices/iio:device0/in_temp_scale 267544e7dc5SBruce Mitchell // 268544e7dc5SBruce Mitchell // Other IIO devices look like this on sysfs: 269544e7dc5SBruce Mitchell // /sys/bus/iio/devices/iio:device1/in_temp_input 270544e7dc5SBruce Mitchell // /sys/bus/iio/devices/iio:device1/in_pressure_input 2716714a25aSJames Feist std::vector<fs::path> paths; 272544e7dc5SBruce Mitchell fs::path root("/sys/bus/iio/devices"); 273544e7dc5SBruce Mitchell findFiles(root, R"(in_temp\d*_(input|raw))", paths); 274544e7dc5SBruce Mitchell findFiles(root, R"(in_pressure\d*_(input|raw))", paths); 2753ec41c53SBruce Mitchell findFiles(root, R"(in_humidityrelative\d*_(input|raw))", paths); 276544e7dc5SBruce Mitchell findFiles(fs::path("/sys/class/hwmon"), R"(temp\d+_input)", paths); 277544e7dc5SBruce Mitchell 278544e7dc5SBruce Mitchell if (paths.empty()) 2796714a25aSJames Feist { 2806714a25aSJames Feist return; 2816714a25aSJames Feist } 2826714a25aSJames Feist 283544e7dc5SBruce Mitchell // iterate through all found temp and pressure sensors, 284544e7dc5SBruce Mitchell // and try to match them with configuration 2856714a25aSJames Feist for (auto& path : paths) 2866714a25aSJames Feist { 2876714a25aSJames Feist std::smatch match; 288544e7dc5SBruce Mitchell const std::string pathStr = path.string(); 2896714a25aSJames Feist auto directory = path.parent_path(); 290544e7dc5SBruce Mitchell fs::path device; 2916714a25aSJames Feist 292544e7dc5SBruce Mitchell std::string deviceName; 293544e7dc5SBruce Mitchell if (pathStr.starts_with("/sys/bus/iio/devices")) 2946714a25aSJames Feist { 295544e7dc5SBruce Mitchell device = fs::canonical(directory); 296544e7dc5SBruce Mitchell deviceName = device.parent_path().stem(); 29737266ca9SJames Feist } 298544e7dc5SBruce Mitchell else 299544e7dc5SBruce Mitchell { 300544e7dc5SBruce Mitchell device = directory / "device"; 301544e7dc5SBruce Mitchell deviceName = fs::canonical(device).stem(); 302544e7dc5SBruce Mitchell } 3038a57ec09SEd Tanous auto findHyphen = deviceName.find('-'); 30437266ca9SJames Feist if (findHyphen == std::string::npos) 30537266ca9SJames Feist { 30637266ca9SJames Feist std::cerr << "found bad device " << deviceName << "\n"; 3076714a25aSJames Feist continue; 3086714a25aSJames Feist } 30937266ca9SJames Feist std::string busStr = deviceName.substr(0, findHyphen); 31037266ca9SJames Feist std::string addrStr = deviceName.substr(findHyphen + 1); 31137266ca9SJames Feist 3127dd6443bSJae Hyun Yoo uint64_t bus = 0; 3137dd6443bSJae Hyun Yoo uint64_t addr = 0; 3147dd6443bSJae Hyun Yoo std::from_chars_result res; 3157dd6443bSJae Hyun Yoo res = std::from_chars(busStr.data(), 3167dd6443bSJae Hyun Yoo busStr.data() + busStr.size(), bus); 3177dd6443bSJae Hyun Yoo if (res.ec != std::errc{}) 3186714a25aSJames Feist { 3197dd6443bSJae Hyun Yoo continue; 32037266ca9SJames Feist } 3217dd6443bSJae Hyun Yoo res = std::from_chars( 3227dd6443bSJae Hyun Yoo addrStr.data(), addrStr.data() + addrStr.size(), addr, 16); 3237dd6443bSJae Hyun Yoo if (res.ec != std::errc{}) 32437266ca9SJames Feist { 3256714a25aSJames Feist continue; 3266714a25aSJames Feist } 32737266ca9SJames Feist 328544e7dc5SBruce Mitchell auto thisSensorParameters = getSensorParameters(path); 3299f3a74edSJayashree Dhanapal auto findSensorCfg = configMap.find({bus, addr}); 3309f3a74edSJayashree Dhanapal if (findSensorCfg == configMap.end()) 33137266ca9SJames Feist { 33237266ca9SJames Feist continue; 33337266ca9SJames Feist } 33437266ca9SJames Feist 3359f3a74edSJayashree Dhanapal const std::string& interfacePath = 3369f3a74edSJayashree Dhanapal findSensorCfg->second.sensorPath; 3379f3a74edSJayashree Dhanapal const SensorData& sensorData = findSensorCfg->second.sensorData; 3389f3a74edSJayashree Dhanapal const std::string& sensorType = findSensorCfg->second.interface; 3399f3a74edSJayashree Dhanapal const SensorBaseConfigMap& baseConfigMap = 3409f3a74edSJayashree Dhanapal findSensorCfg->second.config; 3419f3a74edSJayashree Dhanapal std::vector<std::string>& hwmonName = 3429f3a74edSJayashree Dhanapal findSensorCfg->second.name; 3436714a25aSJames Feist 344544e7dc5SBruce Mitchell // Temperature has "Name", pressure has "Name1" 3459f3a74edSJayashree Dhanapal auto findSensorName = baseConfigMap.find("Name"); 346fefdbe7fSPotin Lai int index = 1; 3473ec41c53SBruce Mitchell if (thisSensorParameters.typeName == "pressure" || 3483ec41c53SBruce Mitchell thisSensorParameters.typeName == "humidity") 349544e7dc5SBruce Mitchell { 3509f3a74edSJayashree Dhanapal findSensorName = baseConfigMap.find("Name1"); 351fefdbe7fSPotin Lai index = 2; 352544e7dc5SBruce Mitchell } 353544e7dc5SBruce Mitchell 3549f3a74edSJayashree Dhanapal if (findSensorName == baseConfigMap.end()) 3556714a25aSJames Feist { 3566714a25aSJames Feist std::cerr << "could not determine configuration name for " 35737266ca9SJames Feist << deviceName << "\n"; 3586714a25aSJames Feist continue; 3596714a25aSJames Feist } 360df515159SJames Feist std::string sensorName = 361df515159SJames Feist std::get<std::string>(findSensorName->second); 3626714a25aSJames Feist // on rescans, only update sensors we were signaled by 3636714a25aSJames Feist auto findSensor = sensors.find(sensorName); 3646714a25aSJames Feist if (!firstScan && findSensor != sensors.end()) 3656714a25aSJames Feist { 3666714a25aSJames Feist bool found = false; 367d653b75cSBruce Mitchell auto it = sensorsChanged->begin(); 368d653b75cSBruce Mitchell while (it != sensorsChanged->end()) 3696714a25aSJames Feist { 3706714a25aSJames Feist if (boost::ends_with(*it, findSensor->second->name)) 3716714a25aSJames Feist { 372d653b75cSBruce Mitchell it = sensorsChanged->erase(it); 3736714a25aSJames Feist findSensor->second = nullptr; 3746714a25aSJames Feist found = true; 3756714a25aSJames Feist break; 3766714a25aSJames Feist } 377d653b75cSBruce Mitchell ++it; 3786714a25aSJames Feist } 3796714a25aSJames Feist if (!found) 3806714a25aSJames Feist { 3816714a25aSJames Feist continue; 3826714a25aSJames Feist } 3836714a25aSJames Feist } 3845636d52bSMatt Spinler 3856714a25aSJames Feist std::vector<thresholds::Threshold> sensorThresholds; 3865636d52bSMatt Spinler 3879f3a74edSJayashree Dhanapal if (!parseThresholdsFromConfig(sensorData, sensorThresholds, 3885636d52bSMatt Spinler nullptr, &index)) 3896714a25aSJames Feist { 390df515159SJames Feist std::cerr << "error populating thresholds for " 391fefdbe7fSPotin Lai << sensorName << " index " << index << "\n"; 3926714a25aSJames Feist } 39387bc67f7SJeff Lin 3949f3a74edSJayashree Dhanapal auto findPollRate = baseConfigMap.find("PollRate"); 39587bc67f7SJeff Lin float pollRate = pollRateDefault; 3969f3a74edSJayashree Dhanapal if (findPollRate != baseConfigMap.end()) 39787bc67f7SJeff Lin { 39887bc67f7SJeff Lin pollRate = std::visit(VariantToFloatVisitor(), 39987bc67f7SJeff Lin findPollRate->second); 40087bc67f7SJeff Lin if (pollRate <= 0.0f) 40187bc67f7SJeff Lin { 40287bc67f7SJeff Lin pollRate = pollRateDefault; // polling time too short 40387bc67f7SJeff Lin } 40487bc67f7SJeff Lin } 40587bc67f7SJeff Lin 4069f3a74edSJayashree Dhanapal auto findPowerOn = baseConfigMap.find("PowerState"); 407f9b01b6dSJames Feist PowerState readState = PowerState::always; 4089f3a74edSJayashree Dhanapal if (findPowerOn != baseConfigMap.end()) 409f9b01b6dSJames Feist { 410f9b01b6dSJames Feist std::string powerState = std::visit( 411f9b01b6dSJames Feist VariantToStringVisitor(), findPowerOn->second); 412f9b01b6dSJames Feist setReadState(powerState, readState); 413f9b01b6dSJames Feist } 414100c20bfSJason Ling 4159f3a74edSJayashree Dhanapal auto permitSet = getPermitSet(baseConfigMap); 4168b3f7d40SAlex Qiu auto& sensor = sensors[sensorName]; 4178b3f7d40SAlex Qiu sensor = nullptr; 418100c20bfSJason Ling auto hwmonFile = getFullHwmonFilePath(directory.string(), 419100c20bfSJason Ling "temp1", permitSet); 420544e7dc5SBruce Mitchell if (pathStr.starts_with("/sys/bus/iio/devices")) 421544e7dc5SBruce Mitchell { 422544e7dc5SBruce Mitchell hwmonFile = pathStr; 423544e7dc5SBruce Mitchell } 424100c20bfSJason Ling if (hwmonFile) 425100c20bfSJason Ling { 426f3fd1915SYong Li sensor = std::make_shared<HwmonTempSensor>( 427100c20bfSJason Ling *hwmonFile, sensorType, objectServer, dbusConnection, 428544e7dc5SBruce Mitchell io, sensorName, std::move(sensorThresholds), 4299f3a74edSJayashree Dhanapal thisSensorParameters, pollRate, interfacePath, 430544e7dc5SBruce Mitchell readState); 431f3fd1915SYong Li sensor->setupRead(); 4329f3a74edSJayashree Dhanapal hwmonName.erase( 4339f3a74edSJayashree Dhanapal remove(hwmonName.begin(), hwmonName.end(), sensorName), 4349f3a74edSJayashree Dhanapal hwmonName.end()); 435100c20bfSJason Ling } 4368b3f7d40SAlex Qiu // Looking for keys like "Name1" for temp2_input, 4378b3f7d40SAlex Qiu // "Name2" for temp3_input, etc. 4388b3f7d40SAlex Qiu int i = 0; 4398b3f7d40SAlex Qiu while (true) 44037266ca9SJames Feist { 4418b3f7d40SAlex Qiu ++i; 4428b3f7d40SAlex Qiu auto findKey = 4439f3a74edSJayashree Dhanapal baseConfigMap.find("Name" + std::to_string(i)); 4449f3a74edSJayashree Dhanapal if (findKey == baseConfigMap.end()) 4458b3f7d40SAlex Qiu { 4468b3f7d40SAlex Qiu break; 44737266ca9SJames Feist } 4488b3f7d40SAlex Qiu std::string sensorName = 4498b3f7d40SAlex Qiu std::get<std::string>(findKey->second); 450100c20bfSJason Ling hwmonFile = getFullHwmonFilePath( 451100c20bfSJason Ling directory.string(), "temp" + std::to_string(i + 1), 452100c20bfSJason Ling permitSet); 453544e7dc5SBruce Mitchell if (pathStr.starts_with("/sys/bus/iio/devices")) 454544e7dc5SBruce Mitchell { 455544e7dc5SBruce Mitchell continue; 456544e7dc5SBruce Mitchell } 457100c20bfSJason Ling if (hwmonFile) 458100c20bfSJason Ling { 4595636d52bSMatt Spinler // To look up thresholds for these additional sensors, 4605636d52bSMatt Spinler // match on the Index property in the threshold data 4615636d52bSMatt Spinler // where the index comes from the sysfs file we're on, 4625636d52bSMatt Spinler // i.e. index = 2 for temp2_input. 4635636d52bSMatt Spinler int index = i + 1; 4645636d52bSMatt Spinler std::vector<thresholds::Threshold> thresholds; 4655636d52bSMatt Spinler 4669f3a74edSJayashree Dhanapal if (!parseThresholdsFromConfig(sensorData, thresholds, 4675636d52bSMatt Spinler nullptr, &index)) 4685636d52bSMatt Spinler { 4695636d52bSMatt Spinler std::cerr << "error populating thresholds for " 4705636d52bSMatt Spinler << sensorName << " index " << index 4715636d52bSMatt Spinler << "\n"; 4725636d52bSMatt Spinler } 4735636d52bSMatt Spinler 4748b3f7d40SAlex Qiu auto& sensor = sensors[sensorName]; 4758b3f7d40SAlex Qiu sensor = nullptr; 476f3fd1915SYong Li sensor = std::make_shared<HwmonTempSensor>( 477100c20bfSJason Ling *hwmonFile, sensorType, objectServer, 478100c20bfSJason Ling dbusConnection, io, sensorName, 479544e7dc5SBruce Mitchell std::move(thresholds), thisSensorParameters, 4809f3a74edSJayashree Dhanapal pollRate, interfacePath, readState); 481f3fd1915SYong Li sensor->setupRead(); 4829f3a74edSJayashree Dhanapal hwmonName.erase(remove(hwmonName.begin(), 4839f3a74edSJayashree Dhanapal hwmonName.end(), sensorName), 4849f3a74edSJayashree Dhanapal hwmonName.end()); 4858b3f7d40SAlex Qiu } 4866714a25aSJames Feist } 48731ec7dbbSMatt Spinler if (hwmonName.empty()) 48831ec7dbbSMatt Spinler { 4899f3a74edSJayashree Dhanapal configMap.erase(findSensorCfg); 4909f3a74edSJayashree Dhanapal } 49131ec7dbbSMatt Spinler } 4928a17c303SEd Tanous }); 493df515159SJames Feist getter->getConfiguration( 494df515159SJames Feist std::vector<std::string>(sensorTypes.begin(), sensorTypes.end())); 4956714a25aSJames Feist } 4966714a25aSJames Feist 49720bf2c1cSMatt Spinler void interfaceRemoved( 49820bf2c1cSMatt Spinler sdbusplus::message::message& message, 49920bf2c1cSMatt Spinler boost::container::flat_map<std::string, std::shared_ptr<HwmonTempSensor>>& 50020bf2c1cSMatt Spinler sensors) 50120bf2c1cSMatt Spinler { 50220bf2c1cSMatt Spinler if (message.is_method_error()) 50320bf2c1cSMatt Spinler { 50420bf2c1cSMatt Spinler std::cerr << "interfacesRemoved callback method error\n"; 50520bf2c1cSMatt Spinler return; 50620bf2c1cSMatt Spinler } 50720bf2c1cSMatt Spinler 50820bf2c1cSMatt Spinler sdbusplus::message::object_path path; 50920bf2c1cSMatt Spinler std::vector<std::string> interfaces; 51020bf2c1cSMatt Spinler 51120bf2c1cSMatt Spinler message.read(path, interfaces); 51220bf2c1cSMatt Spinler 51320bf2c1cSMatt Spinler // If the xyz.openbmc_project.Confguration.X interface was removed 51420bf2c1cSMatt Spinler // for one or more sensors, delete those sensor objects. 51520bf2c1cSMatt Spinler auto sensorIt = sensors.begin(); 51620bf2c1cSMatt Spinler while (sensorIt != sensors.end()) 51720bf2c1cSMatt Spinler { 51820bf2c1cSMatt Spinler if ((sensorIt->second->configurationPath == path) && 51920bf2c1cSMatt Spinler (std::find(interfaces.begin(), interfaces.end(), 52020bf2c1cSMatt Spinler sensorIt->second->objectType) != interfaces.end())) 52120bf2c1cSMatt Spinler { 52220bf2c1cSMatt Spinler sensorIt = sensors.erase(sensorIt); 52320bf2c1cSMatt Spinler } 52420bf2c1cSMatt Spinler else 52520bf2c1cSMatt Spinler { 52620bf2c1cSMatt Spinler sensorIt++; 52720bf2c1cSMatt Spinler } 52820bf2c1cSMatt Spinler } 52920bf2c1cSMatt Spinler } 53020bf2c1cSMatt Spinler 531b6c0b914SJames Feist int main() 5326714a25aSJames Feist { 5336714a25aSJames Feist boost::asio::io_service io; 5346714a25aSJames Feist auto systemBus = std::make_shared<sdbusplus::asio::connection>(io); 5356714a25aSJames Feist systemBus->request_name("xyz.openbmc_project.HwmonTempSensor"); 5366714a25aSJames Feist sdbusplus::asio::object_server objectServer(systemBus); 537f3fd1915SYong Li boost::container::flat_map<std::string, std::shared_ptr<HwmonTempSensor>> 5386714a25aSJames Feist sensors; 5396714a25aSJames Feist std::vector<std::unique_ptr<sdbusplus::bus::match::match>> matches; 5405591cf08SJames Feist auto sensorsChanged = 5415591cf08SJames Feist std::make_shared<boost::container::flat_set<std::string>>(); 5426714a25aSJames Feist 5436714a25aSJames Feist io.post([&]() { 5446714a25aSJames Feist createSensors(io, objectServer, sensors, systemBus, nullptr); 5456714a25aSJames Feist }); 5466714a25aSJames Feist 5476714a25aSJames Feist boost::asio::deadline_timer filterTimer(io); 5486714a25aSJames Feist std::function<void(sdbusplus::message::message&)> eventHandler = 5496714a25aSJames Feist [&](sdbusplus::message::message& message) { 5506714a25aSJames Feist if (message.is_method_error()) 5516714a25aSJames Feist { 5526714a25aSJames Feist std::cerr << "callback method error\n"; 5536714a25aSJames Feist return; 5546714a25aSJames Feist } 5556714a25aSJames Feist sensorsChanged->insert(message.get_path()); 5566714a25aSJames Feist // this implicitly cancels the timer 5576714a25aSJames Feist filterTimer.expires_from_now(boost::posix_time::seconds(1)); 5586714a25aSJames Feist 5596714a25aSJames Feist filterTimer.async_wait([&](const boost::system::error_code& ec) { 5606714a25aSJames Feist if (ec == boost::asio::error::operation_aborted) 5616714a25aSJames Feist { 5626714a25aSJames Feist /* we were canceled*/ 5636714a25aSJames Feist return; 5646714a25aSJames Feist } 5658a57ec09SEd Tanous if (ec) 5666714a25aSJames Feist { 5676714a25aSJames Feist std::cerr << "timer error\n"; 5686714a25aSJames Feist return; 5696714a25aSJames Feist } 5706714a25aSJames Feist createSensors(io, objectServer, sensors, systemBus, 5716714a25aSJames Feist sensorsChanged); 5726714a25aSJames Feist }); 5736714a25aSJames Feist }; 5746714a25aSJames Feist 5759ced0a38SJae Hyun Yoo for (const char* type : sensorTypes) 5766714a25aSJames Feist { 5776714a25aSJames Feist auto match = std::make_unique<sdbusplus::bus::match::match>( 5786714a25aSJames Feist static_cast<sdbusplus::bus::bus&>(*systemBus), 5796714a25aSJames Feist "type='signal',member='PropertiesChanged',path_namespace='" + 5809ced0a38SJae Hyun Yoo std::string(inventoryPath) + "',arg0namespace='" + type + "'", 5816714a25aSJames Feist eventHandler); 5826714a25aSJames Feist matches.emplace_back(std::move(match)); 5836714a25aSJames Feist } 5846714a25aSJames Feist 5851263c3daSBruce Lee setupManufacturingModeMatch(*systemBus); 58620bf2c1cSMatt Spinler 58720bf2c1cSMatt Spinler // Watch for entity-manager to remove configuration interfaces 58820bf2c1cSMatt Spinler // so the corresponding sensors can be removed. 58920bf2c1cSMatt Spinler auto ifaceRemovedMatch = std::make_unique<sdbusplus::bus::match::match>( 59020bf2c1cSMatt Spinler static_cast<sdbusplus::bus::bus&>(*systemBus), 59120bf2c1cSMatt Spinler "type='signal',member='InterfacesRemoved',arg0path='" + 59220bf2c1cSMatt Spinler std::string(inventoryPath) + "/'", 59320bf2c1cSMatt Spinler [&sensors](sdbusplus::message::message& msg) { 59420bf2c1cSMatt Spinler interfaceRemoved(msg, sensors); 59520bf2c1cSMatt Spinler }); 59620bf2c1cSMatt Spinler 59720bf2c1cSMatt Spinler matches.emplace_back(std::move(ifaceRemovedMatch)); 59820bf2c1cSMatt Spinler 5996714a25aSJames Feist io.run(); 6006714a25aSJames Feist } 601