xref: /openbmc/dbus-sensors/src/FanMain.cpp (revision 8685b17a)
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 }
86abf91de1SJeff Lin void enablePwm(const fs::path& filePath)
87abf91de1SJeff Lin {
88abf91de1SJeff Lin     std::fstream enableFile(filePath, std::ios::in | std::ios::out);
89abf91de1SJeff Lin     if (!enableFile.good())
90abf91de1SJeff Lin     {
91abf91de1SJeff Lin         std::cerr << "Error read/write " << filePath << "\n";
92abf91de1SJeff Lin         return;
93abf91de1SJeff Lin     }
94dc6c55f3SJames Feist 
95abf91de1SJeff Lin     std::string regulateMode;
96abf91de1SJeff Lin     std::getline(enableFile, regulateMode);
97abf91de1SJeff Lin     if (regulateMode == "0")
98abf91de1SJeff Lin     {
99abf91de1SJeff Lin         enableFile << 1;
100abf91de1SJeff Lin     }
101abf91de1SJeff Lin }
102d540741eSKuiying Wang void createRedundancySensor(
103d540741eSKuiying Wang     const boost::container::flat_map<std::string, std::unique_ptr<TachSensor>>&
104d540741eSKuiying Wang         sensors,
1058a57ec09SEd Tanous     const std::shared_ptr<sdbusplus::asio::connection>& conn,
106d540741eSKuiying Wang     sdbusplus::asio::object_server& objectServer)
107d540741eSKuiying Wang {
108d540741eSKuiying Wang 
109d540741eSKuiying Wang     conn->async_method_call(
110d540741eSKuiying Wang         [&objectServer, &sensors](boost::system::error_code& ec,
1118a57ec09SEd Tanous                                   const ManagedObjectType& managedObj) {
112d540741eSKuiying Wang             if (ec)
113d540741eSKuiying Wang             {
114d540741eSKuiying Wang                 std::cerr << "Error calling entity manager \n";
115d540741eSKuiying Wang                 return;
116d540741eSKuiying Wang             }
117d540741eSKuiying Wang             for (const auto& pathPair : managedObj)
118d540741eSKuiying Wang             {
119d540741eSKuiying Wang                 for (const auto& interfacePair : pathPair.second)
120d540741eSKuiying Wang                 {
121d540741eSKuiying Wang                     if (interfacePair.first == redundancyConfiguration)
122d540741eSKuiying Wang                     {
123d540741eSKuiying Wang                         // currently only support one
124d540741eSKuiying Wang                         auto findCount =
125d540741eSKuiying Wang                             interfacePair.second.find("AllowedFailures");
126d540741eSKuiying Wang                         if (findCount == interfacePair.second.end())
127d540741eSKuiying Wang                         {
128d540741eSKuiying Wang                             std::cerr << "Malformed redundancy record \n";
129d540741eSKuiying Wang                             return;
130d540741eSKuiying Wang                         }
131d540741eSKuiying Wang                         std::vector<std::string> sensorList;
132d540741eSKuiying Wang 
133d540741eSKuiying Wang                         for (const auto& sensor : sensors)
134d540741eSKuiying Wang                         {
135d540741eSKuiying Wang                             sensorList.push_back(
136d540741eSKuiying Wang                                 "/xyz/openbmc_project/sensors/fan_tach/" +
137d540741eSKuiying Wang                                 sensor.second->name);
138d540741eSKuiying Wang                         }
139d540741eSKuiying Wang                         systemRedundancy.reset();
140d540741eSKuiying Wang                         systemRedundancy.emplace(RedundancySensor(
141d540741eSKuiying Wang                             std::get<uint64_t>(findCount->second), sensorList,
142d540741eSKuiying Wang                             objectServer, pathPair.first));
143d540741eSKuiying Wang 
144d540741eSKuiying Wang                         return;
145d540741eSKuiying Wang                     }
146d540741eSKuiying Wang                 }
147d540741eSKuiying Wang             }
148d540741eSKuiying Wang         },
149d540741eSKuiying Wang         "xyz.openbmc_project.EntityManager", "/",
150d540741eSKuiying Wang         "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
151d540741eSKuiying Wang }
152d540741eSKuiying Wang 
1536714a25aSJames Feist void createSensors(
1546714a25aSJames Feist     boost::asio::io_service& io, sdbusplus::asio::object_server& objectServer,
1556714a25aSJames Feist     boost::container::flat_map<std::string, std::unique_ptr<TachSensor>>&
1566714a25aSJames Feist         tachSensors,
1576714a25aSJames Feist     boost::container::flat_map<std::string, std::unique_ptr<PwmSensor>>&
1586714a25aSJames Feist         pwmSensors,
1596714a25aSJames Feist     std::shared_ptr<sdbusplus::asio::connection>& dbusConnection,
1605591cf08SJames Feist     const std::shared_ptr<boost::container::flat_set<std::string>>&
161f27a55c7SJames Feist         sensorsChanged,
162f27a55c7SJames Feist     size_t retries = 0)
1636714a25aSJames Feist {
164de5e9705SJames Feist     auto getter = std::make_shared<GetSensorConfiguration>(
165de5e9705SJames Feist         dbusConnection,
166de5e9705SJames Feist         std::move([&io, &objectServer, &tachSensors, &pwmSensors,
1675591cf08SJames Feist                    &dbusConnection, sensorsChanged](
168de5e9705SJames Feist                       const ManagedObjectType& sensorConfigurations) {
1696714a25aSJames Feist             bool firstScan = sensorsChanged == nullptr;
1706714a25aSJames Feist             std::vector<fs::path> paths;
171de5e9705SJames Feist             if (!findFiles(fs::path("/sys/class/hwmon"), R"(fan\d+_input)",
172de5e9705SJames Feist                            paths))
1736714a25aSJames Feist             {
17477b3add2SYong Zhao                 std::cerr << "No fan sensors in system\n";
1756714a25aSJames Feist                 return;
1766714a25aSJames Feist             }
1776714a25aSJames Feist 
1786714a25aSJames Feist             // iterate through all found fan sensors, and try to match them with
1796714a25aSJames Feist             // configuration
18095b079b7SJames Feist             for (const auto& path : paths)
1816714a25aSJames Feist             {
1826714a25aSJames Feist                 std::smatch match;
1836714a25aSJames Feist                 std::string pathStr = path.string();
1846714a25aSJames Feist 
1859ced0a38SJae Hyun Yoo                 std::regex_search(pathStr, match, inputRegex);
1866714a25aSJames Feist                 std::string indexStr = *(match.begin() + 1);
1876714a25aSJames Feist 
18877b3add2SYong Zhao                 fs::path directory = path.parent_path();
18995b079b7SJames Feist                 FanTypes fanType = getFanType(directory);
19077b3add2SYong Zhao 
1916714a25aSJames Feist                 // convert to 0 based
1926714a25aSJames Feist                 size_t index = std::stoul(indexStr) - 1;
1936714a25aSJames Feist 
1946714a25aSJames Feist                 const char* baseType;
1956714a25aSJames Feist                 const SensorData* sensorData = nullptr;
1966714a25aSJames Feist                 const std::string* interfacePath = nullptr;
19787d713abSJames Feist                 const SensorBaseConfiguration* baseConfiguration = nullptr;
198de5e9705SJames Feist                 for (const std::pair<sdbusplus::message::object_path,
199de5e9705SJames Feist                                      SensorData>& sensor : sensorConfigurations)
2006714a25aSJames Feist                 {
201de5e9705SJames Feist                     // find the base of the configuration to see if indexes
202de5e9705SJames Feist                     // match
203a3e8f2a3SYong Zhao                     auto sensorBaseFind =
204a3e8f2a3SYong Zhao                         sensor.second.find(sensorTypes[fanType]);
205a3e8f2a3SYong Zhao                     if (sensorBaseFind == sensor.second.end())
2066714a25aSJames Feist                     {
2076714a25aSJames Feist                         continue;
2086714a25aSJames Feist                     }
209347dd4e7SZhikui Ren 
210a3e8f2a3SYong Zhao                     baseConfiguration = &(*sensorBaseFind);
211a3e8f2a3SYong Zhao                     interfacePath = &(sensor.first.str);
212a3e8f2a3SYong Zhao                     baseType = sensorTypes[fanType];
213a3e8f2a3SYong Zhao 
2146714a25aSJames Feist                     auto findIndex = baseConfiguration->second.find("Index");
2156714a25aSJames Feist                     if (findIndex == baseConfiguration->second.end())
2166714a25aSJames Feist                     {
217de5e9705SJames Feist                         std::cerr << baseConfiguration->first
218de5e9705SJames Feist                                   << " missing index\n";
2196714a25aSJames Feist                         continue;
2206714a25aSJames Feist                     }
221de5e9705SJames Feist                     unsigned int configIndex = std::visit(
222de5e9705SJames Feist                         VariantToUnsignedIntVisitor(), findIndex->second);
2236714a25aSJames Feist                     if (configIndex != index)
2246714a25aSJames Feist                     {
2256714a25aSJames Feist                         continue;
2266714a25aSJames Feist                     }
227de5e9705SJames Feist                     if (fanType == FanTypes::aspeed ||
228de5e9705SJames Feist                         fanType == FanTypes::nuvoton)
2296714a25aSJames Feist                     {
230de5e9705SJames Feist                         // there will be only 1 aspeed or nuvoton sensor object
231de5e9705SJames Feist                         // in sysfs, we found the fan
23295b079b7SJames Feist                         sensorData = &(sensor.second);
23395b079b7SJames Feist                         break;
23495b079b7SJames Feist                     }
2358a57ec09SEd Tanous                     if (fanType == FanTypes::i2c)
23695b079b7SJames Feist                     {
237add46820SYong Zhao                         size_t bus = 0;
238add46820SYong Zhao                         size_t address = 0;
239add46820SYong Zhao 
240add46820SYong Zhao                         std::string link =
241add46820SYong Zhao                             fs::read_symlink(directory / "device").filename();
242add46820SYong Zhao 
243add46820SYong Zhao                         size_t findDash = link.find('-');
244add46820SYong Zhao                         if (findDash == std::string::npos ||
245add46820SYong Zhao                             link.size() <= findDash + 1)
246add46820SYong Zhao                         {
247add46820SYong Zhao                             std::cerr << "Error finding device from symlink";
248add46820SYong Zhao                         }
249add46820SYong Zhao                         bus = std::stoi(link.substr(0, findDash));
250add46820SYong Zhao                         address =
251add46820SYong Zhao                             std::stoi(link.substr(findDash + 1), nullptr, 16);
252add46820SYong Zhao 
25395b079b7SJames Feist                         auto findBus = baseConfiguration->second.find("Bus");
254de5e9705SJames Feist                         auto findAddress =
255de5e9705SJames Feist                             baseConfiguration->second.find("Address");
25695b079b7SJames Feist                         if (findBus == baseConfiguration->second.end() ||
25795b079b7SJames Feist                             findAddress == baseConfiguration->second.end())
25895b079b7SJames Feist                         {
25995b079b7SJames Feist                             std::cerr << baseConfiguration->first
26095b079b7SJames Feist                                       << " missing bus or address\n";
2616714a25aSJames Feist                             continue;
2626714a25aSJames Feist                         }
263de5e9705SJames Feist                         unsigned int configBus = std::visit(
264de5e9705SJames Feist                             VariantToUnsignedIntVisitor(), findBus->second);
2653eb82629SJames Feist                         unsigned int configAddress = std::visit(
26695b079b7SJames Feist                             VariantToUnsignedIntVisitor(), findAddress->second);
26795b079b7SJames Feist 
26884e9e662SJae Hyun Yoo                         if (configBus == bus && configAddress == address)
2696714a25aSJames Feist                         {
2706714a25aSJames Feist                             sensorData = &(sensor.second);
2716714a25aSJames Feist                             break;
2726714a25aSJames Feist                         }
2736714a25aSJames Feist                     }
27495b079b7SJames Feist                 }
2756714a25aSJames Feist                 if (sensorData == nullptr)
2766714a25aSJames Feist                 {
277de5e9705SJames Feist                     std::cerr << "failed to find match for " << path.string()
278de5e9705SJames Feist                               << "\n";
2796714a25aSJames Feist                     continue;
2806714a25aSJames Feist                 }
2816714a25aSJames Feist 
2826714a25aSJames Feist                 auto findSensorName = baseConfiguration->second.find("Name");
283347dd4e7SZhikui Ren 
2846714a25aSJames Feist                 if (findSensorName == baseConfiguration->second.end())
2856714a25aSJames Feist                 {
2866714a25aSJames Feist                     std::cerr << "could not determine configuration name for "
2876714a25aSJames Feist                               << path.string() << "\n";
2886714a25aSJames Feist                     continue;
2896714a25aSJames Feist                 }
290de5e9705SJames Feist                 std::string sensorName =
291de5e9705SJames Feist                     std::get<std::string>(findSensorName->second);
292347dd4e7SZhikui Ren 
2936714a25aSJames Feist                 // on rescans, only update sensors we were signaled by
2946714a25aSJames Feist                 auto findSensor = tachSensors.find(sensorName);
2956714a25aSJames Feist                 if (!firstScan && findSensor != tachSensors.end())
2966714a25aSJames Feist                 {
2976714a25aSJames Feist                     bool found = false;
298de5e9705SJames Feist                     for (auto it = sensorsChanged->begin();
299de5e9705SJames Feist                          it != sensorsChanged->end(); it++)
3006714a25aSJames Feist                     {
3016714a25aSJames Feist                         if (boost::ends_with(*it, findSensor->second->name))
3026714a25aSJames Feist                         {
3036714a25aSJames Feist                             sensorsChanged->erase(it);
3046714a25aSJames Feist                             findSensor->second = nullptr;
3056714a25aSJames Feist                             found = true;
3066714a25aSJames Feist                             break;
3076714a25aSJames Feist                         }
3086714a25aSJames Feist                     }
3096714a25aSJames Feist                     if (!found)
3106714a25aSJames Feist                     {
3116714a25aSJames Feist                         continue;
3126714a25aSJames Feist                     }
3136714a25aSJames Feist                 }
3146714a25aSJames Feist                 std::vector<thresholds::Threshold> sensorThresholds;
3159ced0a38SJae Hyun Yoo                 if (!parseThresholdsFromConfig(*sensorData, sensorThresholds))
3166714a25aSJames Feist                 {
317de5e9705SJames Feist                     std::cerr << "error populating thresholds for "
318de5e9705SJames Feist                               << sensorName << "\n";
3196714a25aSJames Feist                 }
3206714a25aSJames Feist 
3217bc2bab2SJames Feist                 auto presenceConfig =
3227bc2bab2SJames Feist                     sensorData->find(baseType + std::string(".Presence"));
3237bc2bab2SJames Feist 
3247bc2bab2SJames Feist                 std::unique_ptr<PresenceSensor> presenceSensor(nullptr);
3257bc2bab2SJames Feist 
3267bc2bab2SJames Feist                 // presence sensors are optional
3277bc2bab2SJames Feist                 if (presenceConfig != sensorData->end())
3287bc2bab2SJames Feist                 {
3297bc2bab2SJames Feist                     auto findPolarity = presenceConfig->second.find("Polarity");
330347dd4e7SZhikui Ren                     auto findPinName = presenceConfig->second.find("PinName");
3317bc2bab2SJames Feist 
332347dd4e7SZhikui Ren                     if (findPinName == presenceConfig->second.end() ||
3337bc2bab2SJames Feist                         findPolarity == presenceConfig->second.end())
3347bc2bab2SJames Feist                     {
3357bc2bab2SJames Feist                         std::cerr << "Malformed Presence Configuration\n";
3367bc2bab2SJames Feist                     }
3377bc2bab2SJames Feist                     else
3387bc2bab2SJames Feist                     {
339de5e9705SJames Feist                         bool inverted = std::get<std::string>(
340de5e9705SJames Feist                                             findPolarity->second) == "Low";
341347dd4e7SZhikui Ren                         if (auto pinName =
342347dd4e7SZhikui Ren                                 std::get_if<std::string>(&findPinName->second))
343347dd4e7SZhikui Ren                         {
3447b18b1e0SJames Feist                             presenceSensor = std::make_unique<PresenceSensor>(
345347dd4e7SZhikui Ren                                 *pinName, inverted, io, sensorName);
346347dd4e7SZhikui Ren                         }
347347dd4e7SZhikui Ren                         else
348347dd4e7SZhikui Ren                         {
349347dd4e7SZhikui Ren                             std::cerr
350347dd4e7SZhikui Ren                                 << "Malformed Presence pinName for sensor "
351347dd4e7SZhikui Ren                                 << sensorName << " \n";
352347dd4e7SZhikui Ren                         }
3537bc2bab2SJames Feist                     }
3547bc2bab2SJames Feist                 }
3557b18b1e0SJames Feist                 std::optional<RedundancySensor>* redundancy = nullptr;
35695b079b7SJames Feist                 if (fanType == FanTypes::aspeed)
35795b079b7SJames Feist                 {
3587b18b1e0SJames Feist                     redundancy = &systemRedundancy;
35995b079b7SJames Feist                 }
3607bc2bab2SJames Feist 
361f920e09cSJosh Lehan                 PowerState powerState = PowerState::on;
362f920e09cSJosh Lehan                 auto findPower = baseConfiguration->second.find("PowerState");
363f920e09cSJosh Lehan                 if (findPower != baseConfiguration->second.end())
364f920e09cSJosh Lehan                 {
365f920e09cSJosh Lehan                     auto ptrPower =
366f920e09cSJosh Lehan                         std::get_if<std::string>(&(findPower->second));
367f920e09cSJosh Lehan                     if (ptrPower)
368f920e09cSJosh Lehan                     {
369f920e09cSJosh Lehan                         setReadState(*ptrPower, powerState);
370f920e09cSJosh Lehan                     }
371f920e09cSJosh Lehan                 }
372f920e09cSJosh Lehan 
37387d713abSJames Feist                 constexpr double defaultMaxReading = 25000;
37487d713abSJames Feist                 constexpr double defaultMinReading = 0;
375de5e9705SJames Feist                 auto limits =
376de5e9705SJames Feist                     std::make_pair(defaultMinReading, defaultMaxReading);
37787d713abSJames Feist 
378de5e9705SJames Feist                 auto connector =
379de5e9705SJames Feist                     sensorData->find(baseType + std::string(".Connector"));
38049a8ccd6SJames Feist 
38149a8ccd6SJames Feist                 std::optional<std::string> led;
38277b3add2SYong Zhao                 std::string pwmName;
383d05867c0SZhikui Ren                 fs::path pwmPath;
38449a8ccd6SJames Feist 
3858e94c204SJames Feist                 if (connector != sensorData->end())
3868e94c204SJames Feist                 {
3878e94c204SJames Feist                     auto findPwm = connector->second.find("Pwm");
38849a8ccd6SJames Feist                     if (findPwm != connector->second.end())
3898e94c204SJames Feist                     {
390abf91de1SJeff Lin                         fs::path pwmEnableFile =
391abf91de1SJeff Lin                             "pwm" + std::to_string(index + 1) + "_enable";
392abf91de1SJeff Lin                         fs::path enablePath =
393abf91de1SJeff Lin                             path.parent_path() / pwmEnableFile;
394abf91de1SJeff Lin                         enablePwm(enablePath);
395de5e9705SJames Feist                         size_t pwm = std::visit(VariantToUnsignedIntVisitor(),
396de5e9705SJames Feist                                                 findPwm->second);
397d05867c0SZhikui Ren                         pwmPath = directory / ("pwm" + std::to_string(pwm + 1));
39849a8ccd6SJames Feist                         /* use pwm name override if found in configuration else
39949a8ccd6SJames Feist                          * use default */
400d320a2e1SJason Ling                         auto findOverride = connector->second.find("PwmName");
401d320a2e1SJason Ling                         if (findOverride != connector->second.end())
402d320a2e1SJason Ling                         {
403d320a2e1SJason Ling                             pwmName = std::visit(VariantToStringVisitor(),
404d320a2e1SJason Ling                                                  findOverride->second);
405d320a2e1SJason Ling                         }
406d320a2e1SJason Ling                         else
407d320a2e1SJason Ling                         {
408d320a2e1SJason Ling                             pwmName = "Pwm_" + std::to_string(pwm + 1);
409d320a2e1SJason Ling                         }
4108e94c204SJames Feist                     }
41149a8ccd6SJames Feist                     else
41249a8ccd6SJames Feist                     {
41349a8ccd6SJames Feist                         std::cerr << "Connector for " << sensorName
41449a8ccd6SJames Feist                                   << " missing pwm!\n";
41549a8ccd6SJames Feist                     }
41649a8ccd6SJames Feist 
41749a8ccd6SJames Feist                     auto findLED = connector->second.find("LED");
41849a8ccd6SJames Feist                     if (findLED != connector->second.end())
41949a8ccd6SJames Feist                     {
42049a8ccd6SJames Feist                         auto ledName =
42149a8ccd6SJames Feist                             std::get_if<std::string>(&(findLED->second));
42249a8ccd6SJames Feist                         if (ledName == nullptr)
42349a8ccd6SJames Feist                         {
42449a8ccd6SJames Feist                             std::cerr << "Wrong format for LED of "
42549a8ccd6SJames Feist                                       << sensorName << "\n";
42649a8ccd6SJames Feist                         }
42749a8ccd6SJames Feist                         else
42849a8ccd6SJames Feist                         {
42949a8ccd6SJames Feist                             led = *ledName;
43049a8ccd6SJames Feist                         }
43149a8ccd6SJames Feist                     }
43249a8ccd6SJames Feist                 }
43349a8ccd6SJames Feist 
43449a8ccd6SJames Feist                 findLimits(limits, baseConfiguration);
43549a8ccd6SJames Feist                 tachSensors[sensorName] = std::make_unique<TachSensor>(
43649a8ccd6SJames Feist                     path.string(), baseType, objectServer, dbusConnection,
43749a8ccd6SJames Feist                     std::move(presenceSensor), redundancy, io, sensorName,
43849a8ccd6SJames Feist                     std::move(sensorThresholds), *interfacePath, limits,
43949a8ccd6SJames Feist                     powerState, led);
44077b3add2SYong Zhao 
441d05867c0SZhikui Ren                 if (!pwmPath.empty() && fs::exists(pwmPath) &&
442d05867c0SZhikui Ren                     !pwmSensors.count(pwmPath))
44377b3add2SYong Zhao                 {
44477b3add2SYong Zhao                     pwmSensors[pwmPath] = std::make_unique<PwmSensor>(
44577b3add2SYong Zhao                         pwmName, pwmPath, dbusConnection, objectServer,
44677b3add2SYong Zhao                         *interfacePath, "Fan");
4476714a25aSJames Feist                 }
44877b3add2SYong Zhao             }
44977b3add2SYong Zhao 
450d540741eSKuiying Wang             createRedundancySensor(tachSensors, dbusConnection, objectServer);
451de5e9705SJames Feist         }));
452de5e9705SJames Feist     getter->getConfiguration(
453f27a55c7SJames Feist         std::vector<std::string>{sensorTypes.begin(), sensorTypes.end()},
454f27a55c7SJames Feist         retries);
4556714a25aSJames Feist }
4566714a25aSJames Feist 
457b6c0b914SJames Feist int main()
4586714a25aSJames Feist {
4596714a25aSJames Feist     boost::asio::io_service io;
4606714a25aSJames Feist     auto systemBus = std::make_shared<sdbusplus::asio::connection>(io);
4616714a25aSJames Feist     systemBus->request_name("xyz.openbmc_project.FanSensor");
4626714a25aSJames Feist     sdbusplus::asio::object_server objectServer(systemBus);
4636714a25aSJames Feist     boost::container::flat_map<std::string, std::unique_ptr<TachSensor>>
4646714a25aSJames Feist         tachSensors;
4656714a25aSJames Feist     boost::container::flat_map<std::string, std::unique_ptr<PwmSensor>>
4666714a25aSJames Feist         pwmSensors;
4676714a25aSJames Feist     std::vector<std::unique_ptr<sdbusplus::bus::match::match>> matches;
4685591cf08SJames Feist     auto sensorsChanged =
4695591cf08SJames Feist         std::make_shared<boost::container::flat_set<std::string>>();
4706714a25aSJames Feist 
4716714a25aSJames Feist     io.post([&]() {
4726714a25aSJames Feist         createSensors(io, objectServer, tachSensors, pwmSensors, systemBus,
4736714a25aSJames Feist                       nullptr);
4746714a25aSJames Feist     });
4756714a25aSJames Feist 
4766714a25aSJames Feist     boost::asio::deadline_timer filterTimer(io);
4776714a25aSJames Feist     std::function<void(sdbusplus::message::message&)> eventHandler =
4786714a25aSJames Feist         [&](sdbusplus::message::message& message) {
4796714a25aSJames Feist             if (message.is_method_error())
4806714a25aSJames Feist             {
4816714a25aSJames Feist                 std::cerr << "callback method error\n";
4826714a25aSJames Feist                 return;
4836714a25aSJames Feist             }
4846714a25aSJames Feist             sensorsChanged->insert(message.get_path());
4856714a25aSJames Feist             // this implicitly cancels the timer
4866714a25aSJames Feist             filterTimer.expires_from_now(boost::posix_time::seconds(1));
4876714a25aSJames Feist 
4886714a25aSJames Feist             filterTimer.async_wait([&](const boost::system::error_code& ec) {
4896714a25aSJames Feist                 if (ec == boost::asio::error::operation_aborted)
4906714a25aSJames Feist                 {
4916714a25aSJames Feist                     /* we were canceled*/
4926714a25aSJames Feist                     return;
4936714a25aSJames Feist                 }
4948a57ec09SEd Tanous                 if (ec)
4956714a25aSJames Feist                 {
4966714a25aSJames Feist                     std::cerr << "timer error\n";
4976714a25aSJames Feist                     return;
4986714a25aSJames Feist                 }
4996714a25aSJames Feist                 createSensors(io, objectServer, tachSensors, pwmSensors,
500f27a55c7SJames Feist                               systemBus, sensorsChanged, 5);
5016714a25aSJames Feist             });
5026714a25aSJames Feist         };
5036714a25aSJames Feist 
5049ced0a38SJae Hyun Yoo     for (const char* type : sensorTypes)
5056714a25aSJames Feist     {
5066714a25aSJames Feist         auto match = std::make_unique<sdbusplus::bus::match::match>(
5076714a25aSJames Feist             static_cast<sdbusplus::bus::bus&>(*systemBus),
5086714a25aSJames Feist             "type='signal',member='PropertiesChanged',path_namespace='" +
5099ced0a38SJae Hyun Yoo                 std::string(inventoryPath) + "',arg0namespace='" + type + "'",
5106714a25aSJames Feist             eventHandler);
5116714a25aSJames Feist         matches.emplace_back(std::move(match));
5126714a25aSJames Feist     }
5136714a25aSJames Feist 
514dc6c55f3SJames Feist     // redundancy sensor
515dc6c55f3SJames Feist     std::function<void(sdbusplus::message::message&)> redundancyHandler =
516dc6c55f3SJames Feist         [&tachSensors, &systemBus,
517b6c0b914SJames Feist          &objectServer](sdbusplus::message::message&) {
518dc6c55f3SJames Feist             createRedundancySensor(tachSensors, systemBus, objectServer);
519dc6c55f3SJames Feist         };
520dc6c55f3SJames Feist     auto match = std::make_unique<sdbusplus::bus::match::match>(
521dc6c55f3SJames Feist         static_cast<sdbusplus::bus::bus&>(*systemBus),
522dc6c55f3SJames Feist         "type='signal',member='PropertiesChanged',path_namespace='" +
523dc6c55f3SJames Feist             std::string(inventoryPath) + "',arg0namespace='" +
524dc6c55f3SJames Feist             redundancyConfiguration + "'",
525b6c0b914SJames Feist         std::move(redundancyHandler));
526dc6c55f3SJames Feist     matches.emplace_back(std::move(match));
527dc6c55f3SJames Feist 
5281263c3daSBruce Lee     setupManufacturingModeMatch(*systemBus);
5296714a25aSJames Feist     io.run();
530*8685b17aSZhikui Ren     return 0;
5316714a25aSJames Feist }
532