xref: /openbmc/phosphor-fan-presence/control/json/manager.cpp (revision 2a9e7b2ef17b3d302a2c52daf2c081c3108ff0eb)
1a227a16dSMatthew Barth /**
2a227a16dSMatthew Barth  * Copyright © 2020 IBM Corporation
3a227a16dSMatthew Barth  *
4a227a16dSMatthew Barth  * Licensed under the Apache License, Version 2.0 (the "License");
5a227a16dSMatthew Barth  * you may not use this file except in compliance with the License.
6a227a16dSMatthew Barth  * You may obtain a copy of the License at
7a227a16dSMatthew Barth  *
8a227a16dSMatthew Barth  *     http://www.apache.org/licenses/LICENSE-2.0
9a227a16dSMatthew Barth  *
10a227a16dSMatthew Barth  * Unless required by applicable law or agreed to in writing, software
11a227a16dSMatthew Barth  * distributed under the License is distributed on an "AS IS" BASIS,
12a227a16dSMatthew Barth  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13a227a16dSMatthew Barth  * See the License for the specific language governing permissions and
14a227a16dSMatthew Barth  * limitations under the License.
15a227a16dSMatthew Barth  */
16b584d818SMatthew Barth #include "config.h"
17b584d818SMatthew Barth 
18a227a16dSMatthew Barth #include "manager.hpp"
19a227a16dSMatthew Barth 
20d9cb63b6SMatthew Barth #include "action.hpp"
2144ab7693SMatthew Barth #include "event.hpp"
22de90fb4dSMatthew Barth #include "fan.hpp"
23d9cb63b6SMatthew Barth #include "group.hpp"
24a227a16dSMatthew Barth #include "json_config.hpp"
2506764946SMatthew Barth #include "profile.hpp"
269403a217SMatthew Barth #include "sdbusplus.hpp"
27acd737cdSMatthew Barth #include "zone.hpp"
28a227a16dSMatthew Barth 
29acd737cdSMatthew Barth #include <nlohmann/json.hpp>
30a227a16dSMatthew Barth #include <sdbusplus/bus.hpp>
31acd737cdSMatthew Barth #include <sdeventplus/event.hpp>
32d9cb63b6SMatthew Barth #include <sdeventplus/utility/timer.hpp>
33a227a16dSMatthew Barth 
34de90fb4dSMatthew Barth #include <algorithm>
35d9cb63b6SMatthew Barth #include <chrono>
36a227a16dSMatthew Barth #include <filesystem>
37d9cb63b6SMatthew Barth #include <functional>
38d9cb63b6SMatthew Barth #include <map>
39d9cb63b6SMatthew Barth #include <memory>
40d9cb63b6SMatthew Barth #include <tuple>
41d9cb63b6SMatthew Barth #include <utility>
4206764946SMatthew Barth #include <vector>
43a227a16dSMatthew Barth 
44a227a16dSMatthew Barth namespace phosphor::fan::control::json
45a227a16dSMatthew Barth {
46a227a16dSMatthew Barth 
47acd737cdSMatthew Barth using json = nlohmann::json;
48acd737cdSMatthew Barth 
49acd737cdSMatthew Barth std::vector<std::string> Manager::_activeProfiles;
5012cb125aSMatthew Barth std::map<std::string,
514ca87faeSMatthew Barth          std::map<std::string, std::pair<bool, std::vector<std::string>>>>
5212cb125aSMatthew Barth     Manager::_servTree;
5307fecfc6SMatthew Barth std::map<std::string,
5407fecfc6SMatthew Barth          std::map<std::string, std::map<std::string, PropertyVariantType>>>
5507fecfc6SMatthew Barth     Manager::_objects;
56acd737cdSMatthew Barth 
579403a217SMatthew Barth Manager::Manager(const sdeventplus::Event& event) :
589403a217SMatthew Barth     _bus(util::SDBusPlus::getBus()), _event(event)
59a227a16dSMatthew Barth {
60a227a16dSMatthew Barth     // Manager JSON config file is optional
61a227a16dSMatthew Barth     auto confFile =
629403a217SMatthew Barth         fan::JsonConfig::getConfFile(_bus, confAppName, confFileName, true);
63a227a16dSMatthew Barth     if (!confFile.empty())
64a227a16dSMatthew Barth     {
65a227a16dSMatthew Barth         _jsonObj = fan::JsonConfig::load(confFile);
66a227a16dSMatthew Barth     }
6706764946SMatthew Barth 
68acd737cdSMatthew Barth     // Parse and set the available profiles and which are active
69acd737cdSMatthew Barth     setProfiles();
70acd737cdSMatthew Barth 
71acd737cdSMatthew Barth     // Load the zone configurations
729403a217SMatthew Barth     _zones = getConfig<Zone>(false, event, this);
73de90fb4dSMatthew Barth 
74de90fb4dSMatthew Barth     // Load the fan configurations and move each fan into its zone
759403a217SMatthew Barth     auto fans = getConfig<Fan>(false);
76de90fb4dSMatthew Barth     for (auto& fan : fans)
77de90fb4dSMatthew Barth     {
780206c728SMatthew Barth         configKey fanProfile =
790206c728SMatthew Barth             std::make_pair(fan.second->getZone(), fan.first.second);
800206c728SMatthew Barth         auto itZone = std::find_if(
810206c728SMatthew Barth             _zones.begin(), _zones.end(), [&fanProfile](const auto& zone) {
820206c728SMatthew Barth                 return Manager::inConfig(fanProfile, zone.first);
83de90fb4dSMatthew Barth             });
84de90fb4dSMatthew Barth         if (itZone != _zones.end())
85de90fb4dSMatthew Barth         {
866f787309SMatthew Barth             if (itZone->second->getTarget() != fan.second->getTarget() &&
876f787309SMatthew Barth                 fan.second->getTarget() != 0)
886f787309SMatthew Barth             {
896f787309SMatthew Barth                 // Update zone target to current target of the fan in the zone
906f787309SMatthew Barth                 itZone->second->setTarget(fan.second->getTarget());
916f787309SMatthew Barth             }
92de90fb4dSMatthew Barth             itZone->second->addFan(std::move(fan.second));
93de90fb4dSMatthew Barth         }
94de90fb4dSMatthew Barth     }
95b584d818SMatthew Barth 
9644ab7693SMatthew Barth     // Load the configured groups that are copied into events where they're used
979403a217SMatthew Barth     auto groups = getConfig<Group>(true);
9844ab7693SMatthew Barth 
9944ab7693SMatthew Barth     // Load any events configured
1009403a217SMatthew Barth     _events = getConfig<Event>(true, this, groups, _zones);
10144ab7693SMatthew Barth 
1029403a217SMatthew Barth     _bus.request_name(CONTROL_BUSNAME);
10306764946SMatthew Barth }
104acd737cdSMatthew Barth 
105acd737cdSMatthew Barth const std::vector<std::string>& Manager::getActiveProfiles()
106acd737cdSMatthew Barth {
107acd737cdSMatthew Barth     return _activeProfiles;
108a227a16dSMatthew Barth }
109a227a16dSMatthew Barth 
1100206c728SMatthew Barth bool Manager::inConfig(const configKey& input, const configKey& comp)
1110206c728SMatthew Barth {
1120206c728SMatthew Barth     // Config names dont match, do not include in config
1130206c728SMatthew Barth     if (input.first != comp.first)
1140206c728SMatthew Barth     {
1150206c728SMatthew Barth         return false;
1160206c728SMatthew Barth     }
1170206c728SMatthew Barth     // No profiles specified by input config, can be used in any config
1180206c728SMatthew Barth     if (input.second.empty())
1190206c728SMatthew Barth     {
1200206c728SMatthew Barth         return true;
1210206c728SMatthew Barth     }
1220206c728SMatthew Barth     else
1230206c728SMatthew Barth     {
1240206c728SMatthew Barth         // Profiles must have one match in the other's profiles(and they must be
1250206c728SMatthew Barth         // an active profile) to be used in the config
1260206c728SMatthew Barth         return std::any_of(
1270206c728SMatthew Barth             input.second.begin(), input.second.end(),
1280206c728SMatthew Barth             [&comp](const auto& lProfile) {
1290206c728SMatthew Barth                 return std::any_of(
1300206c728SMatthew Barth                     comp.second.begin(), comp.second.end(),
1310206c728SMatthew Barth                     [&lProfile](const auto& rProfile) {
1320206c728SMatthew Barth                         if (lProfile != rProfile)
1330206c728SMatthew Barth                         {
1340206c728SMatthew Barth                             return false;
1350206c728SMatthew Barth                         }
1360206c728SMatthew Barth                         auto activeProfs = getActiveProfiles();
1370206c728SMatthew Barth                         return std::find(activeProfs.begin(), activeProfs.end(),
1380206c728SMatthew Barth                                          lProfile) != activeProfs.end();
1390206c728SMatthew Barth                     });
1400206c728SMatthew Barth             });
1410206c728SMatthew Barth     }
1420206c728SMatthew Barth }
1430206c728SMatthew Barth 
14412cb125aSMatthew Barth bool Manager::hasOwner(const std::string& path, const std::string& intf)
14512cb125aSMatthew Barth {
14612cb125aSMatthew Barth     auto itServ = _servTree.find(path);
14712cb125aSMatthew Barth     if (itServ == _servTree.end())
14812cb125aSMatthew Barth     {
14912cb125aSMatthew Barth         // Path not found in cache, therefore owner missing
15012cb125aSMatthew Barth         return false;
15112cb125aSMatthew Barth     }
1524ca87faeSMatthew Barth     for (const auto& service : itServ->second)
15312cb125aSMatthew Barth     {
15412cb125aSMatthew Barth         auto itIntf = std::find_if(
1554ca87faeSMatthew Barth             service.second.second.begin(), service.second.second.end(),
15612cb125aSMatthew Barth             [&intf](const auto& interface) { return intf == interface; });
1574ca87faeSMatthew Barth         if (itIntf != std::end(service.second.second))
15812cb125aSMatthew Barth         {
15912cb125aSMatthew Barth             // Service found, return owner state
1604ca87faeSMatthew Barth             return service.second.first;
16112cb125aSMatthew Barth         }
16212cb125aSMatthew Barth     }
16312cb125aSMatthew Barth     // Interface not found in cache, therefore owner missing
16412cb125aSMatthew Barth     return false;
16512cb125aSMatthew Barth }
16612cb125aSMatthew Barth 
1674ca87faeSMatthew Barth void Manager::setOwner(const std::string& path, const std::string& serv,
1684ca87faeSMatthew Barth                        const std::string& intf, bool isOwned)
1694ca87faeSMatthew Barth {
170*2a9e7b2eSMatthew Barth     // Set owner state for specific object given
171*2a9e7b2eSMatthew Barth     auto& ownIntf = _servTree[path][serv];
172*2a9e7b2eSMatthew Barth     ownIntf.first = isOwned;
1734ca87faeSMatthew Barth     auto itIntf = std::find_if(
174*2a9e7b2eSMatthew Barth         ownIntf.second.begin(), ownIntf.second.end(),
1754ca87faeSMatthew Barth         [&intf](const auto& interface) { return intf == interface; });
176*2a9e7b2eSMatthew Barth     if (itIntf == std::end(ownIntf.second))
1774ca87faeSMatthew Barth     {
178*2a9e7b2eSMatthew Barth         ownIntf.second.emplace_back(intf);
179*2a9e7b2eSMatthew Barth     }
180*2a9e7b2eSMatthew Barth 
181*2a9e7b2eSMatthew Barth     // Update owner state on all entries of the same `serv` & `intf`
182*2a9e7b2eSMatthew Barth     for (auto& itPath : _servTree)
1834ca87faeSMatthew Barth     {
184*2a9e7b2eSMatthew Barth         if (itPath.first == path)
185*2a9e7b2eSMatthew Barth         {
186*2a9e7b2eSMatthew Barth             // Already set/updated owner on this path for `serv` & `intf`
187*2a9e7b2eSMatthew Barth             continue;
188*2a9e7b2eSMatthew Barth         }
189*2a9e7b2eSMatthew Barth         for (auto& itServ : itPath.second)
190*2a9e7b2eSMatthew Barth         {
191*2a9e7b2eSMatthew Barth             if (itServ.first != serv)
192*2a9e7b2eSMatthew Barth             {
193*2a9e7b2eSMatthew Barth                 continue;
194*2a9e7b2eSMatthew Barth             }
195*2a9e7b2eSMatthew Barth             auto itIntf = std::find_if(
196*2a9e7b2eSMatthew Barth                 itServ.second.second.begin(), itServ.second.second.end(),
197*2a9e7b2eSMatthew Barth                 [&intf](const auto& interface) { return intf == interface; });
198*2a9e7b2eSMatthew Barth             if (itIntf != std::end(itServ.second.second))
199*2a9e7b2eSMatthew Barth             {
200*2a9e7b2eSMatthew Barth                 itServ.second.first = isOwned;
2014ca87faeSMatthew Barth             }
2024ca87faeSMatthew Barth         }
2034ca87faeSMatthew Barth     }
2044ca87faeSMatthew Barth }
2054ca87faeSMatthew Barth 
2064ca87faeSMatthew Barth const std::string& Manager::findService(const std::string& path,
2074ca87faeSMatthew Barth                                         const std::string& intf)
2084ca87faeSMatthew Barth {
2094ca87faeSMatthew Barth     static const std::string empty = "";
2104ca87faeSMatthew Barth 
2114ca87faeSMatthew Barth     auto itServ = _servTree.find(path);
2124ca87faeSMatthew Barth     if (itServ != _servTree.end())
2134ca87faeSMatthew Barth     {
2144ca87faeSMatthew Barth         for (const auto& service : itServ->second)
2154ca87faeSMatthew Barth         {
2164ca87faeSMatthew Barth             auto itIntf = std::find_if(
2174ca87faeSMatthew Barth                 service.second.second.begin(), service.second.second.end(),
2184ca87faeSMatthew Barth                 [&intf](const auto& interface) { return intf == interface; });
2194ca87faeSMatthew Barth             if (itIntf != std::end(service.second.second))
2204ca87faeSMatthew Barth             {
2214ca87faeSMatthew Barth                 // Service found, return service name
2224ca87faeSMatthew Barth                 return service.first;
2234ca87faeSMatthew Barth             }
2244ca87faeSMatthew Barth         }
2254ca87faeSMatthew Barth     }
2264ca87faeSMatthew Barth 
2274ca87faeSMatthew Barth     return empty;
2284ca87faeSMatthew Barth }
2294ca87faeSMatthew Barth 
23098f6fc17SMatthew Barth void Manager::addServices(const std::string& intf, int32_t depth)
2314ca87faeSMatthew Barth {
2324ca87faeSMatthew Barth     // Get all subtree objects for the given interface
2334ca87faeSMatthew Barth     auto objects = util::SDBusPlus::getSubTree(util::SDBusPlus::getBus(), "/",
2344ca87faeSMatthew Barth                                                intf, depth);
2354ca87faeSMatthew Barth     // Add what's returned to the cache of path->services
2364ca87faeSMatthew Barth     for (auto& itPath : objects)
2374ca87faeSMatthew Barth     {
2384ca87faeSMatthew Barth         auto pathIter = _servTree.find(itPath.first);
2394ca87faeSMatthew Barth         if (pathIter != _servTree.end())
2404ca87faeSMatthew Barth         {
2414ca87faeSMatthew Barth             // Path found in cache
2424ca87faeSMatthew Barth             for (auto& itServ : itPath.second)
2434ca87faeSMatthew Barth             {
2444ca87faeSMatthew Barth                 auto servIter = pathIter->second.find(itServ.first);
2454ca87faeSMatthew Barth                 if (servIter != pathIter->second.end())
2464ca87faeSMatthew Barth                 {
2474ca87faeSMatthew Barth                     // Service found in cache
2484ca87faeSMatthew Barth                     for (auto& itIntf : itServ.second)
2494ca87faeSMatthew Barth                     {
2504ca87faeSMatthew Barth                         if (std::find(servIter->second.second.begin(),
2514ca87faeSMatthew Barth                                       servIter->second.second.end(),
2524ca87faeSMatthew Barth                                       itIntf) == servIter->second.second.end())
2534ca87faeSMatthew Barth                         {
2544ca87faeSMatthew Barth                             // Add interface to cache
2554ca87faeSMatthew Barth                             servIter->second.second.emplace_back(itIntf);
2564ca87faeSMatthew Barth                         }
2574ca87faeSMatthew Barth                     }
2584ca87faeSMatthew Barth                 }
2594ca87faeSMatthew Barth                 else
2604ca87faeSMatthew Barth                 {
2614ca87faeSMatthew Barth                     // Service not found in cache
2624ca87faeSMatthew Barth                     auto intfs = {intf};
2634ca87faeSMatthew Barth                     pathIter->second[itServ.first] =
2644ca87faeSMatthew Barth                         std::make_pair(true, intfs);
2654ca87faeSMatthew Barth                 }
2664ca87faeSMatthew Barth             }
2674ca87faeSMatthew Barth         }
2684ca87faeSMatthew Barth         else
2694ca87faeSMatthew Barth         {
2704ca87faeSMatthew Barth             // Path not found in cache
2714ca87faeSMatthew Barth             auto intfs = {intf};
2724ca87faeSMatthew Barth             _servTree[itPath.first] = {
2734ca87faeSMatthew Barth                 {itPath.second.begin()->first, std::make_pair(true, intfs)}};
2744ca87faeSMatthew Barth         }
2754ca87faeSMatthew Barth     }
2764ca87faeSMatthew Barth }
2774ca87faeSMatthew Barth 
2784ca87faeSMatthew Barth const std::string& Manager::getService(const std::string& path,
2794ca87faeSMatthew Barth                                        const std::string& intf)
2804ca87faeSMatthew Barth {
2814ca87faeSMatthew Barth     // Retrieve service from cache
2824ca87faeSMatthew Barth     const auto& serviceName = findService(path, intf);
2834ca87faeSMatthew Barth     if (serviceName.empty())
2844ca87faeSMatthew Barth     {
28598f6fc17SMatthew Barth         addServices(intf, 0);
2864ca87faeSMatthew Barth         return findService(path, intf);
2874ca87faeSMatthew Barth     }
2884ca87faeSMatthew Barth 
2894ca87faeSMatthew Barth     return serviceName;
2904ca87faeSMatthew Barth }
2914ca87faeSMatthew Barth 
292f41e947bSMatthew Barth std::vector<std::string> Manager::findPaths(const std::string& serv,
293f41e947bSMatthew Barth                                             const std::string& intf)
294f41e947bSMatthew Barth {
295f41e947bSMatthew Barth     std::vector<std::string> paths;
296f41e947bSMatthew Barth 
297f41e947bSMatthew Barth     for (const auto& path : _servTree)
298f41e947bSMatthew Barth     {
299f41e947bSMatthew Barth         auto itServ = path.second.find(serv);
300f41e947bSMatthew Barth         if (itServ != path.second.end())
301f41e947bSMatthew Barth         {
302f41e947bSMatthew Barth             if (std::find(itServ->second.second.begin(),
303f41e947bSMatthew Barth                           itServ->second.second.end(),
304f41e947bSMatthew Barth                           intf) != itServ->second.second.end())
305f41e947bSMatthew Barth             {
306f41e947bSMatthew Barth                 if (std::find(paths.begin(), paths.end(), path.first) ==
307f41e947bSMatthew Barth                     paths.end())
308f41e947bSMatthew Barth                 {
309f41e947bSMatthew Barth                     paths.push_back(path.first);
310f41e947bSMatthew Barth                 }
311f41e947bSMatthew Barth             }
312f41e947bSMatthew Barth         }
313f41e947bSMatthew Barth     }
314f41e947bSMatthew Barth 
315f41e947bSMatthew Barth     return paths;
316f41e947bSMatthew Barth }
317f41e947bSMatthew Barth 
318f41e947bSMatthew Barth std::vector<std::string> Manager::getPaths(const std::string& serv,
319f41e947bSMatthew Barth                                            const std::string& intf)
320f41e947bSMatthew Barth {
321f41e947bSMatthew Barth     auto paths = findPaths(serv, intf);
322f41e947bSMatthew Barth     if (paths.empty())
323f41e947bSMatthew Barth     {
324f41e947bSMatthew Barth         addServices(intf, 0);
325f41e947bSMatthew Barth         return findPaths(serv, intf);
326f41e947bSMatthew Barth     }
327f41e947bSMatthew Barth 
328f41e947bSMatthew Barth     return paths;
329f41e947bSMatthew Barth }
330f41e947bSMatthew Barth 
331f41e947bSMatthew Barth void Manager::addObjects(const std::string& path, const std::string& intf,
332f41e947bSMatthew Barth                          const std::string& prop)
333f41e947bSMatthew Barth {
334f41e947bSMatthew Barth     auto service = getService(path, intf);
335f41e947bSMatthew Barth     if (service.empty())
336f41e947bSMatthew Barth     {
337f41e947bSMatthew Barth         // Log service not found for object
338f41e947bSMatthew Barth         log<level::ERR>(
339f41e947bSMatthew Barth             fmt::format("Unable to get service name for path {}, interface {}",
340f41e947bSMatthew Barth                         path, intf)
341f41e947bSMatthew Barth                 .c_str());
342f41e947bSMatthew Barth         return;
343f41e947bSMatthew Barth     }
344f41e947bSMatthew Barth 
345f41e947bSMatthew Barth     auto objMgrPaths = getPaths(service, "org.freedesktop.DBus.ObjectManager");
346f41e947bSMatthew Barth     if (objMgrPaths.empty())
347f41e947bSMatthew Barth     {
348f41e947bSMatthew Barth         // No object manager interface provided by service?
349f41e947bSMatthew Barth         // Attempt to retrieve property directly
350f41e947bSMatthew Barth         auto variant = util::SDBusPlus::getPropertyVariant<PropertyVariantType>(
351f41e947bSMatthew Barth             _bus, service, path, intf, prop);
352f41e947bSMatthew Barth         _objects[path][intf][prop] = variant;
353f41e947bSMatthew Barth         return;
354f41e947bSMatthew Barth     }
355f41e947bSMatthew Barth 
356f41e947bSMatthew Barth     for (const auto& objMgrPath : objMgrPaths)
357f41e947bSMatthew Barth     {
358f41e947bSMatthew Barth         // Get all managed objects of service
359f41e947bSMatthew Barth         auto objects = util::SDBusPlus::getManagedObjects<PropertyVariantType>(
360f41e947bSMatthew Barth             _bus, service, objMgrPath);
361f41e947bSMatthew Barth 
362f41e947bSMatthew Barth         // Add what's returned to the cache of objects
363f41e947bSMatthew Barth         for (auto& object : objects)
364f41e947bSMatthew Barth         {
365f41e947bSMatthew Barth             auto itPath = _objects.find(object.first);
366f41e947bSMatthew Barth             if (itPath != _objects.end())
367f41e947bSMatthew Barth             {
368f41e947bSMatthew Barth                 // Path found in cache
369f41e947bSMatthew Barth                 for (auto& interface : itPath->second)
370f41e947bSMatthew Barth                 {
371f41e947bSMatthew Barth                     auto itIntf = itPath->second.find(interface.first);
372f41e947bSMatthew Barth                     if (itIntf != itPath->second.end())
373f41e947bSMatthew Barth                     {
374f41e947bSMatthew Barth                         // Interface found in cache
375f41e947bSMatthew Barth                         for (auto& property : itIntf->second)
376f41e947bSMatthew Barth                         {
377f41e947bSMatthew Barth                             auto itProp = itIntf->second.find(property.first);
378f41e947bSMatthew Barth                             if (itProp != itIntf->second.end())
379f41e947bSMatthew Barth                             {
380f41e947bSMatthew Barth                                 // Property found, update value
381f41e947bSMatthew Barth                                 itProp->second = property.second;
382f41e947bSMatthew Barth                             }
383f41e947bSMatthew Barth                             else
384f41e947bSMatthew Barth                             {
385f41e947bSMatthew Barth                                 itIntf->second.insert(property);
386f41e947bSMatthew Barth                             }
387f41e947bSMatthew Barth                         }
388f41e947bSMatthew Barth                     }
389f41e947bSMatthew Barth                     else
390f41e947bSMatthew Barth                     {
391f41e947bSMatthew Barth                         // Interface not found in cache
392f41e947bSMatthew Barth                         itPath->second.insert(interface);
393f41e947bSMatthew Barth                     }
394f41e947bSMatthew Barth                 }
395f41e947bSMatthew Barth             }
396f41e947bSMatthew Barth             else
397f41e947bSMatthew Barth             {
398f41e947bSMatthew Barth                 // Path not found in cache
399f41e947bSMatthew Barth                 _objects.insert(object);
400f41e947bSMatthew Barth             }
401f41e947bSMatthew Barth         }
402f41e947bSMatthew Barth     }
403f41e947bSMatthew Barth }
404f41e947bSMatthew Barth 
405f41e947bSMatthew Barth const std::optional<PropertyVariantType>
406f41e947bSMatthew Barth     Manager::getProperty(const std::string& path, const std::string& intf,
407f41e947bSMatthew Barth                          const std::string& prop)
408f41e947bSMatthew Barth {
409f41e947bSMatthew Barth     // TODO Objects hosted by fan control (i.e. ThermalMode) are required to
410f41e947bSMatthew Barth     // update the cache upon being set/updated
411f41e947bSMatthew Barth     auto itPath = _objects.find(path);
412f41e947bSMatthew Barth     if (itPath != _objects.end())
413f41e947bSMatthew Barth     {
414f41e947bSMatthew Barth         auto itIntf = itPath->second.find(intf);
415f41e947bSMatthew Barth         if (itIntf != itPath->second.end())
416f41e947bSMatthew Barth         {
417f41e947bSMatthew Barth             auto itProp = itIntf->second.find(prop);
418f41e947bSMatthew Barth             if (itProp != itIntf->second.end())
419f41e947bSMatthew Barth             {
420f41e947bSMatthew Barth                 return itProp->second;
421f41e947bSMatthew Barth             }
422f41e947bSMatthew Barth         }
423f41e947bSMatthew Barth     }
424f41e947bSMatthew Barth 
425f41e947bSMatthew Barth     return std::nullopt;
426f41e947bSMatthew Barth }
427f41e947bSMatthew Barth 
428d9cb63b6SMatthew Barth void Manager::addTimer(const TimerType type,
429d9cb63b6SMatthew Barth                        const std::chrono::microseconds interval,
430d9cb63b6SMatthew Barth                        std::unique_ptr<TimerPkg> pkg)
431d9cb63b6SMatthew Barth {
432d9cb63b6SMatthew Barth     auto dataPtr =
433d9cb63b6SMatthew Barth         std::make_unique<TimerData>(std::make_pair(type, std::move(*pkg)));
434d9cb63b6SMatthew Barth     Timer timer(_event,
435d9cb63b6SMatthew Barth                 std::bind(&Manager::timerExpired, this, std::ref(*dataPtr)));
436d9cb63b6SMatthew Barth     if (type == TimerType::repeating)
437d9cb63b6SMatthew Barth     {
438d9cb63b6SMatthew Barth         timer.restart(interval);
439d9cb63b6SMatthew Barth     }
440d9cb63b6SMatthew Barth     else if (type == TimerType::oneshot)
441d9cb63b6SMatthew Barth     {
442d9cb63b6SMatthew Barth         timer.restartOnce(interval);
443d9cb63b6SMatthew Barth     }
444d9cb63b6SMatthew Barth     else
445d9cb63b6SMatthew Barth     {
446d9cb63b6SMatthew Barth         throw std::invalid_argument("Invalid Timer Type");
447d9cb63b6SMatthew Barth     }
448d9cb63b6SMatthew Barth     _timers.emplace_back(std::move(dataPtr), std::move(timer));
449d9cb63b6SMatthew Barth }
450d9cb63b6SMatthew Barth 
451d9cb63b6SMatthew Barth void Manager::timerExpired(TimerData& data)
452d9cb63b6SMatthew Barth {
453d9cb63b6SMatthew Barth     auto& actions =
454d9cb63b6SMatthew Barth         std::get<std::vector<std::unique_ptr<ActionBase>>&>(data.second);
455d9cb63b6SMatthew Barth     // Perform the actions in the timer data
456d9cb63b6SMatthew Barth     std::for_each(actions.begin(), actions.end(),
45700f6aa09SMatthew Barth                   [](auto& action) { action->run(); });
458d9cb63b6SMatthew Barth 
459d9cb63b6SMatthew Barth     // Remove oneshot timers after they expired
460d9cb63b6SMatthew Barth     if (data.first == TimerType::oneshot)
461d9cb63b6SMatthew Barth     {
462d9cb63b6SMatthew Barth         auto itTimer = std::find_if(
463d9cb63b6SMatthew Barth             _timers.begin(), _timers.end(), [&data](const auto& timer) {
464d9cb63b6SMatthew Barth                 return (data.first == timer.first->first &&
465d9cb63b6SMatthew Barth                         (std::get<std::string>(data.second) ==
466d9cb63b6SMatthew Barth                          std::get<std::string>(timer.first->second)));
467d9cb63b6SMatthew Barth             });
468d9cb63b6SMatthew Barth         if (itTimer != std::end(_timers))
469d9cb63b6SMatthew Barth         {
470d9cb63b6SMatthew Barth             _timers.erase(itTimer);
471d9cb63b6SMatthew Barth         }
472d9cb63b6SMatthew Barth     }
473d9cb63b6SMatthew Barth }
474d9cb63b6SMatthew Barth 
475ebabc040SMatthew Barth void Manager::handleSignal(sdbusplus::message::message& msg,
476ebabc040SMatthew Barth                            const std::vector<SignalPkg>* pkgs)
477ebabc040SMatthew Barth {
478ebabc040SMatthew Barth     for (auto& pkg : *pkgs)
479ebabc040SMatthew Barth     {
480ebabc040SMatthew Barth         // Handle the signal callback and only run the actions if the handler
481ebabc040SMatthew Barth         // updated the cache for the given SignalObject
482ebabc040SMatthew Barth         if (std::get<SignalHandler>(pkg)(msg, std::get<SignalObject>(pkg),
483ebabc040SMatthew Barth                                          *this))
484ebabc040SMatthew Barth         {
485ebabc040SMatthew Barth             // Perform the actions in the handler package
486ebabc040SMatthew Barth             auto& actions = std::get<SignalActions>(pkg);
487ebabc040SMatthew Barth             std::for_each(actions.begin(), actions.end(),
488ebabc040SMatthew Barth                           [](auto& action) { action.get()->run(); });
489ebabc040SMatthew Barth         }
490ebabc040SMatthew Barth     }
491ebabc040SMatthew Barth }
492ebabc040SMatthew Barth 
493a227a16dSMatthew Barth unsigned int Manager::getPowerOnDelay()
494a227a16dSMatthew Barth {
495a227a16dSMatthew Barth     auto powerOnDelay = 0;
496a227a16dSMatthew Barth 
497a227a16dSMatthew Barth     // Parse optional "power_on_delay" from JSON object
498a227a16dSMatthew Barth     if (!_jsonObj.empty() && _jsonObj.contains("power_on_delay"))
499a227a16dSMatthew Barth     {
500a227a16dSMatthew Barth         powerOnDelay = _jsonObj["power_on_delay"].get<unsigned int>();
501a227a16dSMatthew Barth     }
502a227a16dSMatthew Barth 
503a227a16dSMatthew Barth     return powerOnDelay;
504a227a16dSMatthew Barth }
505a227a16dSMatthew Barth 
506acd737cdSMatthew Barth void Manager::setProfiles()
507acd737cdSMatthew Barth {
508acd737cdSMatthew Barth     // Profiles JSON config file is optional
509acd737cdSMatthew Barth     auto confFile = fan::JsonConfig::getConfFile(_bus, confAppName,
510acd737cdSMatthew Barth                                                  Profile::confFileName, true);
511acd737cdSMatthew Barth     if (!confFile.empty())
512acd737cdSMatthew Barth     {
513acd737cdSMatthew Barth         for (const auto& entry : fan::JsonConfig::load(confFile))
514acd737cdSMatthew Barth         {
515acd737cdSMatthew Barth             auto obj = std::make_unique<Profile>(entry);
516acd737cdSMatthew Barth             _profiles.emplace(
517acd737cdSMatthew Barth                 std::make_pair(obj->getName(), obj->getProfiles()),
518acd737cdSMatthew Barth                 std::move(obj));
519acd737cdSMatthew Barth         }
520acd737cdSMatthew Barth     }
521acd737cdSMatthew Barth     // Ensure all configurations use the same set of active profiles
522acd737cdSMatthew Barth     // (In case a profile's active state changes during configuration)
523acd737cdSMatthew Barth     for (const auto& profile : _profiles)
524acd737cdSMatthew Barth     {
525acd737cdSMatthew Barth         if (profile.second->isActive())
526acd737cdSMatthew Barth         {
527acd737cdSMatthew Barth             _activeProfiles.emplace_back(profile.first.first);
528acd737cdSMatthew Barth         }
529acd737cdSMatthew Barth     }
530acd737cdSMatthew Barth }
531acd737cdSMatthew Barth 
532a227a16dSMatthew Barth } // namespace phosphor::fan::control::json
533