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" 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 { 770206c728SMatthew Barth configKey fanProfile = 780206c728SMatthew Barth std::make_pair(fan.second->getZone(), fan.first.second); 790206c728SMatthew Barth auto itZone = std::find_if( 800206c728SMatthew Barth _zones.begin(), _zones.end(), [&fanProfile](const auto& zone) { 810206c728SMatthew Barth return Manager::inConfig(fanProfile, zone.first); 82de90fb4dSMatthew Barth }); 83de90fb4dSMatthew Barth if (itZone != _zones.end()) 84de90fb4dSMatthew Barth { 856f787309SMatthew Barth if (itZone->second->getTarget() != fan.second->getTarget() && 866f787309SMatthew Barth fan.second->getTarget() != 0) 876f787309SMatthew Barth { 886f787309SMatthew Barth // Update zone target to current target of the fan in the zone 896f787309SMatthew Barth itZone->second->setTarget(fan.second->getTarget()); 906f787309SMatthew Barth } 91de90fb4dSMatthew Barth itZone->second->addFan(std::move(fan.second)); 92de90fb4dSMatthew Barth } 93de90fb4dSMatthew Barth } 94b584d818SMatthew Barth 9544ab7693SMatthew Barth // Load the configured groups that are copied into events where they're used 9644ab7693SMatthew Barth auto groups = getConfig<Group>(true, bus); 9744ab7693SMatthew Barth 9844ab7693SMatthew Barth // Load any events configured 999f1632e5SMatthew Barth _events = getConfig<Event>(true, bus, bus, groups, _zones); 10044ab7693SMatthew Barth 101b584d818SMatthew Barth bus.request_name(CONTROL_BUSNAME); 10206764946SMatthew Barth } 103acd737cdSMatthew Barth 104acd737cdSMatthew Barth const std::vector<std::string>& Manager::getActiveProfiles() 105acd737cdSMatthew Barth { 106acd737cdSMatthew Barth return _activeProfiles; 107a227a16dSMatthew Barth } 108a227a16dSMatthew Barth 1090206c728SMatthew Barth bool Manager::inConfig(const configKey& input, const configKey& comp) 1100206c728SMatthew Barth { 1110206c728SMatthew Barth // Config names dont match, do not include in config 1120206c728SMatthew Barth if (input.first != comp.first) 1130206c728SMatthew Barth { 1140206c728SMatthew Barth return false; 1150206c728SMatthew Barth } 1160206c728SMatthew Barth // No profiles specified by input config, can be used in any config 1170206c728SMatthew Barth if (input.second.empty()) 1180206c728SMatthew Barth { 1190206c728SMatthew Barth return true; 1200206c728SMatthew Barth } 1210206c728SMatthew Barth else 1220206c728SMatthew Barth { 1230206c728SMatthew Barth // Profiles must have one match in the other's profiles(and they must be 1240206c728SMatthew Barth // an active profile) to be used in the config 1250206c728SMatthew Barth return std::any_of( 1260206c728SMatthew Barth input.second.begin(), input.second.end(), 1270206c728SMatthew Barth [&comp](const auto& lProfile) { 1280206c728SMatthew Barth return std::any_of( 1290206c728SMatthew Barth comp.second.begin(), comp.second.end(), 1300206c728SMatthew Barth [&lProfile](const auto& rProfile) { 1310206c728SMatthew Barth if (lProfile != rProfile) 1320206c728SMatthew Barth { 1330206c728SMatthew Barth return false; 1340206c728SMatthew Barth } 1350206c728SMatthew Barth auto activeProfs = getActiveProfiles(); 1360206c728SMatthew Barth return std::find(activeProfs.begin(), activeProfs.end(), 1370206c728SMatthew Barth lProfile) != activeProfs.end(); 1380206c728SMatthew Barth }); 1390206c728SMatthew Barth }); 1400206c728SMatthew Barth } 1410206c728SMatthew Barth } 1420206c728SMatthew Barth 14312cb125aSMatthew Barth bool Manager::hasOwner(const std::string& path, const std::string& intf) 14412cb125aSMatthew Barth { 14512cb125aSMatthew Barth auto itServ = _servTree.find(path); 14612cb125aSMatthew Barth if (itServ == _servTree.end()) 14712cb125aSMatthew Barth { 14812cb125aSMatthew Barth // Path not found in cache, therefore owner missing 14912cb125aSMatthew Barth return false; 15012cb125aSMatthew Barth } 15112cb125aSMatthew Barth for (const auto& serv : itServ->second) 15212cb125aSMatthew Barth { 15312cb125aSMatthew Barth auto itIntf = std::find_if( 15412cb125aSMatthew Barth serv.second.begin(), serv.second.end(), 15512cb125aSMatthew Barth [&intf](const auto& interface) { return intf == interface; }); 15612cb125aSMatthew Barth if (itIntf != std::end(serv.second)) 15712cb125aSMatthew Barth { 15812cb125aSMatthew Barth // Service found, return owner state 15912cb125aSMatthew Barth return serv.first.second; 16012cb125aSMatthew Barth } 16112cb125aSMatthew Barth } 16212cb125aSMatthew Barth // Interface not found in cache, therefore owner missing 16312cb125aSMatthew Barth return false; 16412cb125aSMatthew Barth } 16512cb125aSMatthew Barth 166d9cb63b6SMatthew Barth void Manager::addTimer(const TimerType type, 167d9cb63b6SMatthew Barth const std::chrono::microseconds interval, 168d9cb63b6SMatthew Barth std::unique_ptr<TimerPkg> pkg) 169d9cb63b6SMatthew Barth { 170d9cb63b6SMatthew Barth auto dataPtr = 171d9cb63b6SMatthew Barth std::make_unique<TimerData>(std::make_pair(type, std::move(*pkg))); 172d9cb63b6SMatthew Barth Timer timer(_event, 173d9cb63b6SMatthew Barth std::bind(&Manager::timerExpired, this, std::ref(*dataPtr))); 174d9cb63b6SMatthew Barth if (type == TimerType::repeating) 175d9cb63b6SMatthew Barth { 176d9cb63b6SMatthew Barth timer.restart(interval); 177d9cb63b6SMatthew Barth } 178d9cb63b6SMatthew Barth else if (type == TimerType::oneshot) 179d9cb63b6SMatthew Barth { 180d9cb63b6SMatthew Barth timer.restartOnce(interval); 181d9cb63b6SMatthew Barth } 182d9cb63b6SMatthew Barth else 183d9cb63b6SMatthew Barth { 184d9cb63b6SMatthew Barth throw std::invalid_argument("Invalid Timer Type"); 185d9cb63b6SMatthew Barth } 186d9cb63b6SMatthew Barth _timers.emplace_back(std::move(dataPtr), std::move(timer)); 187d9cb63b6SMatthew Barth } 188d9cb63b6SMatthew Barth 189d9cb63b6SMatthew Barth void Manager::timerExpired(TimerData& data) 190d9cb63b6SMatthew Barth { 191d9cb63b6SMatthew Barth auto& actions = 192d9cb63b6SMatthew Barth std::get<std::vector<std::unique_ptr<ActionBase>>&>(data.second); 193d9cb63b6SMatthew Barth // Perform the actions in the timer data 194d9cb63b6SMatthew Barth std::for_each(actions.begin(), actions.end(), 195*00f6aa09SMatthew Barth [](auto& action) { action->run(); }); 196d9cb63b6SMatthew Barth 197d9cb63b6SMatthew Barth // Remove oneshot timers after they expired 198d9cb63b6SMatthew Barth if (data.first == TimerType::oneshot) 199d9cb63b6SMatthew Barth { 200d9cb63b6SMatthew Barth auto itTimer = std::find_if( 201d9cb63b6SMatthew Barth _timers.begin(), _timers.end(), [&data](const auto& timer) { 202d9cb63b6SMatthew Barth return (data.first == timer.first->first && 203d9cb63b6SMatthew Barth (std::get<std::string>(data.second) == 204d9cb63b6SMatthew Barth std::get<std::string>(timer.first->second))); 205d9cb63b6SMatthew Barth }); 206d9cb63b6SMatthew Barth if (itTimer != std::end(_timers)) 207d9cb63b6SMatthew Barth { 208d9cb63b6SMatthew Barth _timers.erase(itTimer); 209d9cb63b6SMatthew Barth } 210d9cb63b6SMatthew Barth } 211d9cb63b6SMatthew Barth } 212d9cb63b6SMatthew Barth 213a227a16dSMatthew Barth unsigned int Manager::getPowerOnDelay() 214a227a16dSMatthew Barth { 215a227a16dSMatthew Barth auto powerOnDelay = 0; 216a227a16dSMatthew Barth 217a227a16dSMatthew Barth // Parse optional "power_on_delay" from JSON object 218a227a16dSMatthew Barth if (!_jsonObj.empty() && _jsonObj.contains("power_on_delay")) 219a227a16dSMatthew Barth { 220a227a16dSMatthew Barth powerOnDelay = _jsonObj["power_on_delay"].get<unsigned int>(); 221a227a16dSMatthew Barth } 222a227a16dSMatthew Barth 223a227a16dSMatthew Barth return powerOnDelay; 224a227a16dSMatthew Barth } 225a227a16dSMatthew Barth 226acd737cdSMatthew Barth void Manager::setProfiles() 227acd737cdSMatthew Barth { 228acd737cdSMatthew Barth // Profiles JSON config file is optional 229acd737cdSMatthew Barth auto confFile = fan::JsonConfig::getConfFile(_bus, confAppName, 230acd737cdSMatthew Barth Profile::confFileName, true); 231acd737cdSMatthew Barth if (!confFile.empty()) 232acd737cdSMatthew Barth { 233acd737cdSMatthew Barth for (const auto& entry : fan::JsonConfig::load(confFile)) 234acd737cdSMatthew Barth { 235acd737cdSMatthew Barth auto obj = std::make_unique<Profile>(entry); 236acd737cdSMatthew Barth _profiles.emplace( 237acd737cdSMatthew Barth std::make_pair(obj->getName(), obj->getProfiles()), 238acd737cdSMatthew Barth std::move(obj)); 239acd737cdSMatthew Barth } 240acd737cdSMatthew Barth } 241acd737cdSMatthew Barth // Ensure all configurations use the same set of active profiles 242acd737cdSMatthew Barth // (In case a profile's active state changes during configuration) 243acd737cdSMatthew Barth for (const auto& profile : _profiles) 244acd737cdSMatthew Barth { 245acd737cdSMatthew Barth if (profile.second->isActive()) 246acd737cdSMatthew Barth { 247acd737cdSMatthew Barth _activeProfiles.emplace_back(profile.first.first); 248acd737cdSMatthew Barth } 249acd737cdSMatthew Barth } 250acd737cdSMatthew Barth } 251acd737cdSMatthew Barth 252a227a16dSMatthew Barth } // namespace phosphor::fan::control::json 253