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 17d29f8aa0SZev Weiss #include <DeviceMgmt.hpp> 188a57ec09SEd Tanous #include <HwmonTempSensor.hpp> 198a57ec09SEd Tanous #include <Utils.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; 52d29f8aa0SZev Weiss 53d29f8aa0SZev Weiss static const I2CDeviceTypeMap sensorTypes{ 54d29f8aa0SZev Weiss {"DPS310", I2CDeviceType{"dps310", false}}, 55d29f8aa0SZev Weiss {"EMC1412", I2CDeviceType{"emc1412", true}}, 56d29f8aa0SZev Weiss {"EMC1413", I2CDeviceType{"emc1413", true}}, 57d29f8aa0SZev Weiss {"EMC1414", I2CDeviceType{"emc1414", true}}, 58d29f8aa0SZev Weiss {"HDC1080", I2CDeviceType{"hdc1080", false}}, 59d29f8aa0SZev Weiss {"JC42", I2CDeviceType{"jc42", true}}, 60d29f8aa0SZev Weiss {"LM75A", I2CDeviceType{"lm75a", true}}, 61d29f8aa0SZev Weiss {"LM95234", I2CDeviceType{"lm95234", true}}, 62d29f8aa0SZev Weiss {"MAX31725", I2CDeviceType{"max31725", true}}, 63d29f8aa0SZev Weiss {"MAX31730", I2CDeviceType{"max31730", true}}, 64d29f8aa0SZev Weiss {"MAX6581", I2CDeviceType{"max6581", true}}, 65d29f8aa0SZev Weiss {"MAX6654", I2CDeviceType{"max6654", true}}, 66d29f8aa0SZev Weiss {"NCT6779", I2CDeviceType{"nct6779", true}}, 67d29f8aa0SZev Weiss {"NCT7802", I2CDeviceType{"nct7802", true}}, 68d29f8aa0SZev Weiss {"SBTSI", I2CDeviceType{"sbtsi", true}}, 69d29f8aa0SZev Weiss {"SI7020", I2CDeviceType{"si7020", false}}, 70d29f8aa0SZev Weiss {"TMP112", I2CDeviceType{"tmp112", true}}, 71d29f8aa0SZev Weiss {"TMP175", I2CDeviceType{"tmp175", true}}, 72d29f8aa0SZev Weiss {"TMP421", I2CDeviceType{"tmp421", true}}, 73d29f8aa0SZev Weiss {"TMP441", I2CDeviceType{"tmp441", true}}, 74d29f8aa0SZev Weiss {"TMP75", I2CDeviceType{"tmp75", true}}, 75d29f8aa0SZev Weiss {"W83773G", I2CDeviceType{"w83773g", true}}, 76d29f8aa0SZev Weiss }; 776714a25aSJames Feist 78544e7dc5SBruce Mitchell static struct SensorParams 79544e7dc5SBruce Mitchell getSensorParameters(const std::filesystem::path& path) 80544e7dc5SBruce Mitchell { 81544e7dc5SBruce Mitchell // offset is to default to 0 and scale to 1, see lore 82544e7dc5SBruce Mitchell // https://lore.kernel.org/linux-iio/5c79425f-6e88-36b6-cdfe-4080738d039f@metafoo.de/ 83544e7dc5SBruce Mitchell struct SensorParams tmpSensorParameters = {.minValue = minValueTemperature, 84544e7dc5SBruce Mitchell .maxValue = maxValueTemperature, 85544e7dc5SBruce Mitchell .offsetValue = 0.0, 86544e7dc5SBruce Mitchell .scaleValue = 1.0, 875a86e562SBruce Mitchell .units = 885a86e562SBruce Mitchell sensor_paths::unitDegreesC, 89544e7dc5SBruce Mitchell .typeName = "temperature"}; 90544e7dc5SBruce Mitchell 91544e7dc5SBruce Mitchell // For IIO RAW sensors we get a raw_value, an offset, and scale 92544e7dc5SBruce Mitchell // to compute the value = (raw_value + offset) * scale 93544e7dc5SBruce Mitchell // with a _raw IIO device we need to get the 94544e7dc5SBruce Mitchell // offsetValue and scaleValue from the driver 95544e7dc5SBruce Mitchell // these are used to compute the reading in 96544e7dc5SBruce Mitchell // units that have yet to be scaled for D-Bus. 97544e7dc5SBruce Mitchell const std::string pathStr = path.string(); 98544e7dc5SBruce Mitchell if (pathStr.ends_with("_raw")) 99544e7dc5SBruce Mitchell { 100544e7dc5SBruce Mitchell std::string pathOffsetStr = 101544e7dc5SBruce Mitchell pathStr.substr(0, pathStr.size() - 4) + "_offset"; 102544e7dc5SBruce Mitchell std::optional<double> tmpOffsetValue = readFile(pathOffsetStr, 1.0); 103544e7dc5SBruce Mitchell // In case there is nothing to read skip this device 104544e7dc5SBruce Mitchell // This is not an error condition see lore 105544e7dc5SBruce Mitchell // https://lore.kernel.org/linux-iio/5c79425f-6e88-36b6-cdfe-4080738d039f@metafoo.de/ 106544e7dc5SBruce Mitchell if (tmpOffsetValue) 107544e7dc5SBruce Mitchell { 108544e7dc5SBruce Mitchell tmpSensorParameters.offsetValue = *tmpOffsetValue; 109544e7dc5SBruce Mitchell } 110544e7dc5SBruce Mitchell 111544e7dc5SBruce Mitchell std::string pathScaleStr = 112544e7dc5SBruce Mitchell pathStr.substr(0, pathStr.size() - 4) + "_scale"; 113544e7dc5SBruce Mitchell std::optional<double> tmpScaleValue = readFile(pathScaleStr, 1.0); 114544e7dc5SBruce Mitchell // In case there is nothing to read skip this device 115544e7dc5SBruce Mitchell // This is not an error condition see lore 116544e7dc5SBruce Mitchell // https://lore.kernel.org/linux-iio/5c79425f-6e88-36b6-cdfe-4080738d039f@metafoo.de/ 117544e7dc5SBruce Mitchell if (tmpScaleValue) 118544e7dc5SBruce Mitchell { 119544e7dc5SBruce Mitchell tmpSensorParameters.scaleValue = *tmpScaleValue; 120544e7dc5SBruce Mitchell } 121544e7dc5SBruce Mitchell } 122544e7dc5SBruce Mitchell 123544e7dc5SBruce Mitchell // Temperatures are read in milli degrees Celsius, we need 124544e7dc5SBruce Mitchell // degrees Celsius. Pressures are read in kilopascal, we need 125544e7dc5SBruce Mitchell // Pascals. On D-Bus for Open BMC we use the International 126544e7dc5SBruce Mitchell // System of Units without prefixes. Links to the kernel 127544e7dc5SBruce Mitchell // documentation: 128544e7dc5SBruce Mitchell // https://www.kernel.org/doc/Documentation/hwmon/sysfs-interface 129544e7dc5SBruce Mitchell // https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-bus-iio 130544e7dc5SBruce Mitchell if (path.filename() == "in_pressure_input" || 131544e7dc5SBruce Mitchell path.filename() == "in_pressure_raw") 132544e7dc5SBruce Mitchell { 133544e7dc5SBruce Mitchell tmpSensorParameters.minValue = minValuePressure; 134544e7dc5SBruce Mitchell tmpSensorParameters.maxValue = maxValuePressure; 135544e7dc5SBruce Mitchell // Pressures are read in kilopascal, we need Pascals. 136544e7dc5SBruce Mitchell tmpSensorParameters.scaleValue *= 1000.0; 137544e7dc5SBruce Mitchell tmpSensorParameters.typeName = "pressure"; 1385a86e562SBruce Mitchell tmpSensorParameters.units = sensor_paths::unitPascals; 139544e7dc5SBruce Mitchell } 1403ec41c53SBruce Mitchell else if (path.filename() == "in_humidityrelative_input" || 1413ec41c53SBruce Mitchell path.filename() == "in_humidityrelative_raw") 1423ec41c53SBruce Mitchell { 1433ec41c53SBruce Mitchell tmpSensorParameters.minValue = minValueRelativeHumidity; 1443ec41c53SBruce Mitchell tmpSensorParameters.maxValue = maxValueRelativeHumidity; 1453ec41c53SBruce Mitchell // Relative Humidity are read in milli-percent, we need percent. 1463ec41c53SBruce Mitchell tmpSensorParameters.scaleValue *= 0.001; 1473ec41c53SBruce Mitchell tmpSensorParameters.typeName = "humidity"; 1483ec41c53SBruce Mitchell tmpSensorParameters.units = "PercentRH"; 1493ec41c53SBruce Mitchell } 150544e7dc5SBruce Mitchell else 151544e7dc5SBruce Mitchell { 152544e7dc5SBruce Mitchell // Temperatures are read in milli degrees Celsius, 153544e7dc5SBruce Mitchell // we need degrees Celsius. 154544e7dc5SBruce Mitchell tmpSensorParameters.scaleValue *= 0.001; 155544e7dc5SBruce Mitchell } 156544e7dc5SBruce Mitchell 157544e7dc5SBruce Mitchell return tmpSensorParameters; 158544e7dc5SBruce Mitchell } 159544e7dc5SBruce Mitchell 1609f3a74edSJayashree Dhanapal struct SensorConfigKey 1619f3a74edSJayashree Dhanapal { 1629f3a74edSJayashree Dhanapal uint64_t bus; 1639f3a74edSJayashree Dhanapal uint64_t addr; 1649f3a74edSJayashree Dhanapal bool operator<(const SensorConfigKey& other) const 1659f3a74edSJayashree Dhanapal { 1669f3a74edSJayashree Dhanapal if (bus != other.bus) 1679f3a74edSJayashree Dhanapal { 1689f3a74edSJayashree Dhanapal return bus < other.bus; 1699f3a74edSJayashree Dhanapal } 1709f3a74edSJayashree Dhanapal return addr < other.addr; 1719f3a74edSJayashree Dhanapal } 1729f3a74edSJayashree Dhanapal }; 1739f3a74edSJayashree Dhanapal 1749f3a74edSJayashree Dhanapal struct SensorConfig 1759f3a74edSJayashree Dhanapal { 1769f3a74edSJayashree Dhanapal std::string sensorPath; 1779f3a74edSJayashree Dhanapal SensorData sensorData; 1789f3a74edSJayashree Dhanapal std::string interface; 1799f3a74edSJayashree Dhanapal SensorBaseConfigMap config; 1809f3a74edSJayashree Dhanapal std::vector<std::string> name; 1819f3a74edSJayashree Dhanapal }; 1829f3a74edSJayashree Dhanapal 1839f3a74edSJayashree Dhanapal using SensorConfigMap = 1849f3a74edSJayashree Dhanapal boost::container::flat_map<SensorConfigKey, SensorConfig>; 1859f3a74edSJayashree Dhanapal 1869f3a74edSJayashree Dhanapal static SensorConfigMap 1879f3a74edSJayashree Dhanapal buildSensorConfigMap(const ManagedObjectType& sensorConfigs) 1889f3a74edSJayashree Dhanapal { 1899f3a74edSJayashree Dhanapal SensorConfigMap configMap; 190a1808330SZev Weiss for (const auto& [path, cfgData] : sensorConfigs) 1919f3a74edSJayashree Dhanapal { 192a1808330SZev Weiss for (const auto& [intf, cfg] : cfgData) 1939f3a74edSJayashree Dhanapal { 1949f3a74edSJayashree Dhanapal auto busCfg = cfg.find("Bus"); 1959f3a74edSJayashree Dhanapal auto addrCfg = cfg.find("Address"); 1969f3a74edSJayashree Dhanapal if ((busCfg == cfg.end()) || (addrCfg == cfg.end())) 1979f3a74edSJayashree Dhanapal { 1989f3a74edSJayashree Dhanapal continue; 1999f3a74edSJayashree Dhanapal } 2009f3a74edSJayashree Dhanapal 2012049bd26SEd Tanous if ((std::get_if<uint64_t>(&busCfg->second) == nullptr) || 2022049bd26SEd Tanous (std::get_if<uint64_t>(&addrCfg->second) == nullptr)) 2039f3a74edSJayashree Dhanapal { 204a1808330SZev Weiss std::cerr << path.str << " Bus or Address invalid\n"; 2059f3a74edSJayashree Dhanapal continue; 2069f3a74edSJayashree Dhanapal } 2079f3a74edSJayashree Dhanapal 2089f3a74edSJayashree Dhanapal std::vector<std::string> hwmonNames; 2099f3a74edSJayashree Dhanapal auto nameCfg = cfg.find("Name"); 2109f3a74edSJayashree Dhanapal if (nameCfg != cfg.end()) 2119f3a74edSJayashree Dhanapal { 2129f3a74edSJayashree Dhanapal hwmonNames.push_back(std::get<std::string>(nameCfg->second)); 2139f3a74edSJayashree Dhanapal size_t i = 1; 2149f3a74edSJayashree Dhanapal while (true) 2159f3a74edSJayashree Dhanapal { 2169f3a74edSJayashree Dhanapal auto sensorNameCfg = cfg.find("Name" + std::to_string(i)); 2179f3a74edSJayashree Dhanapal if (sensorNameCfg == cfg.end()) 2189f3a74edSJayashree Dhanapal { 2199f3a74edSJayashree Dhanapal break; 2209f3a74edSJayashree Dhanapal } 2219f3a74edSJayashree Dhanapal hwmonNames.push_back( 2229f3a74edSJayashree Dhanapal std::get<std::string>(sensorNameCfg->second)); 2239f3a74edSJayashree Dhanapal i++; 2249f3a74edSJayashree Dhanapal } 2259f3a74edSJayashree Dhanapal } 2269f3a74edSJayashree Dhanapal 2279f3a74edSJayashree Dhanapal SensorConfigKey key = {std::get<uint64_t>(busCfg->second), 2289f3a74edSJayashree Dhanapal std::get<uint64_t>(addrCfg->second)}; 229a1808330SZev Weiss SensorConfig val = {path.str, cfgData, intf, cfg, hwmonNames}; 2309f3a74edSJayashree Dhanapal 2319f3a74edSJayashree Dhanapal auto [it, inserted] = configMap.emplace(key, std::move(val)); 2329f3a74edSJayashree Dhanapal if (!inserted) 2339f3a74edSJayashree Dhanapal { 234a1808330SZev Weiss std::cerr << path.str << ": ignoring duplicate entry for {" 235a1808330SZev Weiss << key.bus << ", 0x" << std::hex << key.addr 236a1808330SZev Weiss << std::dec << "}\n"; 2379f3a74edSJayashree Dhanapal } 2389f3a74edSJayashree Dhanapal } 2399f3a74edSJayashree Dhanapal } 2409f3a74edSJayashree Dhanapal return configMap; 2419f3a74edSJayashree Dhanapal } 2429f3a74edSJayashree Dhanapal 2436714a25aSJames Feist void createSensors( 2446714a25aSJames Feist boost::asio::io_service& io, sdbusplus::asio::object_server& objectServer, 245f3fd1915SYong Li boost::container::flat_map<std::string, std::shared_ptr<HwmonTempSensor>>& 2466714a25aSJames Feist sensors, 2476714a25aSJames Feist std::shared_ptr<sdbusplus::asio::connection>& dbusConnection, 2485591cf08SJames Feist const std::shared_ptr<boost::container::flat_set<std::string>>& 2496714a25aSJames Feist sensorsChanged) 2506714a25aSJames Feist { 251df515159SJames Feist auto getter = std::make_shared<GetSensorConfiguration>( 252df515159SJames Feist dbusConnection, 2538a17c303SEd Tanous [&io, &objectServer, &sensors, &dbusConnection, 2548a17c303SEd Tanous sensorsChanged](const ManagedObjectType& sensorConfigurations) { 2556714a25aSJames Feist bool firstScan = sensorsChanged == nullptr; 256df515159SJames Feist 257bb67932aSEd Tanous SensorConfigMap configMap = buildSensorConfigMap(sensorConfigurations); 2589f3a74edSJayashree Dhanapal 259544e7dc5SBruce Mitchell // IIO _raw devices look like this on sysfs: 260544e7dc5SBruce Mitchell // /sys/bus/iio/devices/iio:device0/in_temp_raw 261544e7dc5SBruce Mitchell // /sys/bus/iio/devices/iio:device0/in_temp_offset 262544e7dc5SBruce Mitchell // /sys/bus/iio/devices/iio:device0/in_temp_scale 263544e7dc5SBruce Mitchell // 264544e7dc5SBruce Mitchell // Other IIO devices look like this on sysfs: 265544e7dc5SBruce Mitchell // /sys/bus/iio/devices/iio:device1/in_temp_input 266544e7dc5SBruce Mitchell // /sys/bus/iio/devices/iio:device1/in_pressure_input 2676714a25aSJames Feist std::vector<fs::path> paths; 268544e7dc5SBruce Mitchell fs::path root("/sys/bus/iio/devices"); 269544e7dc5SBruce Mitchell findFiles(root, R"(in_temp\d*_(input|raw))", paths); 270544e7dc5SBruce Mitchell findFiles(root, R"(in_pressure\d*_(input|raw))", paths); 2713ec41c53SBruce Mitchell findFiles(root, R"(in_humidityrelative\d*_(input|raw))", paths); 272544e7dc5SBruce Mitchell findFiles(fs::path("/sys/class/hwmon"), R"(temp\d+_input)", paths); 273544e7dc5SBruce Mitchell 274544e7dc5SBruce Mitchell // iterate through all found temp and pressure sensors, 275544e7dc5SBruce Mitchell // and try to match them with configuration 2766714a25aSJames Feist for (auto& path : paths) 2776714a25aSJames Feist { 2786714a25aSJames Feist std::smatch match; 279544e7dc5SBruce Mitchell const std::string pathStr = path.string(); 2806714a25aSJames Feist auto directory = path.parent_path(); 281544e7dc5SBruce Mitchell fs::path device; 2826714a25aSJames Feist 283544e7dc5SBruce Mitchell std::string deviceName; 284544e7dc5SBruce Mitchell if (pathStr.starts_with("/sys/bus/iio/devices")) 2856714a25aSJames Feist { 286544e7dc5SBruce Mitchell device = fs::canonical(directory); 287544e7dc5SBruce Mitchell deviceName = device.parent_path().stem(); 28837266ca9SJames Feist } 289544e7dc5SBruce Mitchell else 290544e7dc5SBruce Mitchell { 291544e7dc5SBruce Mitchell device = directory / "device"; 292544e7dc5SBruce Mitchell deviceName = fs::canonical(device).stem(); 293544e7dc5SBruce Mitchell } 2948a57ec09SEd Tanous auto findHyphen = deviceName.find('-'); 29537266ca9SJames Feist if (findHyphen == std::string::npos) 29637266ca9SJames Feist { 29737266ca9SJames Feist std::cerr << "found bad device " << deviceName << "\n"; 2986714a25aSJames Feist continue; 2996714a25aSJames Feist } 30037266ca9SJames Feist std::string busStr = deviceName.substr(0, findHyphen); 30137266ca9SJames Feist std::string addrStr = deviceName.substr(findHyphen + 1); 30237266ca9SJames Feist 3037dd6443bSJae Hyun Yoo uint64_t bus = 0; 3047dd6443bSJae Hyun Yoo uint64_t addr = 0; 3052049bd26SEd Tanous std::from_chars_result res{}; 306bb67932aSEd Tanous res = std::from_chars(busStr.data(), busStr.data() + busStr.size(), 307bb67932aSEd Tanous bus); 3087dd6443bSJae Hyun Yoo if (res.ec != std::errc{}) 3096714a25aSJames Feist { 3107dd6443bSJae Hyun Yoo continue; 31137266ca9SJames Feist } 312bb67932aSEd Tanous res = std::from_chars(addrStr.data(), 313bb67932aSEd Tanous addrStr.data() + addrStr.size(), addr, 16); 3147dd6443bSJae Hyun Yoo if (res.ec != std::errc{}) 31537266ca9SJames Feist { 3166714a25aSJames Feist continue; 3176714a25aSJames Feist } 31837266ca9SJames Feist 319544e7dc5SBruce Mitchell auto thisSensorParameters = getSensorParameters(path); 3209f3a74edSJayashree Dhanapal auto findSensorCfg = configMap.find({bus, addr}); 3219f3a74edSJayashree Dhanapal if (findSensorCfg == configMap.end()) 32237266ca9SJames Feist { 32337266ca9SJames Feist continue; 32437266ca9SJames Feist } 32537266ca9SJames Feist 326bb67932aSEd Tanous const std::string& interfacePath = findSensorCfg->second.sensorPath; 3279f3a74edSJayashree Dhanapal const SensorData& sensorData = findSensorCfg->second.sensorData; 3289f3a74edSJayashree Dhanapal const std::string& sensorType = findSensorCfg->second.interface; 3299f3a74edSJayashree Dhanapal const SensorBaseConfigMap& baseConfigMap = 3309f3a74edSJayashree Dhanapal findSensorCfg->second.config; 331bb67932aSEd Tanous std::vector<std::string>& hwmonName = findSensorCfg->second.name; 3326714a25aSJames Feist 333544e7dc5SBruce Mitchell // Temperature has "Name", pressure has "Name1" 3349f3a74edSJayashree Dhanapal auto findSensorName = baseConfigMap.find("Name"); 335fefdbe7fSPotin Lai int index = 1; 3363ec41c53SBruce Mitchell if (thisSensorParameters.typeName == "pressure" || 3373ec41c53SBruce Mitchell thisSensorParameters.typeName == "humidity") 338544e7dc5SBruce Mitchell { 3399f3a74edSJayashree Dhanapal findSensorName = baseConfigMap.find("Name1"); 340fefdbe7fSPotin Lai index = 2; 341544e7dc5SBruce Mitchell } 342544e7dc5SBruce Mitchell 3439f3a74edSJayashree Dhanapal if (findSensorName == baseConfigMap.end()) 3446714a25aSJames Feist { 3456714a25aSJames Feist std::cerr << "could not determine configuration name for " 34637266ca9SJames Feist << deviceName << "\n"; 3476714a25aSJames Feist continue; 3486714a25aSJames Feist } 349df515159SJames Feist std::string sensorName = 350df515159SJames Feist std::get<std::string>(findSensorName->second); 3516714a25aSJames Feist // on rescans, only update sensors we were signaled by 3526714a25aSJames Feist auto findSensor = sensors.find(sensorName); 3536714a25aSJames Feist if (!firstScan && findSensor != sensors.end()) 3546714a25aSJames Feist { 3556714a25aSJames Feist bool found = false; 356d653b75cSBruce Mitchell auto it = sensorsChanged->begin(); 357d653b75cSBruce Mitchell while (it != sensorsChanged->end()) 3586714a25aSJames Feist { 3596c106d66SZev Weiss if (it->ends_with(findSensor->second->name)) 3606714a25aSJames Feist { 361d653b75cSBruce Mitchell it = sensorsChanged->erase(it); 3626714a25aSJames Feist findSensor->second = nullptr; 3636714a25aSJames Feist found = true; 3646714a25aSJames Feist break; 3656714a25aSJames Feist } 366d653b75cSBruce Mitchell ++it; 3676714a25aSJames Feist } 3686714a25aSJames Feist if (!found) 3696714a25aSJames Feist { 3706714a25aSJames Feist continue; 3716714a25aSJames Feist } 3726714a25aSJames Feist } 3735636d52bSMatt Spinler 3746714a25aSJames Feist std::vector<thresholds::Threshold> sensorThresholds; 3755636d52bSMatt Spinler 3769f3a74edSJayashree Dhanapal if (!parseThresholdsFromConfig(sensorData, sensorThresholds, 3775636d52bSMatt Spinler nullptr, &index)) 3786714a25aSJames Feist { 379bb67932aSEd Tanous std::cerr << "error populating thresholds for " << sensorName 380bb67932aSEd Tanous << " index " << index << "\n"; 3816714a25aSJames Feist } 38287bc67f7SJeff Lin 3838569bf2aSZev Weiss float pollRate = getPollRate(baseConfigMap, pollRateDefault); 384a4d2768cSZev Weiss PowerState readState = getPowerState(baseConfigMap); 385100c20bfSJason Ling 3869f3a74edSJayashree Dhanapal auto permitSet = getPermitSet(baseConfigMap); 3878b3f7d40SAlex Qiu auto& sensor = sensors[sensorName]; 3888b3f7d40SAlex Qiu sensor = nullptr; 389bb67932aSEd Tanous auto hwmonFile = 390bb67932aSEd Tanous getFullHwmonFilePath(directory.string(), "temp1", permitSet); 391544e7dc5SBruce Mitchell if (pathStr.starts_with("/sys/bus/iio/devices")) 392544e7dc5SBruce Mitchell { 393544e7dc5SBruce Mitchell hwmonFile = pathStr; 394544e7dc5SBruce Mitchell } 395100c20bfSJason Ling if (hwmonFile) 396100c20bfSJason Ling { 397f3fd1915SYong Li sensor = std::make_shared<HwmonTempSensor>( 398bb67932aSEd Tanous *hwmonFile, sensorType, objectServer, dbusConnection, io, 399bb67932aSEd Tanous sensorName, std::move(sensorThresholds), 400bb67932aSEd Tanous thisSensorParameters, pollRate, interfacePath, readState); 401f3fd1915SYong Li sensor->setupRead(); 4029eb0cc3dSWilly Tu } 4039f3a74edSJayashree Dhanapal hwmonName.erase( 4049f3a74edSJayashree Dhanapal remove(hwmonName.begin(), hwmonName.end(), sensorName), 4059f3a74edSJayashree Dhanapal hwmonName.end()); 4069eb0cc3dSWilly Tu 4078b3f7d40SAlex Qiu // Looking for keys like "Name1" for temp2_input, 4088b3f7d40SAlex Qiu // "Name2" for temp3_input, etc. 4098b3f7d40SAlex Qiu int i = 0; 4108b3f7d40SAlex Qiu while (true) 41137266ca9SJames Feist { 4128b3f7d40SAlex Qiu ++i; 413bb67932aSEd Tanous auto findKey = baseConfigMap.find("Name" + std::to_string(i)); 4149f3a74edSJayashree Dhanapal if (findKey == baseConfigMap.end()) 4158b3f7d40SAlex Qiu { 4168b3f7d40SAlex Qiu break; 41737266ca9SJames Feist } 418bb67932aSEd Tanous std::string sensorName = std::get<std::string>(findKey->second); 419bb67932aSEd Tanous hwmonFile = getFullHwmonFilePath(directory.string(), 420bb67932aSEd Tanous "temp" + std::to_string(i + 1), 421100c20bfSJason Ling permitSet); 422544e7dc5SBruce Mitchell if (pathStr.starts_with("/sys/bus/iio/devices")) 423544e7dc5SBruce Mitchell { 424544e7dc5SBruce Mitchell continue; 425544e7dc5SBruce Mitchell } 426100c20bfSJason Ling if (hwmonFile) 427100c20bfSJason Ling { 4285636d52bSMatt Spinler // To look up thresholds for these additional sensors, 4295636d52bSMatt Spinler // match on the Index property in the threshold data 4305636d52bSMatt Spinler // where the index comes from the sysfs file we're on, 4315636d52bSMatt Spinler // i.e. index = 2 for temp2_input. 4325636d52bSMatt Spinler int index = i + 1; 4335636d52bSMatt Spinler std::vector<thresholds::Threshold> thresholds; 4345636d52bSMatt Spinler 4359f3a74edSJayashree Dhanapal if (!parseThresholdsFromConfig(sensorData, thresholds, 4365636d52bSMatt Spinler nullptr, &index)) 4375636d52bSMatt Spinler { 4385636d52bSMatt Spinler std::cerr << "error populating thresholds for " 439bb67932aSEd Tanous << sensorName << " index " << index << "\n"; 4405636d52bSMatt Spinler } 4415636d52bSMatt Spinler 4428b3f7d40SAlex Qiu auto& sensor = sensors[sensorName]; 4438b3f7d40SAlex Qiu sensor = nullptr; 444f3fd1915SYong Li sensor = std::make_shared<HwmonTempSensor>( 445bb67932aSEd Tanous *hwmonFile, sensorType, objectServer, dbusConnection, 446bb67932aSEd Tanous io, sensorName, std::move(thresholds), 447bb67932aSEd Tanous thisSensorParameters, pollRate, interfacePath, 448bb67932aSEd Tanous readState); 449f3fd1915SYong Li sensor->setupRead(); 4508b3f7d40SAlex Qiu } 4519eb0cc3dSWilly Tu 4529eb0cc3dSWilly Tu hwmonName.erase( 4539eb0cc3dSWilly Tu remove(hwmonName.begin(), hwmonName.end(), sensorName), 4549eb0cc3dSWilly Tu hwmonName.end()); 4556714a25aSJames Feist } 45631ec7dbbSMatt Spinler if (hwmonName.empty()) 45731ec7dbbSMatt Spinler { 4589f3a74edSJayashree Dhanapal configMap.erase(findSensorCfg); 4599f3a74edSJayashree Dhanapal } 46031ec7dbbSMatt Spinler } 4618a17c303SEd Tanous }); 462d29f8aa0SZev Weiss std::vector<std::string> types(sensorTypes.size()); 463d29f8aa0SZev Weiss for (const auto& [type, dt] : sensorTypes) 464d29f8aa0SZev Weiss { 465d29f8aa0SZev Weiss types.push_back(type); 466d29f8aa0SZev Weiss } 467d29f8aa0SZev Weiss getter->getConfiguration(types); 4686714a25aSJames Feist } 4696714a25aSJames Feist 47020bf2c1cSMatt Spinler void interfaceRemoved( 47192f8f515SPatrick Williams sdbusplus::message_t& message, 47220bf2c1cSMatt Spinler boost::container::flat_map<std::string, std::shared_ptr<HwmonTempSensor>>& 47320bf2c1cSMatt Spinler sensors) 47420bf2c1cSMatt Spinler { 47520bf2c1cSMatt Spinler if (message.is_method_error()) 47620bf2c1cSMatt Spinler { 47720bf2c1cSMatt Spinler std::cerr << "interfacesRemoved callback method error\n"; 47820bf2c1cSMatt Spinler return; 47920bf2c1cSMatt Spinler } 48020bf2c1cSMatt Spinler 48120bf2c1cSMatt Spinler sdbusplus::message::object_path path; 48220bf2c1cSMatt Spinler std::vector<std::string> interfaces; 48320bf2c1cSMatt Spinler 48420bf2c1cSMatt Spinler message.read(path, interfaces); 48520bf2c1cSMatt Spinler 48620bf2c1cSMatt Spinler // If the xyz.openbmc_project.Confguration.X interface was removed 48720bf2c1cSMatt Spinler // for one or more sensors, delete those sensor objects. 48820bf2c1cSMatt Spinler auto sensorIt = sensors.begin(); 48920bf2c1cSMatt Spinler while (sensorIt != sensors.end()) 49020bf2c1cSMatt Spinler { 49120bf2c1cSMatt Spinler if ((sensorIt->second->configurationPath == path) && 49220bf2c1cSMatt Spinler (std::find(interfaces.begin(), interfaces.end(), 49320bf2c1cSMatt Spinler sensorIt->second->objectType) != interfaces.end())) 49420bf2c1cSMatt Spinler { 49520bf2c1cSMatt Spinler sensorIt = sensors.erase(sensorIt); 49620bf2c1cSMatt Spinler } 49720bf2c1cSMatt Spinler else 49820bf2c1cSMatt Spinler { 49920bf2c1cSMatt Spinler sensorIt++; 50020bf2c1cSMatt Spinler } 50120bf2c1cSMatt Spinler } 50220bf2c1cSMatt Spinler } 50320bf2c1cSMatt Spinler 504b6c0b914SJames Feist int main() 5056714a25aSJames Feist { 5066714a25aSJames Feist boost::asio::io_service io; 5076714a25aSJames Feist auto systemBus = std::make_shared<sdbusplus::asio::connection>(io); 508*14ed5e99SEd Tanous sdbusplus::asio::object_server objectServer(systemBus, true); 509*14ed5e99SEd Tanous objectServer.add_manager("/xyz/openbmc_project/sensors"); 5106714a25aSJames Feist systemBus->request_name("xyz.openbmc_project.HwmonTempSensor"); 511*14ed5e99SEd Tanous 512f3fd1915SYong Li boost::container::flat_map<std::string, std::shared_ptr<HwmonTempSensor>> 5136714a25aSJames Feist sensors; 5145591cf08SJames Feist auto sensorsChanged = 5155591cf08SJames Feist std::make_shared<boost::container::flat_set<std::string>>(); 5166714a25aSJames Feist 5176714a25aSJames Feist io.post([&]() { 5186714a25aSJames Feist createSensors(io, objectServer, sensors, systemBus, nullptr); 5196714a25aSJames Feist }); 5206714a25aSJames Feist 5219b4a20e9SEd Tanous boost::asio::steady_timer filterTimer(io); 52292f8f515SPatrick Williams std::function<void(sdbusplus::message_t&)> eventHandler = 52392f8f515SPatrick Williams [&](sdbusplus::message_t& message) { 5246714a25aSJames Feist if (message.is_method_error()) 5256714a25aSJames Feist { 5266714a25aSJames Feist std::cerr << "callback method error\n"; 5276714a25aSJames Feist return; 5286714a25aSJames Feist } 5296714a25aSJames Feist sensorsChanged->insert(message.get_path()); 5306714a25aSJames Feist // this implicitly cancels the timer 5319b4a20e9SEd Tanous filterTimer.expires_from_now(std::chrono::seconds(1)); 5326714a25aSJames Feist 5336714a25aSJames Feist filterTimer.async_wait([&](const boost::system::error_code& ec) { 5346714a25aSJames Feist if (ec == boost::asio::error::operation_aborted) 5356714a25aSJames Feist { 5366714a25aSJames Feist /* we were canceled*/ 5376714a25aSJames Feist return; 5386714a25aSJames Feist } 5398a57ec09SEd Tanous if (ec) 5406714a25aSJames Feist { 5416714a25aSJames Feist std::cerr << "timer error\n"; 5426714a25aSJames Feist return; 5436714a25aSJames Feist } 544bb67932aSEd Tanous createSensors(io, objectServer, sensors, systemBus, sensorsChanged); 5456714a25aSJames Feist }); 5466714a25aSJames Feist }; 5476714a25aSJames Feist 548214d9717SZev Weiss std::vector<std::unique_ptr<sdbusplus::bus::match_t>> matches = 549214d9717SZev Weiss setupPropertiesChangedMatches(*systemBus, sensorTypes, eventHandler); 5501263c3daSBruce Lee setupManufacturingModeMatch(*systemBus); 55120bf2c1cSMatt Spinler 55220bf2c1cSMatt Spinler // Watch for entity-manager to remove configuration interfaces 55320bf2c1cSMatt Spinler // so the corresponding sensors can be removed. 55492f8f515SPatrick Williams auto ifaceRemovedMatch = std::make_unique<sdbusplus::bus::match_t>( 55592f8f515SPatrick Williams static_cast<sdbusplus::bus_t&>(*systemBus), 55620bf2c1cSMatt Spinler "type='signal',member='InterfacesRemoved',arg0path='" + 55720bf2c1cSMatt Spinler std::string(inventoryPath) + "/'", 55892f8f515SPatrick Williams [&sensors](sdbusplus::message_t& msg) { 55920bf2c1cSMatt Spinler interfaceRemoved(msg, sensors); 56020bf2c1cSMatt Spinler }); 56120bf2c1cSMatt Spinler 56220bf2c1cSMatt Spinler matches.emplace_back(std::move(ifaceRemovedMatch)); 56320bf2c1cSMatt Spinler 5646714a25aSJames Feist io.run(); 5656714a25aSJames Feist } 566