xref: /openbmc/phosphor-fan-presence/control/json/manager.cpp (revision 44ab7693f6584460b4dc538c56572b2b2781bfb6)
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"
21*44ab7693SMatthew 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"
26acd737cdSMatthew Barth #include "zone.hpp"
27a227a16dSMatthew Barth 
28acd737cdSMatthew Barth #include <nlohmann/json.hpp>
29a227a16dSMatthew Barth #include <sdbusplus/bus.hpp>
30acd737cdSMatthew Barth #include <sdeventplus/event.hpp>
31d9cb63b6SMatthew Barth #include <sdeventplus/utility/timer.hpp>
32a227a16dSMatthew Barth 
33de90fb4dSMatthew Barth #include <algorithm>
34d9cb63b6SMatthew Barth #include <chrono>
35a227a16dSMatthew Barth #include <filesystem>
36d9cb63b6SMatthew Barth #include <functional>
37d9cb63b6SMatthew Barth #include <map>
38d9cb63b6SMatthew Barth #include <memory>
39d9cb63b6SMatthew Barth #include <tuple>
40d9cb63b6SMatthew Barth #include <utility>
4106764946SMatthew Barth #include <vector>
42a227a16dSMatthew Barth 
43a227a16dSMatthew Barth namespace phosphor::fan::control::json
44a227a16dSMatthew Barth {
45a227a16dSMatthew Barth 
46acd737cdSMatthew Barth using json = nlohmann::json;
47acd737cdSMatthew Barth 
48acd737cdSMatthew Barth std::vector<std::string> Manager::_activeProfiles;
4912cb125aSMatthew Barth std::map<std::string,
5012cb125aSMatthew Barth          std::map<std::pair<std::string, bool>, std::vector<std::string>>>
5112cb125aSMatthew Barth     Manager::_servTree;
5207fecfc6SMatthew Barth std::map<std::string,
5307fecfc6SMatthew Barth          std::map<std::string, std::map<std::string, PropertyVariantType>>>
5407fecfc6SMatthew Barth     Manager::_objects;
55acd737cdSMatthew Barth 
5606764946SMatthew Barth Manager::Manager(sdbusplus::bus::bus& bus, const sdeventplus::Event& event) :
57acd737cdSMatthew Barth     _bus(bus), _event(event)
58a227a16dSMatthew Barth {
59a227a16dSMatthew Barth     // Manager JSON config file is optional
60a227a16dSMatthew Barth     auto confFile =
61a227a16dSMatthew Barth         fan::JsonConfig::getConfFile(bus, confAppName, confFileName, true);
62a227a16dSMatthew Barth     if (!confFile.empty())
63a227a16dSMatthew Barth     {
64a227a16dSMatthew Barth         _jsonObj = fan::JsonConfig::load(confFile);
65a227a16dSMatthew Barth     }
6606764946SMatthew Barth 
67acd737cdSMatthew Barth     // Parse and set the available profiles and which are active
68acd737cdSMatthew Barth     setProfiles();
69acd737cdSMatthew Barth 
70acd737cdSMatthew Barth     // Load the zone configurations
71603ef164SMatthew Barth     _zones = getConfig<Zone>(false, bus, bus, event, this);
72de90fb4dSMatthew Barth 
73de90fb4dSMatthew Barth     // Load the fan configurations and move each fan into its zone
74603ef164SMatthew Barth     auto fans = getConfig<Fan>(false, bus, bus);
75de90fb4dSMatthew Barth     for (auto& fan : fans)
76de90fb4dSMatthew Barth     {
77de90fb4dSMatthew Barth         auto itZone =
78de90fb4dSMatthew Barth             std::find_if(_zones.begin(), _zones.end(),
79de90fb4dSMatthew Barth                          [&fanZone = fan.second->getZone()](const auto& zone) {
80de90fb4dSMatthew Barth                              return fanZone == zone.second->getName();
81de90fb4dSMatthew Barth                          });
82de90fb4dSMatthew Barth         if (itZone != _zones.end())
83de90fb4dSMatthew Barth         {
846f787309SMatthew Barth             if (itZone->second->getTarget() != fan.second->getTarget() &&
856f787309SMatthew Barth                 fan.second->getTarget() != 0)
866f787309SMatthew Barth             {
876f787309SMatthew Barth                 // Update zone target to current target of the fan in the zone
886f787309SMatthew Barth                 itZone->second->setTarget(fan.second->getTarget());
896f787309SMatthew Barth             }
90de90fb4dSMatthew Barth             itZone->second->addFan(std::move(fan.second));
91de90fb4dSMatthew Barth         }
92de90fb4dSMatthew Barth     }
93b584d818SMatthew Barth 
94*44ab7693SMatthew Barth     // Load the configured groups that are copied into events where they're used
95*44ab7693SMatthew Barth     auto groups = getConfig<Group>(true, bus);
96*44ab7693SMatthew Barth 
97*44ab7693SMatthew Barth     // Load any events configured
98*44ab7693SMatthew Barth     _events = getConfig<Event>(true, bus, bus, groups);
99*44ab7693SMatthew Barth 
100b584d818SMatthew Barth     bus.request_name(CONTROL_BUSNAME);
10106764946SMatthew Barth }
102acd737cdSMatthew Barth 
103acd737cdSMatthew Barth const std::vector<std::string>& Manager::getActiveProfiles()
104acd737cdSMatthew Barth {
105acd737cdSMatthew Barth     return _activeProfiles;
106a227a16dSMatthew Barth }
107a227a16dSMatthew Barth 
10812cb125aSMatthew Barth bool Manager::hasOwner(const std::string& path, const std::string& intf)
10912cb125aSMatthew Barth {
11012cb125aSMatthew Barth     auto itServ = _servTree.find(path);
11112cb125aSMatthew Barth     if (itServ == _servTree.end())
11212cb125aSMatthew Barth     {
11312cb125aSMatthew Barth         // Path not found in cache, therefore owner missing
11412cb125aSMatthew Barth         return false;
11512cb125aSMatthew Barth     }
11612cb125aSMatthew Barth     for (const auto& serv : itServ->second)
11712cb125aSMatthew Barth     {
11812cb125aSMatthew Barth         auto itIntf = std::find_if(
11912cb125aSMatthew Barth             serv.second.begin(), serv.second.end(),
12012cb125aSMatthew Barth             [&intf](const auto& interface) { return intf == interface; });
12112cb125aSMatthew Barth         if (itIntf != std::end(serv.second))
12212cb125aSMatthew Barth         {
12312cb125aSMatthew Barth             // Service found, return owner state
12412cb125aSMatthew Barth             return serv.first.second;
12512cb125aSMatthew Barth         }
12612cb125aSMatthew Barth     }
12712cb125aSMatthew Barth     // Interface not found in cache, therefore owner missing
12812cb125aSMatthew Barth     return false;
12912cb125aSMatthew Barth }
13012cb125aSMatthew Barth 
131d9cb63b6SMatthew Barth void Manager::addTimer(const TimerType type,
132d9cb63b6SMatthew Barth                        const std::chrono::microseconds interval,
133d9cb63b6SMatthew Barth                        std::unique_ptr<TimerPkg> pkg)
134d9cb63b6SMatthew Barth {
135d9cb63b6SMatthew Barth     auto dataPtr =
136d9cb63b6SMatthew Barth         std::make_unique<TimerData>(std::make_pair(type, std::move(*pkg)));
137d9cb63b6SMatthew Barth     Timer timer(_event,
138d9cb63b6SMatthew Barth                 std::bind(&Manager::timerExpired, this, std::ref(*dataPtr)));
139d9cb63b6SMatthew Barth     if (type == TimerType::repeating)
140d9cb63b6SMatthew Barth     {
141d9cb63b6SMatthew Barth         timer.restart(interval);
142d9cb63b6SMatthew Barth     }
143d9cb63b6SMatthew Barth     else if (type == TimerType::oneshot)
144d9cb63b6SMatthew Barth     {
145d9cb63b6SMatthew Barth         timer.restartOnce(interval);
146d9cb63b6SMatthew Barth     }
147d9cb63b6SMatthew Barth     else
148d9cb63b6SMatthew Barth     {
149d9cb63b6SMatthew Barth         throw std::invalid_argument("Invalid Timer Type");
150d9cb63b6SMatthew Barth     }
151d9cb63b6SMatthew Barth     _timers.emplace_back(std::move(dataPtr), std::move(timer));
152d9cb63b6SMatthew Barth }
153d9cb63b6SMatthew Barth 
154d9cb63b6SMatthew Barth void Manager::timerExpired(TimerData& data)
155d9cb63b6SMatthew Barth {
156d9cb63b6SMatthew Barth     auto& actions =
157d9cb63b6SMatthew Barth         std::get<std::vector<std::unique_ptr<ActionBase>>&>(data.second);
158d9cb63b6SMatthew Barth     // Perform the actions in the timer data
159d9cb63b6SMatthew Barth     std::for_each(actions.begin(), actions.end(),
160d9cb63b6SMatthew Barth                   [zone = std::ref(std::get<Zone&>(data.second)),
161d9cb63b6SMatthew Barth                    group = std::cref(std::get<const Group&>(data.second))](
162d9cb63b6SMatthew Barth                       auto& action) { action->run(zone, group); });
163d9cb63b6SMatthew Barth 
164d9cb63b6SMatthew Barth     // Remove oneshot timers after they expired
165d9cb63b6SMatthew Barth     if (data.first == TimerType::oneshot)
166d9cb63b6SMatthew Barth     {
167d9cb63b6SMatthew Barth         auto itTimer = std::find_if(
168d9cb63b6SMatthew Barth             _timers.begin(), _timers.end(), [&data](const auto& timer) {
169d9cb63b6SMatthew Barth                 return (data.first == timer.first->first &&
170d9cb63b6SMatthew Barth                         (std::get<std::string>(data.second) ==
171d9cb63b6SMatthew Barth                          std::get<std::string>(timer.first->second)));
172d9cb63b6SMatthew Barth             });
173d9cb63b6SMatthew Barth         if (itTimer != std::end(_timers))
174d9cb63b6SMatthew Barth         {
175d9cb63b6SMatthew Barth             _timers.erase(itTimer);
176d9cb63b6SMatthew Barth         }
177d9cb63b6SMatthew Barth     }
178d9cb63b6SMatthew Barth }
179d9cb63b6SMatthew Barth 
180a227a16dSMatthew Barth unsigned int Manager::getPowerOnDelay()
181a227a16dSMatthew Barth {
182a227a16dSMatthew Barth     auto powerOnDelay = 0;
183a227a16dSMatthew Barth 
184a227a16dSMatthew Barth     // Parse optional "power_on_delay" from JSON object
185a227a16dSMatthew Barth     if (!_jsonObj.empty() && _jsonObj.contains("power_on_delay"))
186a227a16dSMatthew Barth     {
187a227a16dSMatthew Barth         powerOnDelay = _jsonObj["power_on_delay"].get<unsigned int>();
188a227a16dSMatthew Barth     }
189a227a16dSMatthew Barth 
190a227a16dSMatthew Barth     return powerOnDelay;
191a227a16dSMatthew Barth }
192a227a16dSMatthew Barth 
193acd737cdSMatthew Barth void Manager::setProfiles()
194acd737cdSMatthew Barth {
195acd737cdSMatthew Barth     // Profiles JSON config file is optional
196acd737cdSMatthew Barth     auto confFile = fan::JsonConfig::getConfFile(_bus, confAppName,
197acd737cdSMatthew Barth                                                  Profile::confFileName, true);
198acd737cdSMatthew Barth     if (!confFile.empty())
199acd737cdSMatthew Barth     {
200acd737cdSMatthew Barth         for (const auto& entry : fan::JsonConfig::load(confFile))
201acd737cdSMatthew Barth         {
202acd737cdSMatthew Barth             auto obj = std::make_unique<Profile>(entry);
203acd737cdSMatthew Barth             _profiles.emplace(
204acd737cdSMatthew Barth                 std::make_pair(obj->getName(), obj->getProfiles()),
205acd737cdSMatthew Barth                 std::move(obj));
206acd737cdSMatthew Barth         }
207acd737cdSMatthew Barth     }
208acd737cdSMatthew Barth     // Ensure all configurations use the same set of active profiles
209acd737cdSMatthew Barth     // (In case a profile's active state changes during configuration)
210acd737cdSMatthew Barth     for (const auto& profile : _profiles)
211acd737cdSMatthew Barth     {
212acd737cdSMatthew Barth         if (profile.second->isActive())
213acd737cdSMatthew Barth         {
214acd737cdSMatthew Barth             _activeProfiles.emplace_back(profile.first.first);
215acd737cdSMatthew Barth         }
216acd737cdSMatthew Barth     }
217acd737cdSMatthew Barth }
218acd737cdSMatthew Barth 
219a227a16dSMatthew Barth } // namespace phosphor::fan::control::json
220