xref: /openbmc/dbus-sensors/src/FanMain.cpp (revision d320a2e1)
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