xref: /openbmc/dbus-sensors/src/FanMain.cpp (revision add46820)
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 <PwmSensor.hpp>
188a57ec09SEd Tanous #include <TachSensor.hpp>
198a57ec09SEd Tanous #include <Utils.hpp>
208a57ec09SEd Tanous #include <VariantVisitors.hpp>
216714a25aSJames Feist #include <boost/algorithm/string/predicate.hpp>
226714a25aSJames Feist #include <boost/algorithm/string/replace.hpp>
2396e97db7SPatrick Venture #include <boost/container/flat_map.hpp>
246714a25aSJames Feist #include <boost/container/flat_set.hpp>
256714a25aSJames Feist #include <boost/lexical_cast.hpp>
2638fb5983SJames Feist #include <sdbusplus/asio/connection.hpp>
2738fb5983SJames Feist #include <sdbusplus/asio/object_server.hpp>
2838fb5983SJames Feist #include <sdbusplus/bus/match.hpp>
2938fb5983SJames Feist 
3038fb5983SJames Feist #include <array>
3124f02f24SJames Feist #include <filesystem>
326714a25aSJames Feist #include <fstream>
3396e97db7SPatrick Venture #include <functional>
3496e97db7SPatrick Venture #include <memory>
3596e97db7SPatrick Venture #include <optional>
366714a25aSJames Feist #include <regex>
3796e97db7SPatrick Venture #include <string>
3896e97db7SPatrick Venture #include <utility>
3996e97db7SPatrick Venture #include <variant>
4096e97db7SPatrick Venture #include <vector>
416714a25aSJames Feist 
428a57ec09SEd Tanous static constexpr bool debug = false;
436714a25aSJames Feist 
44cf3bce6eSJames Feist namespace fs = std::filesystem;
453eb82629SJames Feist 
46a3e8f2a3SYong Zhao // The following two structures need to be consistent
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"};
51a3e8f2a3SYong Zhao 
52a3e8f2a3SYong Zhao enum FanTypes
53a3e8f2a3SYong Zhao {
54a3e8f2a3SYong Zhao     aspeed = 0,
55a3e8f2a3SYong Zhao     i2c,
56a3e8f2a3SYong Zhao     nuvoton,
57a3e8f2a3SYong Zhao     max,
58a3e8f2a3SYong Zhao };
59a3e8f2a3SYong Zhao 
60a3e8f2a3SYong Zhao static_assert(std::tuple_size<decltype(sensorTypes)>::value == FanTypes::max,
61a3e8f2a3SYong Zhao               "sensorTypes element number is not equal to FanTypes number");
62a3e8f2a3SYong Zhao 
63dc6c55f3SJames Feist constexpr const char* redundancyConfiguration =
64dc6c55f3SJames Feist     "xyz.openbmc_project.Configuration.FanRedundancy";
659ced0a38SJae Hyun Yoo static std::regex inputRegex(R"(fan(\d+)_input)");
666714a25aSJames Feist 
67dc6c55f3SJames Feist // todo: power supply fan redundancy
687b18b1e0SJames Feist std::optional<RedundancySensor> systemRedundancy;
6995b079b7SJames Feist 
7095b079b7SJames Feist FanTypes getFanType(const fs::path& parentPath)
7195b079b7SJames Feist {
7295b079b7SJames Feist     fs::path linkPath = parentPath / "device";
7395b079b7SJames Feist     std::string canonical = fs::read_symlink(linkPath);
74241356e3SJae Hyun Yoo     if (boost::ends_with(canonical, "1e786000.pwm-tacho-controller") ||
75241356e3SJae Hyun Yoo         boost::ends_with(canonical, "1e610000.pwm-tacho-controller"))
7695b079b7SJames Feist     {
7795b079b7SJames Feist         return FanTypes::aspeed;
7895b079b7SJames Feist     }
798a57ec09SEd Tanous     if (boost::ends_with(canonical, "f0103000.pwm-fan-controller"))
808843b627SPeter Lundgren     {
818843b627SPeter Lundgren         return FanTypes::nuvoton;
828843b627SPeter Lundgren     }
8395b079b7SJames Feist     // todo: will we need to support other types?
8495b079b7SJames Feist     return FanTypes::i2c;
8595b079b7SJames Feist }
86dc6c55f3SJames Feist 
87d540741eSKuiying Wang void createRedundancySensor(
88d540741eSKuiying Wang     const boost::container::flat_map<std::string, std::unique_ptr<TachSensor>>&
89d540741eSKuiying Wang         sensors,
908a57ec09SEd Tanous     const std::shared_ptr<sdbusplus::asio::connection>& conn,
91d540741eSKuiying Wang     sdbusplus::asio::object_server& objectServer)
92d540741eSKuiying Wang {
93d540741eSKuiying Wang 
94d540741eSKuiying Wang     conn->async_method_call(
95d540741eSKuiying Wang         [&objectServer, &sensors](boost::system::error_code& ec,
968a57ec09SEd Tanous                                   const ManagedObjectType& managedObj) {
97d540741eSKuiying Wang             if (ec)
98d540741eSKuiying Wang             {
99d540741eSKuiying Wang                 std::cerr << "Error calling entity manager \n";
100d540741eSKuiying Wang                 return;
101d540741eSKuiying Wang             }
102d540741eSKuiying Wang             for (const auto& pathPair : managedObj)
103d540741eSKuiying Wang             {
104d540741eSKuiying Wang                 for (const auto& interfacePair : pathPair.second)
105d540741eSKuiying Wang                 {
106d540741eSKuiying Wang                     if (interfacePair.first == redundancyConfiguration)
107d540741eSKuiying Wang                     {
108d540741eSKuiying Wang                         // currently only support one
109d540741eSKuiying Wang                         auto findCount =
110d540741eSKuiying Wang                             interfacePair.second.find("AllowedFailures");
111d540741eSKuiying Wang                         if (findCount == interfacePair.second.end())
112d540741eSKuiying Wang                         {
113d540741eSKuiying Wang                             std::cerr << "Malformed redundancy record \n";
114d540741eSKuiying Wang                             return;
115d540741eSKuiying Wang                         }
116d540741eSKuiying Wang                         std::vector<std::string> sensorList;
117d540741eSKuiying Wang 
118d540741eSKuiying Wang                         for (const auto& sensor : sensors)
119d540741eSKuiying Wang                         {
120d540741eSKuiying Wang                             sensorList.push_back(
121d540741eSKuiying Wang                                 "/xyz/openbmc_project/sensors/fan_tach/" +
122d540741eSKuiying Wang                                 sensor.second->name);
123d540741eSKuiying Wang                         }
124d540741eSKuiying Wang                         systemRedundancy.reset();
125d540741eSKuiying Wang                         systemRedundancy.emplace(RedundancySensor(
126d540741eSKuiying Wang                             std::get<uint64_t>(findCount->second), sensorList,
127d540741eSKuiying Wang                             objectServer, pathPair.first));
128d540741eSKuiying Wang 
129d540741eSKuiying Wang                         return;
130d540741eSKuiying Wang                     }
131d540741eSKuiying Wang                 }
132d540741eSKuiying Wang             }
133d540741eSKuiying Wang         },
134d540741eSKuiying Wang         "xyz.openbmc_project.EntityManager", "/",
135d540741eSKuiying Wang         "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
136d540741eSKuiying Wang }
137d540741eSKuiying Wang 
1386714a25aSJames Feist void createSensors(
1396714a25aSJames Feist     boost::asio::io_service& io, sdbusplus::asio::object_server& objectServer,
1406714a25aSJames Feist     boost::container::flat_map<std::string, std::unique_ptr<TachSensor>>&
1416714a25aSJames Feist         tachSensors,
1426714a25aSJames Feist     boost::container::flat_map<std::string, std::unique_ptr<PwmSensor>>&
1436714a25aSJames Feist         pwmSensors,
1446714a25aSJames Feist     std::shared_ptr<sdbusplus::asio::connection>& dbusConnection,
1455591cf08SJames Feist     const std::shared_ptr<boost::container::flat_set<std::string>>&
146f27a55c7SJames Feist         sensorsChanged,
147f27a55c7SJames Feist     size_t retries = 0)
1486714a25aSJames Feist {
149de5e9705SJames Feist     auto getter = std::make_shared<GetSensorConfiguration>(
150de5e9705SJames Feist         dbusConnection,
151de5e9705SJames Feist         std::move([&io, &objectServer, &tachSensors, &pwmSensors,
1525591cf08SJames Feist                    &dbusConnection, sensorsChanged](
153de5e9705SJames Feist                       const ManagedObjectType& sensorConfigurations) {
1546714a25aSJames Feist             bool firstScan = sensorsChanged == nullptr;
1556714a25aSJames Feist             std::vector<fs::path> paths;
156de5e9705SJames Feist             if (!findFiles(fs::path("/sys/class/hwmon"), R"(fan\d+_input)",
157de5e9705SJames Feist                            paths))
1586714a25aSJames Feist             {
15977b3add2SYong Zhao                 std::cerr << "No fan sensors in system\n";
1606714a25aSJames Feist                 return;
1616714a25aSJames Feist             }
1626714a25aSJames Feist 
1636714a25aSJames Feist             // iterate through all found fan sensors, and try to match them with
1646714a25aSJames Feist             // configuration
16595b079b7SJames Feist             for (const auto& path : paths)
1666714a25aSJames Feist             {
1676714a25aSJames Feist                 std::smatch match;
1686714a25aSJames Feist                 std::string pathStr = path.string();
1696714a25aSJames Feist 
1709ced0a38SJae Hyun Yoo                 std::regex_search(pathStr, match, inputRegex);
1716714a25aSJames Feist                 std::string indexStr = *(match.begin() + 1);
1726714a25aSJames Feist 
17377b3add2SYong Zhao                 fs::path directory = path.parent_path();
17495b079b7SJames Feist                 FanTypes fanType = getFanType(directory);
17577b3add2SYong Zhao 
1766714a25aSJames Feist                 // convert to 0 based
1776714a25aSJames Feist                 size_t index = std::stoul(indexStr) - 1;
1786714a25aSJames Feist 
1796714a25aSJames Feist                 const char* baseType;
1806714a25aSJames Feist                 const SensorData* sensorData = nullptr;
1816714a25aSJames Feist                 const std::string* interfacePath = nullptr;
18287d713abSJames Feist                 const SensorBaseConfiguration* baseConfiguration = nullptr;
183de5e9705SJames Feist                 for (const std::pair<sdbusplus::message::object_path,
184de5e9705SJames Feist                                      SensorData>& sensor : sensorConfigurations)
1856714a25aSJames Feist                 {
186de5e9705SJames Feist                     // find the base of the configuration to see if indexes
187de5e9705SJames Feist                     // match
188a3e8f2a3SYong Zhao                     auto sensorBaseFind =
189a3e8f2a3SYong Zhao                         sensor.second.find(sensorTypes[fanType]);
190a3e8f2a3SYong Zhao                     if (sensorBaseFind == sensor.second.end())
1916714a25aSJames Feist                     {
1926714a25aSJames Feist                         continue;
1936714a25aSJames Feist                     }
194347dd4e7SZhikui Ren 
195a3e8f2a3SYong Zhao                     baseConfiguration = &(*sensorBaseFind);
196a3e8f2a3SYong Zhao                     interfacePath = &(sensor.first.str);
197a3e8f2a3SYong Zhao                     baseType = sensorTypes[fanType];
198a3e8f2a3SYong Zhao 
1996714a25aSJames Feist                     auto findIndex = baseConfiguration->second.find("Index");
2006714a25aSJames Feist                     if (findIndex == baseConfiguration->second.end())
2016714a25aSJames Feist                     {
202de5e9705SJames Feist                         std::cerr << baseConfiguration->first
203de5e9705SJames Feist                                   << " missing index\n";
2046714a25aSJames Feist                         continue;
2056714a25aSJames Feist                     }
206de5e9705SJames Feist                     unsigned int configIndex = std::visit(
207de5e9705SJames Feist                         VariantToUnsignedIntVisitor(), findIndex->second);
2086714a25aSJames Feist                     if (configIndex != index)
2096714a25aSJames Feist                     {
2106714a25aSJames Feist                         continue;
2116714a25aSJames Feist                     }
212de5e9705SJames Feist                     if (fanType == FanTypes::aspeed ||
213de5e9705SJames Feist                         fanType == FanTypes::nuvoton)
2146714a25aSJames Feist                     {
215de5e9705SJames Feist                         // there will be only 1 aspeed or nuvoton sensor object
216de5e9705SJames Feist                         // in sysfs, we found the fan
21795b079b7SJames Feist                         sensorData = &(sensor.second);
21895b079b7SJames Feist                         break;
21995b079b7SJames Feist                     }
2208a57ec09SEd Tanous                     if (fanType == FanTypes::i2c)
22195b079b7SJames Feist                     {
222*add46820SYong Zhao                         size_t bus = 0;
223*add46820SYong Zhao                         size_t address = 0;
224*add46820SYong Zhao 
225*add46820SYong Zhao                         std::string link =
226*add46820SYong Zhao                             fs::read_symlink(directory / "device").filename();
227*add46820SYong Zhao 
228*add46820SYong Zhao                         size_t findDash = link.find('-');
229*add46820SYong Zhao                         if (findDash == std::string::npos ||
230*add46820SYong Zhao                             link.size() <= findDash + 1)
231*add46820SYong Zhao                         {
232*add46820SYong Zhao                             std::cerr << "Error finding device from symlink";
233*add46820SYong Zhao                         }
234*add46820SYong Zhao                         bus = std::stoi(link.substr(0, findDash));
235*add46820SYong Zhao                         address =
236*add46820SYong Zhao                             std::stoi(link.substr(findDash + 1), nullptr, 16);
237*add46820SYong Zhao 
23895b079b7SJames Feist                         auto findBus = baseConfiguration->second.find("Bus");
239de5e9705SJames Feist                         auto findAddress =
240de5e9705SJames Feist                             baseConfiguration->second.find("Address");
24195b079b7SJames Feist                         if (findBus == baseConfiguration->second.end() ||
24295b079b7SJames Feist                             findAddress == baseConfiguration->second.end())
24395b079b7SJames Feist                         {
24495b079b7SJames Feist                             std::cerr << baseConfiguration->first
24595b079b7SJames Feist                                       << " missing bus or address\n";
2466714a25aSJames Feist                             continue;
2476714a25aSJames Feist                         }
248de5e9705SJames Feist                         unsigned int configBus = std::visit(
249de5e9705SJames Feist                             VariantToUnsignedIntVisitor(), findBus->second);
2503eb82629SJames Feist                         unsigned int configAddress = std::visit(
25195b079b7SJames Feist                             VariantToUnsignedIntVisitor(), findAddress->second);
25295b079b7SJames Feist 
25384e9e662SJae Hyun Yoo                         if (configBus == bus && configAddress == address)
2546714a25aSJames Feist                         {
2556714a25aSJames Feist                             sensorData = &(sensor.second);
2566714a25aSJames Feist                             break;
2576714a25aSJames Feist                         }
2586714a25aSJames Feist                     }
25995b079b7SJames Feist                 }
2606714a25aSJames Feist                 if (sensorData == nullptr)
2616714a25aSJames Feist                 {
262de5e9705SJames Feist                     std::cerr << "failed to find match for " << path.string()
263de5e9705SJames Feist                               << "\n";
2646714a25aSJames Feist                     continue;
2656714a25aSJames Feist                 }
2666714a25aSJames Feist 
2676714a25aSJames Feist                 auto findSensorName = baseConfiguration->second.find("Name");
268347dd4e7SZhikui Ren 
2696714a25aSJames Feist                 if (findSensorName == baseConfiguration->second.end())
2706714a25aSJames Feist                 {
2716714a25aSJames Feist                     std::cerr << "could not determine configuration name for "
2726714a25aSJames Feist                               << path.string() << "\n";
2736714a25aSJames Feist                     continue;
2746714a25aSJames Feist                 }
275de5e9705SJames Feist                 std::string sensorName =
276de5e9705SJames Feist                     std::get<std::string>(findSensorName->second);
277347dd4e7SZhikui Ren 
2786714a25aSJames Feist                 // on rescans, only update sensors we were signaled by
2796714a25aSJames Feist                 auto findSensor = tachSensors.find(sensorName);
2806714a25aSJames Feist                 if (!firstScan && findSensor != tachSensors.end())
2816714a25aSJames Feist                 {
2826714a25aSJames Feist                     bool found = false;
283de5e9705SJames Feist                     for (auto it = sensorsChanged->begin();
284de5e9705SJames Feist                          it != sensorsChanged->end(); it++)
2856714a25aSJames Feist                     {
2866714a25aSJames Feist                         if (boost::ends_with(*it, findSensor->second->name))
2876714a25aSJames Feist                         {
2886714a25aSJames Feist                             sensorsChanged->erase(it);
2896714a25aSJames Feist                             findSensor->second = nullptr;
2906714a25aSJames Feist                             found = true;
2916714a25aSJames Feist                             break;
2926714a25aSJames Feist                         }
2936714a25aSJames Feist                     }
2946714a25aSJames Feist                     if (!found)
2956714a25aSJames Feist                     {
2966714a25aSJames Feist                         continue;
2976714a25aSJames Feist                     }
2986714a25aSJames Feist                 }
2996714a25aSJames Feist                 std::vector<thresholds::Threshold> sensorThresholds;
3009ced0a38SJae Hyun Yoo                 if (!parseThresholdsFromConfig(*sensorData, sensorThresholds))
3016714a25aSJames Feist                 {
302de5e9705SJames Feist                     std::cerr << "error populating thresholds for "
303de5e9705SJames Feist                               << sensorName << "\n";
3046714a25aSJames Feist                 }
3056714a25aSJames Feist 
3067bc2bab2SJames Feist                 auto presenceConfig =
3077bc2bab2SJames Feist                     sensorData->find(baseType + std::string(".Presence"));
3087bc2bab2SJames Feist 
3097bc2bab2SJames Feist                 std::unique_ptr<PresenceSensor> presenceSensor(nullptr);
3107bc2bab2SJames Feist 
3117bc2bab2SJames Feist                 // presence sensors are optional
3127bc2bab2SJames Feist                 if (presenceConfig != sensorData->end())
3137bc2bab2SJames Feist                 {
3147bc2bab2SJames Feist                     auto findPolarity = presenceConfig->second.find("Polarity");
315347dd4e7SZhikui Ren                     auto findPinName = presenceConfig->second.find("PinName");
3167bc2bab2SJames Feist 
317347dd4e7SZhikui Ren                     if (findPinName == presenceConfig->second.end() ||
3187bc2bab2SJames Feist                         findPolarity == presenceConfig->second.end())
3197bc2bab2SJames Feist                     {
3207bc2bab2SJames Feist                         std::cerr << "Malformed Presence Configuration\n";
3217bc2bab2SJames Feist                     }
3227bc2bab2SJames Feist                     else
3237bc2bab2SJames Feist                     {
324de5e9705SJames Feist                         bool inverted = std::get<std::string>(
325de5e9705SJames Feist                                             findPolarity->second) == "Low";
326347dd4e7SZhikui Ren                         if (auto pinName =
327347dd4e7SZhikui Ren                                 std::get_if<std::string>(&findPinName->second))
328347dd4e7SZhikui Ren                         {
3297b18b1e0SJames Feist                             presenceSensor = std::make_unique<PresenceSensor>(
330347dd4e7SZhikui Ren                                 *pinName, inverted, io, sensorName);
331347dd4e7SZhikui Ren                         }
332347dd4e7SZhikui Ren                         else
333347dd4e7SZhikui Ren                         {
334347dd4e7SZhikui Ren                             std::cerr
335347dd4e7SZhikui Ren                                 << "Malformed Presence pinName for sensor "
336347dd4e7SZhikui Ren                                 << sensorName << " \n";
337347dd4e7SZhikui Ren                         }
3387bc2bab2SJames Feist                     }
3397bc2bab2SJames Feist                 }
3407b18b1e0SJames Feist                 std::optional<RedundancySensor>* redundancy = nullptr;
34195b079b7SJames Feist                 if (fanType == FanTypes::aspeed)
34295b079b7SJames Feist                 {
3437b18b1e0SJames Feist                     redundancy = &systemRedundancy;
34495b079b7SJames Feist                 }
3457bc2bab2SJames Feist 
346f920e09cSJosh Lehan                 PowerState powerState = PowerState::on;
347f920e09cSJosh Lehan                 auto findPower = baseConfiguration->second.find("PowerState");
348f920e09cSJosh Lehan                 if (findPower != baseConfiguration->second.end())
349f920e09cSJosh Lehan                 {
350f920e09cSJosh Lehan                     auto ptrPower =
351f920e09cSJosh Lehan                         std::get_if<std::string>(&(findPower->second));
352f920e09cSJosh Lehan                     if (ptrPower)
353f920e09cSJosh Lehan                     {
354f920e09cSJosh Lehan                         setReadState(*ptrPower, powerState);
355f920e09cSJosh Lehan                     }
356f920e09cSJosh Lehan                 }
357f920e09cSJosh Lehan 
35887d713abSJames Feist                 constexpr double defaultMaxReading = 25000;
35987d713abSJames Feist                 constexpr double defaultMinReading = 0;
360de5e9705SJames Feist                 auto limits =
361de5e9705SJames Feist                     std::make_pair(defaultMinReading, defaultMaxReading);
36287d713abSJames Feist 
363de5e9705SJames Feist                 auto connector =
364de5e9705SJames Feist                     sensorData->find(baseType + std::string(".Connector"));
36549a8ccd6SJames Feist 
36649a8ccd6SJames Feist                 std::optional<std::string> led;
36777b3add2SYong Zhao                 std::string pwmName;
368d05867c0SZhikui Ren                 fs::path pwmPath;
36949a8ccd6SJames Feist 
3708e94c204SJames Feist                 if (connector != sensorData->end())
3718e94c204SJames Feist                 {
3728e94c204SJames Feist                     auto findPwm = connector->second.find("Pwm");
37349a8ccd6SJames Feist                     if (findPwm != connector->second.end())
3748e94c204SJames Feist                     {
37549a8ccd6SJames Feist 
376de5e9705SJames Feist                         size_t pwm = std::visit(VariantToUnsignedIntVisitor(),
377de5e9705SJames Feist                                                 findPwm->second);
378d05867c0SZhikui Ren                         pwmPath = directory / ("pwm" + std::to_string(pwm + 1));
37949a8ccd6SJames Feist                         /* use pwm name override if found in configuration else
38049a8ccd6SJames Feist                          * use default */
381d320a2e1SJason Ling                         auto findOverride = connector->second.find("PwmName");
382d320a2e1SJason Ling                         if (findOverride != connector->second.end())
383d320a2e1SJason Ling                         {
384d320a2e1SJason Ling                             pwmName = std::visit(VariantToStringVisitor(),
385d320a2e1SJason Ling                                                  findOverride->second);
386d320a2e1SJason Ling                         }
387d320a2e1SJason Ling                         else
388d320a2e1SJason Ling                         {
389d320a2e1SJason Ling                             pwmName = "Pwm_" + std::to_string(pwm + 1);
390d320a2e1SJason Ling                         }
3918e94c204SJames Feist                     }
39249a8ccd6SJames Feist                     else
39349a8ccd6SJames Feist                     {
39449a8ccd6SJames Feist                         std::cerr << "Connector for " << sensorName
39549a8ccd6SJames Feist                                   << " missing pwm!\n";
39649a8ccd6SJames Feist                     }
39749a8ccd6SJames Feist 
39849a8ccd6SJames Feist                     auto findLED = connector->second.find("LED");
39949a8ccd6SJames Feist                     if (findLED != connector->second.end())
40049a8ccd6SJames Feist                     {
40149a8ccd6SJames Feist                         auto ledName =
40249a8ccd6SJames Feist                             std::get_if<std::string>(&(findLED->second));
40349a8ccd6SJames Feist                         if (ledName == nullptr)
40449a8ccd6SJames Feist                         {
40549a8ccd6SJames Feist                             std::cerr << "Wrong format for LED of "
40649a8ccd6SJames Feist                                       << sensorName << "\n";
40749a8ccd6SJames Feist                         }
40849a8ccd6SJames Feist                         else
40949a8ccd6SJames Feist                         {
41049a8ccd6SJames Feist                             led = *ledName;
41149a8ccd6SJames Feist                         }
41249a8ccd6SJames Feist                     }
41349a8ccd6SJames Feist                 }
41449a8ccd6SJames Feist 
41549a8ccd6SJames Feist                 findLimits(limits, baseConfiguration);
41649a8ccd6SJames Feist                 tachSensors[sensorName] = std::make_unique<TachSensor>(
41749a8ccd6SJames Feist                     path.string(), baseType, objectServer, dbusConnection,
41849a8ccd6SJames Feist                     std::move(presenceSensor), redundancy, io, sensorName,
41949a8ccd6SJames Feist                     std::move(sensorThresholds), *interfacePath, limits,
42049a8ccd6SJames Feist                     powerState, led);
42177b3add2SYong Zhao 
422d05867c0SZhikui Ren                 if (!pwmPath.empty() && fs::exists(pwmPath) &&
423d05867c0SZhikui Ren                     !pwmSensors.count(pwmPath))
42477b3add2SYong Zhao                 {
42577b3add2SYong Zhao                     pwmSensors[pwmPath] = std::make_unique<PwmSensor>(
42677b3add2SYong Zhao                         pwmName, pwmPath, dbusConnection, objectServer,
42777b3add2SYong Zhao                         *interfacePath, "Fan");
4286714a25aSJames Feist                 }
42977b3add2SYong Zhao             }
43077b3add2SYong Zhao 
431d540741eSKuiying Wang             createRedundancySensor(tachSensors, dbusConnection, objectServer);
432de5e9705SJames Feist         }));
433de5e9705SJames Feist     getter->getConfiguration(
434f27a55c7SJames Feist         std::vector<std::string>{sensorTypes.begin(), sensorTypes.end()},
435f27a55c7SJames Feist         retries);
4366714a25aSJames Feist }
4376714a25aSJames Feist 
438b6c0b914SJames Feist int main()
4396714a25aSJames Feist {
4406714a25aSJames Feist     boost::asio::io_service io;
4416714a25aSJames Feist     auto systemBus = std::make_shared<sdbusplus::asio::connection>(io);
4426714a25aSJames Feist     systemBus->request_name("xyz.openbmc_project.FanSensor");
4436714a25aSJames Feist     sdbusplus::asio::object_server objectServer(systemBus);
4446714a25aSJames Feist     boost::container::flat_map<std::string, std::unique_ptr<TachSensor>>
4456714a25aSJames Feist         tachSensors;
4466714a25aSJames Feist     boost::container::flat_map<std::string, std::unique_ptr<PwmSensor>>
4476714a25aSJames Feist         pwmSensors;
4486714a25aSJames Feist     std::vector<std::unique_ptr<sdbusplus::bus::match::match>> matches;
4495591cf08SJames Feist     auto sensorsChanged =
4505591cf08SJames Feist         std::make_shared<boost::container::flat_set<std::string>>();
4516714a25aSJames Feist 
4526714a25aSJames Feist     io.post([&]() {
4536714a25aSJames Feist         createSensors(io, objectServer, tachSensors, pwmSensors, systemBus,
4546714a25aSJames Feist                       nullptr);
4556714a25aSJames Feist     });
4566714a25aSJames Feist 
4576714a25aSJames Feist     boost::asio::deadline_timer filterTimer(io);
4586714a25aSJames Feist     std::function<void(sdbusplus::message::message&)> eventHandler =
4596714a25aSJames Feist         [&](sdbusplus::message::message& message) {
4606714a25aSJames Feist             if (message.is_method_error())
4616714a25aSJames Feist             {
4626714a25aSJames Feist                 std::cerr << "callback method error\n";
4636714a25aSJames Feist                 return;
4646714a25aSJames Feist             }
4656714a25aSJames Feist             sensorsChanged->insert(message.get_path());
4666714a25aSJames Feist             // this implicitly cancels the timer
4676714a25aSJames Feist             filterTimer.expires_from_now(boost::posix_time::seconds(1));
4686714a25aSJames Feist 
4696714a25aSJames Feist             filterTimer.async_wait([&](const boost::system::error_code& ec) {
4706714a25aSJames Feist                 if (ec == boost::asio::error::operation_aborted)
4716714a25aSJames Feist                 {
4726714a25aSJames Feist                     /* we were canceled*/
4736714a25aSJames Feist                     return;
4746714a25aSJames Feist                 }
4758a57ec09SEd Tanous                 if (ec)
4766714a25aSJames Feist                 {
4776714a25aSJames Feist                     std::cerr << "timer error\n";
4786714a25aSJames Feist                     return;
4796714a25aSJames Feist                 }
4806714a25aSJames Feist                 createSensors(io, objectServer, tachSensors, pwmSensors,
481f27a55c7SJames Feist                               systemBus, sensorsChanged, 5);
4826714a25aSJames Feist             });
4836714a25aSJames Feist         };
4846714a25aSJames Feist 
4859ced0a38SJae Hyun Yoo     for (const char* type : sensorTypes)
4866714a25aSJames Feist     {
4876714a25aSJames Feist         auto match = std::make_unique<sdbusplus::bus::match::match>(
4886714a25aSJames Feist             static_cast<sdbusplus::bus::bus&>(*systemBus),
4896714a25aSJames Feist             "type='signal',member='PropertiesChanged',path_namespace='" +
4909ced0a38SJae Hyun Yoo                 std::string(inventoryPath) + "',arg0namespace='" + type + "'",
4916714a25aSJames Feist             eventHandler);
4926714a25aSJames Feist         matches.emplace_back(std::move(match));
4936714a25aSJames Feist     }
4946714a25aSJames Feist 
495dc6c55f3SJames Feist     // redundancy sensor
496dc6c55f3SJames Feist     std::function<void(sdbusplus::message::message&)> redundancyHandler =
497dc6c55f3SJames Feist         [&tachSensors, &systemBus,
498b6c0b914SJames Feist          &objectServer](sdbusplus::message::message&) {
499dc6c55f3SJames Feist             createRedundancySensor(tachSensors, systemBus, objectServer);
500dc6c55f3SJames Feist         };
501dc6c55f3SJames Feist     auto match = std::make_unique<sdbusplus::bus::match::match>(
502dc6c55f3SJames Feist         static_cast<sdbusplus::bus::bus&>(*systemBus),
503dc6c55f3SJames Feist         "type='signal',member='PropertiesChanged',path_namespace='" +
504dc6c55f3SJames Feist             std::string(inventoryPath) + "',arg0namespace='" +
505dc6c55f3SJames Feist             redundancyConfiguration + "'",
506b6c0b914SJames Feist         std::move(redundancyHandler));
507dc6c55f3SJames Feist     matches.emplace_back(std::move(match));
508dc6c55f3SJames Feist 
5096714a25aSJames Feist     io.run();
5106714a25aSJames Feist }
511