xref: /openbmc/phosphor-fan-presence/control/json/manager.cpp (revision 603ef164096f37311337d3bab592822fd762dd64)
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"
21de90fb4dSMatthew Barth #include "fan.hpp"
22d9cb63b6SMatthew Barth #include "group.hpp"
23a227a16dSMatthew Barth #include "json_config.hpp"
2406764946SMatthew Barth #include "profile.hpp"
25acd737cdSMatthew Barth #include "zone.hpp"
26a227a16dSMatthew Barth 
27acd737cdSMatthew Barth #include <nlohmann/json.hpp>
28a227a16dSMatthew Barth #include <sdbusplus/bus.hpp>
29acd737cdSMatthew Barth #include <sdeventplus/event.hpp>
30d9cb63b6SMatthew Barth #include <sdeventplus/utility/timer.hpp>
31a227a16dSMatthew Barth 
32de90fb4dSMatthew Barth #include <algorithm>
33d9cb63b6SMatthew Barth #include <chrono>
34a227a16dSMatthew Barth #include <filesystem>
35d9cb63b6SMatthew Barth #include <functional>
36d9cb63b6SMatthew Barth #include <map>
37d9cb63b6SMatthew Barth #include <memory>
38d9cb63b6SMatthew Barth #include <tuple>
39d9cb63b6SMatthew Barth #include <utility>
4006764946SMatthew Barth #include <vector>
41a227a16dSMatthew Barth 
42a227a16dSMatthew Barth namespace phosphor::fan::control::json
43a227a16dSMatthew Barth {
44a227a16dSMatthew Barth 
45acd737cdSMatthew Barth using json = nlohmann::json;
46acd737cdSMatthew Barth 
47acd737cdSMatthew Barth std::vector<std::string> Manager::_activeProfiles;
4812cb125aSMatthew Barth std::map<std::string,
4912cb125aSMatthew Barth          std::map<std::pair<std::string, bool>, std::vector<std::string>>>
5012cb125aSMatthew Barth     Manager::_servTree;
5107fecfc6SMatthew Barth std::map<std::string,
5207fecfc6SMatthew Barth          std::map<std::string, std::map<std::string, PropertyVariantType>>>
5307fecfc6SMatthew Barth     Manager::_objects;
54acd737cdSMatthew Barth 
5506764946SMatthew Barth Manager::Manager(sdbusplus::bus::bus& bus, const sdeventplus::Event& event) :
56acd737cdSMatthew Barth     _bus(bus), _event(event)
57a227a16dSMatthew Barth {
58a227a16dSMatthew Barth     // Manager JSON config file is optional
59a227a16dSMatthew Barth     auto confFile =
60a227a16dSMatthew Barth         fan::JsonConfig::getConfFile(bus, confAppName, confFileName, true);
61a227a16dSMatthew Barth     if (!confFile.empty())
62a227a16dSMatthew Barth     {
63a227a16dSMatthew Barth         _jsonObj = fan::JsonConfig::load(confFile);
64a227a16dSMatthew Barth     }
6506764946SMatthew Barth 
66acd737cdSMatthew Barth     // Parse and set the available profiles and which are active
67acd737cdSMatthew Barth     setProfiles();
68acd737cdSMatthew Barth 
69acd737cdSMatthew Barth     // Load the zone configurations
70*603ef164SMatthew Barth     _zones = getConfig<Zone>(false, bus, bus, event, this);
71de90fb4dSMatthew Barth 
72de90fb4dSMatthew Barth     // Load the fan configurations and move each fan into its zone
73*603ef164SMatthew Barth     auto fans = getConfig<Fan>(false, bus, bus);
74de90fb4dSMatthew Barth     for (auto& fan : fans)
75de90fb4dSMatthew Barth     {
76de90fb4dSMatthew Barth         auto itZone =
77de90fb4dSMatthew Barth             std::find_if(_zones.begin(), _zones.end(),
78de90fb4dSMatthew Barth                          [&fanZone = fan.second->getZone()](const auto& zone) {
79de90fb4dSMatthew Barth                              return fanZone == zone.second->getName();
80de90fb4dSMatthew Barth                          });
81de90fb4dSMatthew Barth         if (itZone != _zones.end())
82de90fb4dSMatthew Barth         {
83de90fb4dSMatthew Barth             itZone->second->addFan(std::move(fan.second));
84de90fb4dSMatthew Barth         }
85de90fb4dSMatthew Barth     }
86b584d818SMatthew Barth 
87b584d818SMatthew Barth     bus.request_name(CONTROL_BUSNAME);
8806764946SMatthew Barth }
89acd737cdSMatthew Barth 
90acd737cdSMatthew Barth const std::vector<std::string>& Manager::getActiveProfiles()
91acd737cdSMatthew Barth {
92acd737cdSMatthew Barth     return _activeProfiles;
93a227a16dSMatthew Barth }
94a227a16dSMatthew Barth 
9512cb125aSMatthew Barth bool Manager::hasOwner(const std::string& path, const std::string& intf)
9612cb125aSMatthew Barth {
9712cb125aSMatthew Barth     auto itServ = _servTree.find(path);
9812cb125aSMatthew Barth     if (itServ == _servTree.end())
9912cb125aSMatthew Barth     {
10012cb125aSMatthew Barth         // Path not found in cache, therefore owner missing
10112cb125aSMatthew Barth         return false;
10212cb125aSMatthew Barth     }
10312cb125aSMatthew Barth     for (const auto& serv : itServ->second)
10412cb125aSMatthew Barth     {
10512cb125aSMatthew Barth         auto itIntf = std::find_if(
10612cb125aSMatthew Barth             serv.second.begin(), serv.second.end(),
10712cb125aSMatthew Barth             [&intf](const auto& interface) { return intf == interface; });
10812cb125aSMatthew Barth         if (itIntf != std::end(serv.second))
10912cb125aSMatthew Barth         {
11012cb125aSMatthew Barth             // Service found, return owner state
11112cb125aSMatthew Barth             return serv.first.second;
11212cb125aSMatthew Barth         }
11312cb125aSMatthew Barth     }
11412cb125aSMatthew Barth     // Interface not found in cache, therefore owner missing
11512cb125aSMatthew Barth     return false;
11612cb125aSMatthew Barth }
11712cb125aSMatthew Barth 
118d9cb63b6SMatthew Barth void Manager::addTimer(const TimerType type,
119d9cb63b6SMatthew Barth                        const std::chrono::microseconds interval,
120d9cb63b6SMatthew Barth                        std::unique_ptr<TimerPkg> pkg)
121d9cb63b6SMatthew Barth {
122d9cb63b6SMatthew Barth     auto dataPtr =
123d9cb63b6SMatthew Barth         std::make_unique<TimerData>(std::make_pair(type, std::move(*pkg)));
124d9cb63b6SMatthew Barth     Timer timer(_event,
125d9cb63b6SMatthew Barth                 std::bind(&Manager::timerExpired, this, std::ref(*dataPtr)));
126d9cb63b6SMatthew Barth     if (type == TimerType::repeating)
127d9cb63b6SMatthew Barth     {
128d9cb63b6SMatthew Barth         timer.restart(interval);
129d9cb63b6SMatthew Barth     }
130d9cb63b6SMatthew Barth     else if (type == TimerType::oneshot)
131d9cb63b6SMatthew Barth     {
132d9cb63b6SMatthew Barth         timer.restartOnce(interval);
133d9cb63b6SMatthew Barth     }
134d9cb63b6SMatthew Barth     else
135d9cb63b6SMatthew Barth     {
136d9cb63b6SMatthew Barth         throw std::invalid_argument("Invalid Timer Type");
137d9cb63b6SMatthew Barth     }
138d9cb63b6SMatthew Barth     _timers.emplace_back(std::move(dataPtr), std::move(timer));
139d9cb63b6SMatthew Barth }
140d9cb63b6SMatthew Barth 
141d9cb63b6SMatthew Barth void Manager::timerExpired(TimerData& data)
142d9cb63b6SMatthew Barth {
143d9cb63b6SMatthew Barth     auto& actions =
144d9cb63b6SMatthew Barth         std::get<std::vector<std::unique_ptr<ActionBase>>&>(data.second);
145d9cb63b6SMatthew Barth     // Perform the actions in the timer data
146d9cb63b6SMatthew Barth     std::for_each(actions.begin(), actions.end(),
147d9cb63b6SMatthew Barth                   [zone = std::ref(std::get<Zone&>(data.second)),
148d9cb63b6SMatthew Barth                    group = std::cref(std::get<const Group&>(data.second))](
149d9cb63b6SMatthew Barth                       auto& action) { action->run(zone, group); });
150d9cb63b6SMatthew Barth 
151d9cb63b6SMatthew Barth     // Remove oneshot timers after they expired
152d9cb63b6SMatthew Barth     if (data.first == TimerType::oneshot)
153d9cb63b6SMatthew Barth     {
154d9cb63b6SMatthew Barth         auto itTimer = std::find_if(
155d9cb63b6SMatthew Barth             _timers.begin(), _timers.end(), [&data](const auto& timer) {
156d9cb63b6SMatthew Barth                 return (data.first == timer.first->first &&
157d9cb63b6SMatthew Barth                         (std::get<std::string>(data.second) ==
158d9cb63b6SMatthew Barth                          std::get<std::string>(timer.first->second)));
159d9cb63b6SMatthew Barth             });
160d9cb63b6SMatthew Barth         if (itTimer != std::end(_timers))
161d9cb63b6SMatthew Barth         {
162d9cb63b6SMatthew Barth             _timers.erase(itTimer);
163d9cb63b6SMatthew Barth         }
164d9cb63b6SMatthew Barth     }
165d9cb63b6SMatthew Barth }
166d9cb63b6SMatthew Barth 
167a227a16dSMatthew Barth unsigned int Manager::getPowerOnDelay()
168a227a16dSMatthew Barth {
169a227a16dSMatthew Barth     auto powerOnDelay = 0;
170a227a16dSMatthew Barth 
171a227a16dSMatthew Barth     // Parse optional "power_on_delay" from JSON object
172a227a16dSMatthew Barth     if (!_jsonObj.empty() && _jsonObj.contains("power_on_delay"))
173a227a16dSMatthew Barth     {
174a227a16dSMatthew Barth         powerOnDelay = _jsonObj["power_on_delay"].get<unsigned int>();
175a227a16dSMatthew Barth     }
176a227a16dSMatthew Barth 
177a227a16dSMatthew Barth     return powerOnDelay;
178a227a16dSMatthew Barth }
179a227a16dSMatthew Barth 
180acd737cdSMatthew Barth void Manager::setProfiles()
181acd737cdSMatthew Barth {
182acd737cdSMatthew Barth     // Profiles JSON config file is optional
183acd737cdSMatthew Barth     auto confFile = fan::JsonConfig::getConfFile(_bus, confAppName,
184acd737cdSMatthew Barth                                                  Profile::confFileName, true);
185acd737cdSMatthew Barth     if (!confFile.empty())
186acd737cdSMatthew Barth     {
187acd737cdSMatthew Barth         for (const auto& entry : fan::JsonConfig::load(confFile))
188acd737cdSMatthew Barth         {
189acd737cdSMatthew Barth             auto obj = std::make_unique<Profile>(entry);
190acd737cdSMatthew Barth             _profiles.emplace(
191acd737cdSMatthew Barth                 std::make_pair(obj->getName(), obj->getProfiles()),
192acd737cdSMatthew Barth                 std::move(obj));
193acd737cdSMatthew Barth         }
194acd737cdSMatthew Barth     }
195acd737cdSMatthew Barth     // Ensure all configurations use the same set of active profiles
196acd737cdSMatthew Barth     // (In case a profile's active state changes during configuration)
197acd737cdSMatthew Barth     for (const auto& profile : _profiles)
198acd737cdSMatthew Barth     {
199acd737cdSMatthew Barth         if (profile.second->isActive())
200acd737cdSMatthew Barth         {
201acd737cdSMatthew Barth             _activeProfiles.emplace_back(profile.first.first);
202acd737cdSMatthew Barth         }
203acd737cdSMatthew Barth     }
204acd737cdSMatthew Barth }
205acd737cdSMatthew Barth 
206a227a16dSMatthew Barth } // namespace phosphor::fan::control::json
207