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