blob: 94a39a804e0b1d7392825c73261c56971f6073c9 [file] [log] [blame]
Matthew Bartha227a162020-08-05 10:51:45 -05001/**
2 * Copyright © 2020 IBM Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Matthew Barthb584d812021-03-11 15:55:04 -060016#include "config.h"
17
Matthew Bartha227a162020-08-05 10:51:45 -050018#include "manager.hpp"
19
Matthew Barthd9cb63b2021-03-24 14:36:49 -050020#include "action.hpp"
Matthew Barthde90fb42021-03-04 16:34:28 -060021#include "fan.hpp"
Matthew Barthd9cb63b2021-03-24 14:36:49 -050022#include "group.hpp"
Matthew Bartha227a162020-08-05 10:51:45 -050023#include "json_config.hpp"
Matthew Barth06764942021-03-04 09:28:40 -060024#include "profile.hpp"
Matthew Barthacd737c2021-03-04 11:04:01 -060025#include "zone.hpp"
Matthew Bartha227a162020-08-05 10:51:45 -050026
Matthew Barthacd737c2021-03-04 11:04:01 -060027#include <nlohmann/json.hpp>
Matthew Bartha227a162020-08-05 10:51:45 -050028#include <sdbusplus/bus.hpp>
Matthew Barthacd737c2021-03-04 11:04:01 -060029#include <sdeventplus/event.hpp>
Matthew Barthd9cb63b2021-03-24 14:36:49 -050030#include <sdeventplus/utility/timer.hpp>
Matthew Bartha227a162020-08-05 10:51:45 -050031
Matthew Barthde90fb42021-03-04 16:34:28 -060032#include <algorithm>
Matthew Barthd9cb63b2021-03-24 14:36:49 -050033#include <chrono>
Matthew Bartha227a162020-08-05 10:51:45 -050034#include <filesystem>
Matthew Barthd9cb63b2021-03-24 14:36:49 -050035#include <functional>
36#include <map>
37#include <memory>
38#include <tuple>
39#include <utility>
Matthew Barth06764942021-03-04 09:28:40 -060040#include <vector>
Matthew Bartha227a162020-08-05 10:51:45 -050041
42namespace phosphor::fan::control::json
43{
44
Matthew Barthacd737c2021-03-04 11:04:01 -060045using json = nlohmann::json;
46
47std::vector<std::string> Manager::_activeProfiles;
Matthew Barth12cb1252021-03-08 16:47:30 -060048std::map<std::string,
49 std::map<std::pair<std::string, bool>, std::vector<std::string>>>
50 Manager::_servTree;
Matthew Barth07fecfc2021-01-29 09:04:43 -060051std::map<std::string,
52 std::map<std::string, std::map<std::string, PropertyVariantType>>>
53 Manager::_objects;
Matthew Barthacd737c2021-03-04 11:04:01 -060054
Matthew Barth06764942021-03-04 09:28:40 -060055Manager::Manager(sdbusplus::bus::bus& bus, const sdeventplus::Event& event) :
Matthew Barthacd737c2021-03-04 11:04:01 -060056 _bus(bus), _event(event)
Matthew Bartha227a162020-08-05 10:51:45 -050057{
58 // Manager JSON config file is optional
59 auto confFile =
60 fan::JsonConfig::getConfFile(bus, confAppName, confFileName, true);
61 if (!confFile.empty())
62 {
63 _jsonObj = fan::JsonConfig::load(confFile);
64 }
Matthew Barth06764942021-03-04 09:28:40 -060065
Matthew Barthacd737c2021-03-04 11:04:01 -060066 // Parse and set the available profiles and which are active
67 setProfiles();
68
69 // Load the zone configurations
Matthew Barth603ef162021-03-24 15:34:53 -050070 _zones = getConfig<Zone>(false, bus, bus, event, this);
Matthew Barthde90fb42021-03-04 16:34:28 -060071
72 // Load the fan configurations and move each fan into its zone
Matthew Barth603ef162021-03-24 15:34:53 -050073 auto fans = getConfig<Fan>(false, bus, bus);
Matthew Barthde90fb42021-03-04 16:34:28 -060074 for (auto& fan : fans)
75 {
76 auto itZone =
77 std::find_if(_zones.begin(), _zones.end(),
78 [&fanZone = fan.second->getZone()](const auto& zone) {
79 return fanZone == zone.second->getName();
80 });
81 if (itZone != _zones.end())
82 {
83 itZone->second->addFan(std::move(fan.second));
84 }
85 }
Matthew Barthb584d812021-03-11 15:55:04 -060086
87 bus.request_name(CONTROL_BUSNAME);
Matthew Barthacd737c2021-03-04 11:04:01 -060088}
89
90const std::vector<std::string>& Manager::getActiveProfiles()
91{
92 return _activeProfiles;
Matthew Bartha227a162020-08-05 10:51:45 -050093}
94
Matthew Barth12cb1252021-03-08 16:47:30 -060095bool Manager::hasOwner(const std::string& path, const std::string& intf)
96{
97 auto itServ = _servTree.find(path);
98 if (itServ == _servTree.end())
99 {
100 // Path not found in cache, therefore owner missing
101 return false;
102 }
103 for (const auto& serv : itServ->second)
104 {
105 auto itIntf = std::find_if(
106 serv.second.begin(), serv.second.end(),
107 [&intf](const auto& interface) { return intf == interface; });
108 if (itIntf != std::end(serv.second))
109 {
110 // Service found, return owner state
111 return serv.first.second;
112 }
113 }
114 // Interface not found in cache, therefore owner missing
115 return false;
116}
117
Matthew Barthd9cb63b2021-03-24 14:36:49 -0500118void Manager::addTimer(const TimerType type,
119 const std::chrono::microseconds interval,
120 std::unique_ptr<TimerPkg> pkg)
121{
122 auto dataPtr =
123 std::make_unique<TimerData>(std::make_pair(type, std::move(*pkg)));
124 Timer timer(_event,
125 std::bind(&Manager::timerExpired, this, std::ref(*dataPtr)));
126 if (type == TimerType::repeating)
127 {
128 timer.restart(interval);
129 }
130 else if (type == TimerType::oneshot)
131 {
132 timer.restartOnce(interval);
133 }
134 else
135 {
136 throw std::invalid_argument("Invalid Timer Type");
137 }
138 _timers.emplace_back(std::move(dataPtr), std::move(timer));
139}
140
141void Manager::timerExpired(TimerData& data)
142{
143 auto& actions =
144 std::get<std::vector<std::unique_ptr<ActionBase>>&>(data.second);
145 // Perform the actions in the timer data
146 std::for_each(actions.begin(), actions.end(),
147 [zone = std::ref(std::get<Zone&>(data.second)),
148 group = std::cref(std::get<const Group&>(data.second))](
149 auto& action) { action->run(zone, group); });
150
151 // Remove oneshot timers after they expired
152 if (data.first == TimerType::oneshot)
153 {
154 auto itTimer = std::find_if(
155 _timers.begin(), _timers.end(), [&data](const auto& timer) {
156 return (data.first == timer.first->first &&
157 (std::get<std::string>(data.second) ==
158 std::get<std::string>(timer.first->second)));
159 });
160 if (itTimer != std::end(_timers))
161 {
162 _timers.erase(itTimer);
163 }
164 }
165}
166
Matthew Bartha227a162020-08-05 10:51:45 -0500167unsigned int Manager::getPowerOnDelay()
168{
169 auto powerOnDelay = 0;
170
171 // Parse optional "power_on_delay" from JSON object
172 if (!_jsonObj.empty() && _jsonObj.contains("power_on_delay"))
173 {
174 powerOnDelay = _jsonObj["power_on_delay"].get<unsigned int>();
175 }
176
177 return powerOnDelay;
178}
179
Matthew Barthacd737c2021-03-04 11:04:01 -0600180void Manager::setProfiles()
181{
182 // Profiles JSON config file is optional
183 auto confFile = fan::JsonConfig::getConfFile(_bus, confAppName,
184 Profile::confFileName, true);
185 if (!confFile.empty())
186 {
187 for (const auto& entry : fan::JsonConfig::load(confFile))
188 {
189 auto obj = std::make_unique<Profile>(entry);
190 _profiles.emplace(
191 std::make_pair(obj->getName(), obj->getProfiles()),
192 std::move(obj));
193 }
194 }
195 // Ensure all configurations use the same set of active profiles
196 // (In case a profile's active state changes during configuration)
197 for (const auto& profile : _profiles)
198 {
199 if (profile.second->isActive())
200 {
201 _activeProfiles.emplace_back(profile.first.first);
202 }
203 }
204}
205
Matthew Bartha227a162020-08-05 10:51:45 -0500206} // namespace phosphor::fan::control::json