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 17ca44b2f3SPatrick Venture #include "PwmSensor.hpp" 18ca44b2f3SPatrick Venture #include "TachSensor.hpp" 19ca44b2f3SPatrick Venture #include "Utils.hpp" 20ca44b2f3SPatrick Venture #include "VariantVisitors.hpp" 21ca44b2f3SPatrick Venture 226714a25aSJames Feist #include <boost/algorithm/string/predicate.hpp> 236714a25aSJames Feist #include <boost/algorithm/string/replace.hpp> 2496e97db7SPatrick Venture #include <boost/container/flat_map.hpp> 256714a25aSJames Feist #include <boost/container/flat_set.hpp> 266714a25aSJames Feist #include <boost/lexical_cast.hpp> 2738fb5983SJames Feist #include <sdbusplus/asio/connection.hpp> 2838fb5983SJames Feist #include <sdbusplus/asio/object_server.hpp> 2938fb5983SJames Feist #include <sdbusplus/bus/match.hpp> 3038fb5983SJames Feist 3138fb5983SJames Feist #include <array> 3224f02f24SJames Feist #include <filesystem> 336714a25aSJames Feist #include <fstream> 3496e97db7SPatrick Venture #include <functional> 3596e97db7SPatrick Venture #include <memory> 3696e97db7SPatrick Venture #include <optional> 376714a25aSJames Feist #include <regex> 3896e97db7SPatrick Venture #include <string> 3996e97db7SPatrick Venture #include <utility> 4096e97db7SPatrick Venture #include <variant> 4196e97db7SPatrick Venture #include <vector> 426714a25aSJames Feist 436714a25aSJames Feist static constexpr bool DEBUG = false; 446714a25aSJames Feist 45cf3bce6eSJames Feist namespace fs = std::filesystem; 463eb82629SJames Feist 478843b627SPeter Lundgren static constexpr std::array<const char*, 3> sensorTypes = { 4895b079b7SJames Feist "xyz.openbmc_project.Configuration.AspeedFan", 498843b627SPeter Lundgren "xyz.openbmc_project.Configuration.I2CFan", 508843b627SPeter Lundgren "xyz.openbmc_project.Configuration.NuvotonFan"}; 51dc6c55f3SJames Feist constexpr const char* redundancyConfiguration = 52dc6c55f3SJames Feist "xyz.openbmc_project.Configuration.FanRedundancy"; 539ced0a38SJae Hyun Yoo static std::regex inputRegex(R"(fan(\d+)_input)"); 546714a25aSJames Feist 5595b079b7SJames Feist enum class FanTypes 5695b079b7SJames Feist { 5795b079b7SJames Feist aspeed, 588843b627SPeter Lundgren i2c, 598843b627SPeter Lundgren nuvoton 6095b079b7SJames Feist }; 6195b079b7SJames Feist 62dc6c55f3SJames Feist // todo: power supply fan redundancy 637b18b1e0SJames Feist std::optional<RedundancySensor> systemRedundancy; 6495b079b7SJames Feist 6595b079b7SJames Feist FanTypes getFanType(const fs::path& parentPath) 6695b079b7SJames Feist { 6795b079b7SJames Feist fs::path linkPath = parentPath / "device"; 6895b079b7SJames Feist std::string canonical = fs::read_symlink(linkPath); 69241356e3SJae Hyun Yoo if (boost::ends_with(canonical, "1e786000.pwm-tacho-controller") || 70241356e3SJae Hyun Yoo boost::ends_with(canonical, "1e610000.pwm-tacho-controller")) 7195b079b7SJames Feist { 7295b079b7SJames Feist return FanTypes::aspeed; 7395b079b7SJames Feist } 748843b627SPeter Lundgren else if (boost::ends_with(canonical, "f0103000.pwm-fan-controller")) 758843b627SPeter Lundgren { 768843b627SPeter Lundgren return FanTypes::nuvoton; 778843b627SPeter Lundgren } 7895b079b7SJames Feist // todo: will we need to support other types? 7995b079b7SJames Feist return FanTypes::i2c; 8095b079b7SJames Feist } 81dc6c55f3SJames Feist 826714a25aSJames Feist void createSensors( 836714a25aSJames Feist boost::asio::io_service& io, sdbusplus::asio::object_server& objectServer, 846714a25aSJames Feist boost::container::flat_map<std::string, std::unique_ptr<TachSensor>>& 856714a25aSJames Feist tachSensors, 866714a25aSJames Feist boost::container::flat_map<std::string, std::unique_ptr<PwmSensor>>& 876714a25aSJames Feist pwmSensors, 886714a25aSJames Feist std::shared_ptr<sdbusplus::asio::connection>& dbusConnection, 896714a25aSJames Feist const std::unique_ptr<boost::container::flat_set<std::string>>& 906714a25aSJames Feist sensorsChanged) 916714a25aSJames Feist { 92de5e9705SJames Feist 93de5e9705SJames Feist auto getter = std::make_shared<GetSensorConfiguration>( 94de5e9705SJames Feist dbusConnection, 95de5e9705SJames Feist std::move([&io, &objectServer, &tachSensors, &pwmSensors, 96de5e9705SJames Feist &dbusConnection, &sensorsChanged]( 97de5e9705SJames Feist const ManagedObjectType& sensorConfigurations) { 986714a25aSJames Feist bool firstScan = sensorsChanged == nullptr; 996714a25aSJames Feist std::vector<fs::path> paths; 100de5e9705SJames Feist if (!findFiles(fs::path("/sys/class/hwmon"), R"(fan\d+_input)", 101de5e9705SJames Feist paths)) 1026714a25aSJames Feist { 1036714a25aSJames Feist std::cerr << "No temperature sensors in system\n"; 1046714a25aSJames Feist return; 1056714a25aSJames Feist } 1066714a25aSJames Feist 107*d320a2e1SJason Ling // pwm index, sysfs path, pwm name 108*d320a2e1SJason Ling std::vector<std::tuple<uint8_t, std::string, std::string>> 109*d320a2e1SJason Ling pwmNumbers; 1108e94c204SJames Feist 1116714a25aSJames Feist // iterate through all found fan sensors, and try to match them with 1126714a25aSJames Feist // configuration 11395b079b7SJames Feist for (const auto& path : paths) 1146714a25aSJames Feist { 1156714a25aSJames Feist std::smatch match; 1166714a25aSJames Feist std::string pathStr = path.string(); 1176714a25aSJames Feist 1189ced0a38SJae Hyun Yoo std::regex_search(pathStr, match, inputRegex); 1196714a25aSJames Feist std::string indexStr = *(match.begin() + 1); 1206714a25aSJames Feist 1216714a25aSJames Feist auto directory = path.parent_path(); 12295b079b7SJames Feist FanTypes fanType = getFanType(directory); 12395b079b7SJames Feist size_t bus = 0; 12495b079b7SJames Feist size_t address = 0; 12595b079b7SJames Feist if (fanType == FanTypes::i2c) 12695b079b7SJames Feist { 12795b079b7SJames Feist std::string link = 12895b079b7SJames Feist fs::read_symlink(directory / "device").filename(); 12995b079b7SJames Feist 13095b079b7SJames Feist size_t findDash = link.find("-"); 131de5e9705SJames Feist if (findDash == std::string::npos || 132de5e9705SJames Feist link.size() <= findDash + 1) 13395b079b7SJames Feist { 13495b079b7SJames Feist std::cerr << "Error finding device from symlink"; 13595b079b7SJames Feist } 13695b079b7SJames Feist bus = std::stoi(link.substr(0, findDash)); 13795b079b7SJames Feist address = std::stoi(link.substr(findDash + 1), nullptr, 16); 13895b079b7SJames Feist } 1396714a25aSJames Feist // convert to 0 based 1406714a25aSJames Feist size_t index = std::stoul(indexStr) - 1; 1416714a25aSJames Feist 1426714a25aSJames Feist const char* baseType; 1436714a25aSJames Feist const SensorData* sensorData = nullptr; 1446714a25aSJames Feist const std::string* interfacePath = nullptr; 14587d713abSJames Feist const SensorBaseConfiguration* baseConfiguration = nullptr; 146de5e9705SJames Feist for (const std::pair<sdbusplus::message::object_path, 147de5e9705SJames Feist SensorData>& sensor : sensorConfigurations) 1486714a25aSJames Feist { 149de5e9705SJames Feist // find the base of the configuration to see if indexes 150de5e9705SJames Feist // match 1519ced0a38SJae Hyun Yoo for (const char* type : sensorTypes) 1526714a25aSJames Feist { 1536714a25aSJames Feist auto sensorBaseFind = sensor.second.find(type); 1546714a25aSJames Feist if (sensorBaseFind != sensor.second.end()) 1556714a25aSJames Feist { 1566714a25aSJames Feist baseConfiguration = &(*sensorBaseFind); 1576714a25aSJames Feist interfacePath = &(sensor.first.str); 1586714a25aSJames Feist baseType = type; 1596714a25aSJames Feist break; 1606714a25aSJames Feist } 1616714a25aSJames Feist } 1626714a25aSJames Feist if (baseConfiguration == nullptr) 1636714a25aSJames Feist { 1646714a25aSJames Feist continue; 1656714a25aSJames Feist } 166347dd4e7SZhikui Ren 1676714a25aSJames Feist auto findIndex = baseConfiguration->second.find("Index"); 1686714a25aSJames Feist if (findIndex == baseConfiguration->second.end()) 1696714a25aSJames Feist { 170de5e9705SJames Feist std::cerr << baseConfiguration->first 171de5e9705SJames Feist << " missing index\n"; 1726714a25aSJames Feist continue; 1736714a25aSJames Feist } 174de5e9705SJames Feist unsigned int configIndex = std::visit( 175de5e9705SJames Feist VariantToUnsignedIntVisitor(), findIndex->second); 1766714a25aSJames Feist if (configIndex != index) 1776714a25aSJames Feist { 1786714a25aSJames Feist continue; 1796714a25aSJames Feist } 180de5e9705SJames Feist if (fanType == FanTypes::aspeed || 181de5e9705SJames Feist fanType == FanTypes::nuvoton) 1826714a25aSJames Feist { 183de5e9705SJames Feist // there will be only 1 aspeed or nuvoton sensor object 184de5e9705SJames Feist // in sysfs, we found the fan 18595b079b7SJames Feist sensorData = &(sensor.second); 18695b079b7SJames Feist break; 18795b079b7SJames Feist } 188b6c0b914SJames Feist else if (baseType == 189de5e9705SJames Feist std::string( 190de5e9705SJames Feist "xyz.openbmc_project.Configuration.I2CFan")) 19195b079b7SJames Feist { 19295b079b7SJames Feist auto findBus = baseConfiguration->second.find("Bus"); 193de5e9705SJames Feist auto findAddress = 194de5e9705SJames Feist baseConfiguration->second.find("Address"); 19595b079b7SJames Feist if (findBus == baseConfiguration->second.end() || 19695b079b7SJames Feist findAddress == baseConfiguration->second.end()) 19795b079b7SJames Feist { 19895b079b7SJames Feist std::cerr << baseConfiguration->first 19995b079b7SJames Feist << " missing bus or address\n"; 2006714a25aSJames Feist continue; 2016714a25aSJames Feist } 202de5e9705SJames Feist unsigned int configBus = std::visit( 203de5e9705SJames Feist VariantToUnsignedIntVisitor(), findBus->second); 2043eb82629SJames Feist unsigned int configAddress = std::visit( 20595b079b7SJames Feist VariantToUnsignedIntVisitor(), findAddress->second); 20695b079b7SJames Feist 20784e9e662SJae Hyun Yoo if (configBus == bus && configAddress == address) 2086714a25aSJames Feist { 2096714a25aSJames Feist sensorData = &(sensor.second); 2106714a25aSJames Feist break; 2116714a25aSJames Feist } 2126714a25aSJames Feist } 21395b079b7SJames Feist } 2146714a25aSJames Feist if (sensorData == nullptr) 2156714a25aSJames Feist { 216de5e9705SJames Feist std::cerr << "failed to find match for " << path.string() 217de5e9705SJames Feist << "\n"; 2186714a25aSJames Feist continue; 2196714a25aSJames Feist } 2206714a25aSJames Feist 2216714a25aSJames Feist auto findSensorName = baseConfiguration->second.find("Name"); 222347dd4e7SZhikui Ren 2236714a25aSJames Feist if (findSensorName == baseConfiguration->second.end()) 2246714a25aSJames Feist { 2256714a25aSJames Feist std::cerr << "could not determine configuration name for " 2266714a25aSJames Feist << path.string() << "\n"; 2276714a25aSJames Feist continue; 2286714a25aSJames Feist } 229de5e9705SJames Feist std::string sensorName = 230de5e9705SJames Feist std::get<std::string>(findSensorName->second); 231347dd4e7SZhikui Ren 2326714a25aSJames Feist // on rescans, only update sensors we were signaled by 2336714a25aSJames Feist auto findSensor = tachSensors.find(sensorName); 2346714a25aSJames Feist if (!firstScan && findSensor != tachSensors.end()) 2356714a25aSJames Feist { 2366714a25aSJames Feist bool found = false; 237de5e9705SJames Feist for (auto it = sensorsChanged->begin(); 238de5e9705SJames Feist it != sensorsChanged->end(); it++) 2396714a25aSJames Feist { 2406714a25aSJames Feist if (boost::ends_with(*it, findSensor->second->name)) 2416714a25aSJames Feist { 2426714a25aSJames Feist sensorsChanged->erase(it); 2436714a25aSJames Feist findSensor->second = nullptr; 2446714a25aSJames Feist found = true; 2456714a25aSJames Feist break; 2466714a25aSJames Feist } 2476714a25aSJames Feist } 2486714a25aSJames Feist if (!found) 2496714a25aSJames Feist { 2506714a25aSJames Feist continue; 2516714a25aSJames Feist } 2526714a25aSJames Feist } 2536714a25aSJames Feist std::vector<thresholds::Threshold> sensorThresholds; 2549ced0a38SJae Hyun Yoo if (!parseThresholdsFromConfig(*sensorData, sensorThresholds)) 2556714a25aSJames Feist { 256de5e9705SJames Feist std::cerr << "error populating thresholds for " 257de5e9705SJames Feist << sensorName << "\n"; 2586714a25aSJames Feist } 2596714a25aSJames Feist 2607bc2bab2SJames Feist auto presenceConfig = 2617bc2bab2SJames Feist sensorData->find(baseType + std::string(".Presence")); 2627bc2bab2SJames Feist 2637bc2bab2SJames Feist std::unique_ptr<PresenceSensor> presenceSensor(nullptr); 2647bc2bab2SJames Feist 2657bc2bab2SJames Feist // presence sensors are optional 2667bc2bab2SJames Feist if (presenceConfig != sensorData->end()) 2677bc2bab2SJames Feist { 2687bc2bab2SJames Feist auto findPolarity = presenceConfig->second.find("Polarity"); 269347dd4e7SZhikui Ren auto findPinName = presenceConfig->second.find("PinName"); 2707bc2bab2SJames Feist 271347dd4e7SZhikui Ren if (findPinName == presenceConfig->second.end() || 2727bc2bab2SJames Feist findPolarity == presenceConfig->second.end()) 2737bc2bab2SJames Feist { 2747bc2bab2SJames Feist std::cerr << "Malformed Presence Configuration\n"; 2757bc2bab2SJames Feist } 2767bc2bab2SJames Feist else 2777bc2bab2SJames Feist { 278de5e9705SJames Feist bool inverted = std::get<std::string>( 279de5e9705SJames Feist findPolarity->second) == "Low"; 280347dd4e7SZhikui Ren if (auto pinName = 281347dd4e7SZhikui Ren std::get_if<std::string>(&findPinName->second)) 282347dd4e7SZhikui Ren { 2837b18b1e0SJames Feist presenceSensor = std::make_unique<PresenceSensor>( 284347dd4e7SZhikui Ren *pinName, inverted, io, sensorName); 285347dd4e7SZhikui Ren } 286347dd4e7SZhikui Ren else 287347dd4e7SZhikui Ren { 288347dd4e7SZhikui Ren std::cerr 289347dd4e7SZhikui Ren << "Malformed Presence pinName for sensor " 290347dd4e7SZhikui Ren << sensorName << " \n"; 291347dd4e7SZhikui Ren } 2927bc2bab2SJames Feist } 2937bc2bab2SJames Feist } 2947b18b1e0SJames Feist std::optional<RedundancySensor>* redundancy = nullptr; 29595b079b7SJames Feist if (fanType == FanTypes::aspeed) 29695b079b7SJames Feist { 2977b18b1e0SJames Feist redundancy = &systemRedundancy; 29895b079b7SJames Feist } 2997bc2bab2SJames Feist 30087d713abSJames Feist constexpr double defaultMaxReading = 25000; 30187d713abSJames Feist constexpr double defaultMinReading = 0; 302de5e9705SJames Feist auto limits = 303de5e9705SJames Feist std::make_pair(defaultMinReading, defaultMaxReading); 30487d713abSJames Feist 30587d713abSJames Feist findLimits(limits, baseConfiguration); 3066714a25aSJames Feist tachSensors[sensorName] = std::make_unique<TachSensor>( 307ce3fca41SJames Feist path.string(), baseType, objectServer, dbusConnection, 30895b079b7SJames Feist std::move(presenceSensor), redundancy, io, sensorName, 30987d713abSJames Feist std::move(sensorThresholds), *interfacePath, limits); 3108e94c204SJames Feist 311de5e9705SJames Feist auto connector = 312de5e9705SJames Feist sensorData->find(baseType + std::string(".Connector")); 3138e94c204SJames Feist if (connector != sensorData->end()) 3148e94c204SJames Feist { 3158e94c204SJames Feist auto findPwm = connector->second.find("Pwm"); 3168e94c204SJames Feist if (findPwm == connector->second.end()) 3178e94c204SJames Feist { 3188e94c204SJames Feist std::cerr << "Connector Missing PWM!\n"; 3198e94c204SJames Feist continue; 3208e94c204SJames Feist } 321de5e9705SJames Feist size_t pwm = std::visit(VariantToUnsignedIntVisitor(), 322de5e9705SJames Feist findPwm->second); 323*d320a2e1SJason Ling /* use pwm name override if found in configuration else use 324*d320a2e1SJason Ling * default */ 325*d320a2e1SJason Ling auto findOverride = connector->second.find("PwmName"); 326*d320a2e1SJason Ling std::string pwmName; 327*d320a2e1SJason Ling if (findOverride != connector->second.end()) 328*d320a2e1SJason Ling { 329*d320a2e1SJason Ling pwmName = std::visit(VariantToStringVisitor(), 330*d320a2e1SJason Ling findOverride->second); 331*d320a2e1SJason Ling } 332*d320a2e1SJason Ling else 333*d320a2e1SJason Ling { 334*d320a2e1SJason Ling pwmName = "Pwm_" + std::to_string(pwm + 1); 335*d320a2e1SJason Ling } 336*d320a2e1SJason Ling pwmNumbers.emplace_back(pwm, *interfacePath, pwmName); 3378e94c204SJames Feist } 3386714a25aSJames Feist } 3396714a25aSJames Feist std::vector<fs::path> pwms; 3408e94c204SJames Feist if (!findFiles(fs::path("/sys/class/hwmon"), R"(pwm\d+$)", pwms)) 3416714a25aSJames Feist { 3426714a25aSJames Feist std::cerr << "No pwm in system\n"; 3436714a25aSJames Feist return; 3446714a25aSJames Feist } 3456714a25aSJames Feist for (const fs::path& pwm : pwms) 3466714a25aSJames Feist { 34795b079b7SJames Feist if (pwmSensors.find(pwm) != pwmSensors.end()) 34895b079b7SJames Feist { 34995b079b7SJames Feist continue; 35095b079b7SJames Feist } 35182bac4c7SJames Feist const std::string* path = nullptr; 352*d320a2e1SJason Ling const std::string* pwmName = nullptr; 353*d320a2e1SJason Ling 354*d320a2e1SJason Ling for (const auto& [index, configPath, name] : pwmNumbers) 3558e94c204SJames Feist { 356de5e9705SJames Feist if (boost::ends_with(pwm.string(), 357de5e9705SJames Feist std::to_string(index + 1))) 3588e94c204SJames Feist { 35982bac4c7SJames Feist path = &configPath; 360*d320a2e1SJason Ling pwmName = &name; 3618e94c204SJames Feist break; 3628e94c204SJames Feist } 3638e94c204SJames Feist } 3648e94c204SJames Feist 36582bac4c7SJames Feist if (path == nullptr) 3668e94c204SJames Feist { 3678e94c204SJames Feist continue; 3688e94c204SJames Feist } 3698e94c204SJames Feist 3706714a25aSJames Feist // only add new elements 371916360b8SCheng C Yang const std::string& sysPath = pwm.string(); 372de5e9705SJames Feist pwmSensors.insert( 373de5e9705SJames Feist std::pair<std::string, std::unique_ptr<PwmSensor>>( 374de5e9705SJames Feist sysPath, std::make_unique<PwmSensor>( 375*d320a2e1SJason Ling *pwmName, sysPath, dbusConnection, 376d9d8cafcSAppaRao Puli objectServer, *path, "Fan"))); 3776714a25aSJames Feist } 378de5e9705SJames Feist })); 379de5e9705SJames Feist getter->getConfiguration( 380de5e9705SJames Feist std::vector<std::string>{sensorTypes.begin(), sensorTypes.end()}); 3816714a25aSJames Feist } 3826714a25aSJames Feist 383dc6c55f3SJames Feist void createRedundancySensor( 384dc6c55f3SJames Feist const boost::container::flat_map<std::string, std::unique_ptr<TachSensor>>& 385dc6c55f3SJames Feist sensors, 386dc6c55f3SJames Feist std::shared_ptr<sdbusplus::asio::connection> conn, 387dc6c55f3SJames Feist sdbusplus::asio::object_server& objectServer) 388dc6c55f3SJames Feist { 389dc6c55f3SJames Feist 390dc6c55f3SJames Feist conn->async_method_call( 391dc6c55f3SJames Feist [&objectServer, &sensors](boost::system::error_code& ec, 392dc6c55f3SJames Feist const ManagedObjectType managedObj) { 393dc6c55f3SJames Feist if (ec) 394dc6c55f3SJames Feist { 395dc6c55f3SJames Feist std::cerr << "Error calling entity manager \n"; 396dc6c55f3SJames Feist return; 397dc6c55f3SJames Feist } 398dc6c55f3SJames Feist for (const auto& pathPair : managedObj) 399dc6c55f3SJames Feist { 400dc6c55f3SJames Feist for (const auto& interfacePair : pathPair.second) 401dc6c55f3SJames Feist { 402dc6c55f3SJames Feist if (interfacePair.first == redundancyConfiguration) 403dc6c55f3SJames Feist { 404dc6c55f3SJames Feist // currently only support one 405dc6c55f3SJames Feist auto findCount = 406dc6c55f3SJames Feist interfacePair.second.find("AllowedFailures"); 407dc6c55f3SJames Feist if (findCount == interfacePair.second.end()) 408dc6c55f3SJames Feist { 409dc6c55f3SJames Feist std::cerr << "Malformed redundancy record \n"; 410dc6c55f3SJames Feist return; 411dc6c55f3SJames Feist } 412dc6c55f3SJames Feist std::vector<std::string> sensorList; 413dc6c55f3SJames Feist 414dc6c55f3SJames Feist for (const auto& sensor : sensors) 415dc6c55f3SJames Feist { 416dc6c55f3SJames Feist sensorList.push_back( 417dc6c55f3SJames Feist "/xyz/openbmc_project/sensors/fan_tach/" + 418dc6c55f3SJames Feist sensor.second->name); 419dc6c55f3SJames Feist } 4207b18b1e0SJames Feist systemRedundancy.reset(); 4217b18b1e0SJames Feist systemRedundancy.emplace(RedundancySensor( 4223eb82629SJames Feist std::get<uint64_t>(findCount->second), sensorList, 4237b18b1e0SJames Feist objectServer, pathPair.first)); 424dc6c55f3SJames Feist 425dc6c55f3SJames Feist return; 426dc6c55f3SJames Feist } 427dc6c55f3SJames Feist } 428dc6c55f3SJames Feist } 429dc6c55f3SJames Feist }, 430dc6c55f3SJames Feist "xyz.openbmc_project.EntityManager", "/", 431dc6c55f3SJames Feist "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 432dc6c55f3SJames Feist } 433dc6c55f3SJames Feist 434b6c0b914SJames Feist int main() 4356714a25aSJames Feist { 4366714a25aSJames Feist boost::asio::io_service io; 4376714a25aSJames Feist auto systemBus = std::make_shared<sdbusplus::asio::connection>(io); 4386714a25aSJames Feist systemBus->request_name("xyz.openbmc_project.FanSensor"); 4396714a25aSJames Feist sdbusplus::asio::object_server objectServer(systemBus); 4406714a25aSJames Feist boost::container::flat_map<std::string, std::unique_ptr<TachSensor>> 4416714a25aSJames Feist tachSensors; 4426714a25aSJames Feist boost::container::flat_map<std::string, std::unique_ptr<PwmSensor>> 4436714a25aSJames Feist pwmSensors; 4446714a25aSJames Feist std::vector<std::unique_ptr<sdbusplus::bus::match::match>> matches; 4456714a25aSJames Feist std::unique_ptr<boost::container::flat_set<std::string>> sensorsChanged = 4466714a25aSJames Feist std::make_unique<boost::container::flat_set<std::string>>(); 4476714a25aSJames Feist 4486714a25aSJames Feist io.post([&]() { 4496714a25aSJames Feist createSensors(io, objectServer, tachSensors, pwmSensors, systemBus, 4506714a25aSJames Feist nullptr); 451dc6c55f3SJames Feist createRedundancySensor(tachSensors, systemBus, objectServer); 4526714a25aSJames Feist }); 4536714a25aSJames Feist 4546714a25aSJames Feist boost::asio::deadline_timer filterTimer(io); 4556714a25aSJames Feist std::function<void(sdbusplus::message::message&)> eventHandler = 4566714a25aSJames Feist [&](sdbusplus::message::message& message) { 4576714a25aSJames Feist if (message.is_method_error()) 4586714a25aSJames Feist { 4596714a25aSJames Feist std::cerr << "callback method error\n"; 4606714a25aSJames Feist return; 4616714a25aSJames Feist } 4626714a25aSJames Feist sensorsChanged->insert(message.get_path()); 4636714a25aSJames Feist // this implicitly cancels the timer 4646714a25aSJames Feist filterTimer.expires_from_now(boost::posix_time::seconds(1)); 4656714a25aSJames Feist 4666714a25aSJames Feist filterTimer.async_wait([&](const boost::system::error_code& ec) { 4676714a25aSJames Feist if (ec == boost::asio::error::operation_aborted) 4686714a25aSJames Feist { 4696714a25aSJames Feist /* we were canceled*/ 4706714a25aSJames Feist return; 4716714a25aSJames Feist } 4726714a25aSJames Feist else if (ec) 4736714a25aSJames Feist { 4746714a25aSJames Feist std::cerr << "timer error\n"; 4756714a25aSJames Feist return; 4766714a25aSJames Feist } 4776714a25aSJames Feist createSensors(io, objectServer, tachSensors, pwmSensors, 4786714a25aSJames Feist systemBus, sensorsChanged); 4796714a25aSJames Feist }); 4806714a25aSJames Feist }; 4816714a25aSJames Feist 4829ced0a38SJae Hyun Yoo for (const char* type : sensorTypes) 4836714a25aSJames Feist { 4846714a25aSJames Feist auto match = std::make_unique<sdbusplus::bus::match::match>( 4856714a25aSJames Feist static_cast<sdbusplus::bus::bus&>(*systemBus), 4866714a25aSJames Feist "type='signal',member='PropertiesChanged',path_namespace='" + 4879ced0a38SJae Hyun Yoo std::string(inventoryPath) + "',arg0namespace='" + type + "'", 4886714a25aSJames Feist eventHandler); 4896714a25aSJames Feist matches.emplace_back(std::move(match)); 4906714a25aSJames Feist } 4916714a25aSJames Feist 492dc6c55f3SJames Feist // redundancy sensor 493dc6c55f3SJames Feist std::function<void(sdbusplus::message::message&)> redundancyHandler = 494dc6c55f3SJames Feist [&tachSensors, &systemBus, 495b6c0b914SJames Feist &objectServer](sdbusplus::message::message&) { 496dc6c55f3SJames Feist createRedundancySensor(tachSensors, systemBus, objectServer); 497dc6c55f3SJames Feist }; 498dc6c55f3SJames Feist auto match = std::make_unique<sdbusplus::bus::match::match>( 499dc6c55f3SJames Feist static_cast<sdbusplus::bus::bus&>(*systemBus), 500dc6c55f3SJames Feist "type='signal',member='PropertiesChanged',path_namespace='" + 501dc6c55f3SJames Feist std::string(inventoryPath) + "',arg0namespace='" + 502dc6c55f3SJames Feist redundancyConfiguration + "'", 503b6c0b914SJames Feist std::move(redundancyHandler)); 504dc6c55f3SJames Feist matches.emplace_back(std::move(match)); 505dc6c55f3SJames Feist 5066714a25aSJames Feist io.run(); 5076714a25aSJames Feist } 508