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 202fc0a35dSMatt Spinler #include "../utils/flight_recorder.hpp" 21d9cb63b6SMatthew Barth #include "action.hpp" 2244ab7693SMatthew Barth #include "event.hpp" 23de90fb4dSMatthew Barth #include "fan.hpp" 24d9cb63b6SMatthew Barth #include "group.hpp" 25a227a16dSMatthew Barth #include "json_config.hpp" 2648f44daaSMatthew Barth #include "power_state.hpp" 2706764946SMatthew Barth #include "profile.hpp" 289403a217SMatthew Barth #include "sdbusplus.hpp" 29acd737cdSMatthew Barth #include "zone.hpp" 30a227a16dSMatthew Barth 31acd737cdSMatthew Barth #include <nlohmann/json.hpp> 32a227a16dSMatthew Barth #include <sdbusplus/bus.hpp> 331542fb5aSMatthew Barth #include <sdbusplus/server/manager.hpp> 34acd737cdSMatthew Barth #include <sdeventplus/event.hpp> 35d9cb63b6SMatthew Barth #include <sdeventplus/utility/timer.hpp> 36a227a16dSMatthew Barth 37de90fb4dSMatthew Barth #include <algorithm> 38d9cb63b6SMatthew Barth #include <chrono> 39a227a16dSMatthew Barth #include <filesystem> 40d9cb63b6SMatthew Barth #include <functional> 41d9cb63b6SMatthew Barth #include <map> 42d9cb63b6SMatthew Barth #include <memory> 43d9cb63b6SMatthew Barth #include <tuple> 44d9cb63b6SMatthew Barth #include <utility> 4506764946SMatthew Barth #include <vector> 46a227a16dSMatthew Barth 47a227a16dSMatthew Barth namespace phosphor::fan::control::json 48a227a16dSMatthew Barth { 49a227a16dSMatthew Barth 50acd737cdSMatthew Barth using json = nlohmann::json; 51acd737cdSMatthew Barth 52acd737cdSMatthew Barth std::vector<std::string> Manager::_activeProfiles; 5312cb125aSMatthew Barth std::map<std::string, 544ca87faeSMatthew Barth std::map<std::string, std::pair<bool, std::vector<std::string>>>> 5512cb125aSMatthew Barth Manager::_servTree; 5607fecfc6SMatthew Barth std::map<std::string, 5707fecfc6SMatthew Barth std::map<std::string, std::map<std::string, PropertyVariantType>>> 5807fecfc6SMatthew Barth Manager::_objects; 59d76351bdSMatt Spinler std::unordered_map<std::string, PropertyVariantType> Manager::_parameters; 60acd737cdSMatthew Barth 617787def0SMatt Spinler const std::string Manager::dumpFile = "/tmp/fan_control_dump.json"; 627787def0SMatt Spinler 639403a217SMatthew Barth Manager::Manager(const sdeventplus::Event& event) : 6448f44daaSMatthew Barth _bus(util::SDBusPlus::getBus()), _event(event), 653770a1daSMatthew Barth _mgr(util::SDBusPlus::getBus(), CONTROL_OBJPATH), _loadAllowed(true), 6648f44daaSMatthew Barth _powerState(std::make_unique<PGoodState>( 6748f44daaSMatthew Barth util::SDBusPlus::getBus(), 6848f44daaSMatthew Barth std::bind(std::mem_fn(&Manager::powerStateChanged), this, 6948f44daaSMatthew Barth std::placeholders::_1))) 703770a1daSMatthew Barth {} 71e91ac864SMatthew Barth 72e91ac864SMatthew Barth void Manager::sighupHandler(sdeventplus::source::Signal&, 73e91ac864SMatthew Barth const struct signalfd_siginfo*) 74e91ac864SMatthew Barth { 75e91ac864SMatthew Barth // Save current set of available and active profiles 76e91ac864SMatthew Barth std::map<configKey, std::unique_ptr<Profile>> profiles; 77e91ac864SMatthew Barth profiles.swap(_profiles); 78e91ac864SMatthew Barth std::vector<std::string> activeProfiles; 79e91ac864SMatthew Barth activeProfiles.swap(_activeProfiles); 80e91ac864SMatthew Barth 81e91ac864SMatthew Barth try 82e91ac864SMatthew Barth { 833770a1daSMatthew Barth _loadAllowed = true; 84e91ac864SMatthew Barth load(); 85e91ac864SMatthew Barth } 86ddb773b2SPatrick Williams catch (const std::runtime_error& re) 87e91ac864SMatthew Barth { 88e91ac864SMatthew Barth // Restore saved available and active profiles 893770a1daSMatthew Barth _loadAllowed = false; 90e91ac864SMatthew Barth _profiles.swap(profiles); 91e91ac864SMatthew Barth _activeProfiles.swap(activeProfiles); 92e91ac864SMatthew Barth log<level::ERR>("Error reloading configs, no changes made", 93e91ac864SMatthew Barth entry("LOAD_ERROR=%s", re.what())); 94e91ac864SMatthew Barth } 95e91ac864SMatthew Barth } 96e91ac864SMatthew Barth 972fc0a35dSMatt Spinler void Manager::sigUsr1Handler(sdeventplus::source::Signal&, 982fc0a35dSMatt Spinler const struct signalfd_siginfo*) 992fc0a35dSMatt Spinler { 1007787def0SMatt Spinler debugDumpEventSource = std::make_unique<sdeventplus::source::Defer>( 1017787def0SMatt Spinler _event, std::bind(std::mem_fn(&Manager::dumpDebugData), this, 1022fc0a35dSMatt Spinler std::placeholders::_1)); 1032fc0a35dSMatt Spinler } 1042fc0a35dSMatt Spinler 1057787def0SMatt Spinler void Manager::dumpDebugData(sdeventplus::source::EventBase& /*source*/) 1062fc0a35dSMatt Spinler { 1077787def0SMatt Spinler json data; 1087787def0SMatt Spinler FlightRecorder::instance().dump(data); 109b5c21a24SMatt Spinler dumpCache(data); 1107787def0SMatt Spinler 1119db6dd1dSMatt Spinler std::for_each(_zones.begin(), _zones.end(), [&data](const auto& zone) { 1129db6dd1dSMatt Spinler data["zones"][zone.second->getName()] = zone.second->dump(); 1139db6dd1dSMatt Spinler }); 1149db6dd1dSMatt Spinler 1157787def0SMatt Spinler std::ofstream file{Manager::dumpFile}; 1167787def0SMatt Spinler if (!file) 1177787def0SMatt Spinler { 1187787def0SMatt Spinler log<level::ERR>("Could not open file for fan dump"); 1197787def0SMatt Spinler return; 1207787def0SMatt Spinler } 1217787def0SMatt Spinler 1227787def0SMatt Spinler file << std::setw(4) << data; 1237787def0SMatt Spinler 1247787def0SMatt Spinler debugDumpEventSource.reset(); 1252fc0a35dSMatt Spinler } 1262fc0a35dSMatt Spinler 127b5c21a24SMatt Spinler void Manager::dumpCache(json& data) 128b5c21a24SMatt Spinler { 129b5c21a24SMatt Spinler auto& objects = data["objects"]; 130b5c21a24SMatt Spinler for (const auto& [path, interfaces] : _objects) 131b5c21a24SMatt Spinler { 132b5c21a24SMatt Spinler auto& interfaceJSON = objects[path]; 133b5c21a24SMatt Spinler 134b5c21a24SMatt Spinler for (const auto& [interface, properties] : interfaces) 135b5c21a24SMatt Spinler { 136b5c21a24SMatt Spinler auto& propertyJSON = interfaceJSON[interface]; 137b5c21a24SMatt Spinler for (const auto& [propName, propValue] : properties) 138b5c21a24SMatt Spinler { 139b5c21a24SMatt Spinler std::visit( 140b5c21a24SMatt Spinler [&obj = propertyJSON[propName]](auto&& val) { obj = val; }, 141b5c21a24SMatt Spinler propValue); 142b5c21a24SMatt Spinler } 143b5c21a24SMatt Spinler } 144b5c21a24SMatt Spinler } 145b5c21a24SMatt Spinler 146b5c21a24SMatt Spinler auto& parameters = data["parameters"]; 147b5c21a24SMatt Spinler for (const auto& [name, value] : _parameters) 148b5c21a24SMatt Spinler { 149b5c21a24SMatt Spinler std::visit([&obj = parameters["name"]](auto&& val) { obj = val; }, 150b5c21a24SMatt Spinler value); 151b5c21a24SMatt Spinler } 152b5c21a24SMatt Spinler 153b5c21a24SMatt Spinler data["services"] = _servTree; 154b5c21a24SMatt Spinler } 155b5c21a24SMatt Spinler 156e91ac864SMatthew Barth void Manager::load() 157e91ac864SMatthew Barth { 1583770a1daSMatthew Barth if (_loadAllowed) 1593770a1daSMatthew Barth { 160e91ac864SMatthew Barth // Load the available profiles and which are active 161acd737cdSMatthew Barth setProfiles(); 162acd737cdSMatthew Barth 163acd737cdSMatthew Barth // Load the zone configurations 164e91ac864SMatthew Barth auto zones = getConfig<Zone>(false, _event, this); 165de90fb4dSMatthew Barth // Load the fan configurations and move each fan into its zone 1669403a217SMatthew Barth auto fans = getConfig<Fan>(false); 167de90fb4dSMatthew Barth for (auto& fan : fans) 168de90fb4dSMatthew Barth { 1690206c728SMatthew Barth configKey fanProfile = 1700206c728SMatthew Barth std::make_pair(fan.second->getZone(), fan.first.second); 1710206c728SMatthew Barth auto itZone = std::find_if( 172e91ac864SMatthew Barth zones.begin(), zones.end(), [&fanProfile](const auto& zone) { 1730206c728SMatthew Barth return Manager::inConfig(fanProfile, zone.first); 174de90fb4dSMatthew Barth }); 175e91ac864SMatthew Barth if (itZone != zones.end()) 176de90fb4dSMatthew Barth { 1776f787309SMatthew Barth if (itZone->second->getTarget() != fan.second->getTarget() && 1786f787309SMatthew Barth fan.second->getTarget() != 0) 1796f787309SMatthew Barth { 180e91ac864SMatthew Barth // Update zone target to current target of the fan in the 181e91ac864SMatthew Barth // zone 1826f787309SMatthew Barth itZone->second->setTarget(fan.second->getTarget()); 1836f787309SMatthew Barth } 184de90fb4dSMatthew Barth itZone->second->addFan(std::move(fan.second)); 185de90fb4dSMatthew Barth } 186de90fb4dSMatthew Barth } 187e91ac864SMatthew Barth 1883695ac30SMatthew Barth // Save all currently available groups, if any, then clear for reloading 1893695ac30SMatthew Barth auto groups = std::move(Event::getAllGroups(false)); 1903695ac30SMatthew Barth Event::clearAllGroups(); 1913695ac30SMatthew Barth 1923695ac30SMatthew Barth std::map<configKey, std::unique_ptr<Event>> events; 1933695ac30SMatthew Barth try 1943695ac30SMatthew Barth { 1953695ac30SMatthew Barth // Load any events configured, including all the groups 1963695ac30SMatthew Barth events = getConfig<Event>(true, this, zones); 1973695ac30SMatthew Barth } 1983695ac30SMatthew Barth catch (const std::runtime_error& re) 1993695ac30SMatthew Barth { 2003695ac30SMatthew Barth // Restore saved set of all available groups for current events 2013695ac30SMatthew Barth Event::setAllGroups(std::move(groups)); 2023695ac30SMatthew Barth throw re; 2033695ac30SMatthew Barth } 204e91ac864SMatthew Barth 20514303a45SMatthew Barth // Enable zones 206e91ac864SMatthew Barth _zones = std::move(zones); 20714303a45SMatthew Barth std::for_each(_zones.begin(), _zones.end(), 20814303a45SMatthew Barth [](const auto& entry) { entry.second->enable(); }); 209b584d818SMatthew Barth 210e91ac864SMatthew Barth // Clear current timers and signal subscriptions before enabling events 2113770a1daSMatthew Barth // To save reloading services and/or objects into cache, do not clear 2123770a1daSMatthew Barth // cache 213e91ac864SMatthew Barth _timers.clear(); 214e91ac864SMatthew Barth _signals.clear(); 215e91ac864SMatthew Barth 216e91ac864SMatthew Barth // Enable events 217e91ac864SMatthew Barth _events = std::move(events); 21854b5a24fSMatthew Barth std::for_each(_events.begin(), _events.end(), 21954b5a24fSMatthew Barth [](const auto& entry) { entry.second->enable(); }); 2203770a1daSMatthew Barth 2213770a1daSMatthew Barth _loadAllowed = false; 2223770a1daSMatthew Barth } 22306764946SMatthew Barth } 224acd737cdSMatthew Barth 22548f44daaSMatthew Barth void Manager::powerStateChanged(bool powerStateOn) 22648f44daaSMatthew Barth { 22748f44daaSMatthew Barth if (powerStateOn) 22848f44daaSMatthew Barth { 2296a2418a2SMatthew Barth if (_zones.empty()) 2306a2418a2SMatthew Barth { 2316a2418a2SMatthew Barth throw std::runtime_error("No configured zones found at poweron"); 2326a2418a2SMatthew Barth } 23348f44daaSMatthew Barth std::for_each(_zones.begin(), _zones.end(), [](const auto& entry) { 23448f44daaSMatthew Barth entry.second->setTarget(entry.second->getPoweronTarget()); 23548f44daaSMatthew Barth }); 23648f44daaSMatthew Barth } 23748f44daaSMatthew Barth } 23848f44daaSMatthew Barth 239acd737cdSMatthew Barth const std::vector<std::string>& Manager::getActiveProfiles() 240acd737cdSMatthew Barth { 241acd737cdSMatthew Barth return _activeProfiles; 242a227a16dSMatthew Barth } 243a227a16dSMatthew Barth 2440206c728SMatthew Barth bool Manager::inConfig(const configKey& input, const configKey& comp) 2450206c728SMatthew Barth { 2460206c728SMatthew Barth // Config names dont match, do not include in config 2470206c728SMatthew Barth if (input.first != comp.first) 2480206c728SMatthew Barth { 2490206c728SMatthew Barth return false; 2500206c728SMatthew Barth } 2510206c728SMatthew Barth // No profiles specified by input config, can be used in any config 2520206c728SMatthew Barth if (input.second.empty()) 2530206c728SMatthew Barth { 2540206c728SMatthew Barth return true; 2550206c728SMatthew Barth } 2560206c728SMatthew Barth else 2570206c728SMatthew Barth { 2580206c728SMatthew Barth // Profiles must have one match in the other's profiles(and they must be 2590206c728SMatthew Barth // an active profile) to be used in the config 2600206c728SMatthew Barth return std::any_of( 2610206c728SMatthew Barth input.second.begin(), input.second.end(), 2620206c728SMatthew Barth [&comp](const auto& lProfile) { 2630206c728SMatthew Barth return std::any_of( 2640206c728SMatthew Barth comp.second.begin(), comp.second.end(), 2650206c728SMatthew Barth [&lProfile](const auto& rProfile) { 2660206c728SMatthew Barth if (lProfile != rProfile) 2670206c728SMatthew Barth { 2680206c728SMatthew Barth return false; 2690206c728SMatthew Barth } 2700206c728SMatthew Barth auto activeProfs = getActiveProfiles(); 2710206c728SMatthew Barth return std::find(activeProfs.begin(), activeProfs.end(), 2720206c728SMatthew Barth lProfile) != activeProfs.end(); 2730206c728SMatthew Barth }); 2740206c728SMatthew Barth }); 2750206c728SMatthew Barth } 2760206c728SMatthew Barth } 2770206c728SMatthew Barth 27812cb125aSMatthew Barth bool Manager::hasOwner(const std::string& path, const std::string& intf) 27912cb125aSMatthew Barth { 28012cb125aSMatthew Barth auto itServ = _servTree.find(path); 28112cb125aSMatthew Barth if (itServ == _servTree.end()) 28212cb125aSMatthew Barth { 28312cb125aSMatthew Barth // Path not found in cache, therefore owner missing 28412cb125aSMatthew Barth return false; 28512cb125aSMatthew Barth } 2864ca87faeSMatthew Barth for (const auto& service : itServ->second) 28712cb125aSMatthew Barth { 28812cb125aSMatthew Barth auto itIntf = std::find_if( 2894ca87faeSMatthew Barth service.second.second.begin(), service.second.second.end(), 29012cb125aSMatthew Barth [&intf](const auto& interface) { return intf == interface; }); 2914ca87faeSMatthew Barth if (itIntf != std::end(service.second.second)) 29212cb125aSMatthew Barth { 29312cb125aSMatthew Barth // Service found, return owner state 2944ca87faeSMatthew Barth return service.second.first; 29512cb125aSMatthew Barth } 29612cb125aSMatthew Barth } 29712cb125aSMatthew Barth // Interface not found in cache, therefore owner missing 29812cb125aSMatthew Barth return false; 29912cb125aSMatthew Barth } 30012cb125aSMatthew Barth 3014ca87faeSMatthew Barth void Manager::setOwner(const std::string& path, const std::string& serv, 3024ca87faeSMatthew Barth const std::string& intf, bool isOwned) 3034ca87faeSMatthew Barth { 3042a9e7b2eSMatthew Barth // Set owner state for specific object given 3052a9e7b2eSMatthew Barth auto& ownIntf = _servTree[path][serv]; 3062a9e7b2eSMatthew Barth ownIntf.first = isOwned; 3074ca87faeSMatthew Barth auto itIntf = std::find_if( 3082a9e7b2eSMatthew Barth ownIntf.second.begin(), ownIntf.second.end(), 3094ca87faeSMatthew Barth [&intf](const auto& interface) { return intf == interface; }); 3102a9e7b2eSMatthew Barth if (itIntf == std::end(ownIntf.second)) 3114ca87faeSMatthew Barth { 3122a9e7b2eSMatthew Barth ownIntf.second.emplace_back(intf); 3132a9e7b2eSMatthew Barth } 3142a9e7b2eSMatthew Barth 3152a9e7b2eSMatthew Barth // Update owner state on all entries of the same `serv` & `intf` 3162a9e7b2eSMatthew Barth for (auto& itPath : _servTree) 3174ca87faeSMatthew Barth { 3182a9e7b2eSMatthew Barth if (itPath.first == path) 3192a9e7b2eSMatthew Barth { 3202a9e7b2eSMatthew Barth // Already set/updated owner on this path for `serv` & `intf` 3212a9e7b2eSMatthew Barth continue; 3222a9e7b2eSMatthew Barth } 3232a9e7b2eSMatthew Barth for (auto& itServ : itPath.second) 3242a9e7b2eSMatthew Barth { 3252a9e7b2eSMatthew Barth if (itServ.first != serv) 3262a9e7b2eSMatthew Barth { 3272a9e7b2eSMatthew Barth continue; 3282a9e7b2eSMatthew Barth } 3292a9e7b2eSMatthew Barth auto itIntf = std::find_if( 3302a9e7b2eSMatthew Barth itServ.second.second.begin(), itServ.second.second.end(), 3312a9e7b2eSMatthew Barth [&intf](const auto& interface) { return intf == interface; }); 3322a9e7b2eSMatthew Barth if (itIntf != std::end(itServ.second.second)) 3332a9e7b2eSMatthew Barth { 3342a9e7b2eSMatthew Barth itServ.second.first = isOwned; 3354ca87faeSMatthew Barth } 3364ca87faeSMatthew Barth } 3374ca87faeSMatthew Barth } 3384ca87faeSMatthew Barth } 3394ca87faeSMatthew Barth 3404ca87faeSMatthew Barth const std::string& Manager::findService(const std::string& path, 3414ca87faeSMatthew Barth const std::string& intf) 3424ca87faeSMatthew Barth { 3434ca87faeSMatthew Barth static const std::string empty = ""; 3444ca87faeSMatthew Barth 3454ca87faeSMatthew Barth auto itServ = _servTree.find(path); 3464ca87faeSMatthew Barth if (itServ != _servTree.end()) 3474ca87faeSMatthew Barth { 3484ca87faeSMatthew Barth for (const auto& service : itServ->second) 3494ca87faeSMatthew Barth { 3504ca87faeSMatthew Barth auto itIntf = std::find_if( 3514ca87faeSMatthew Barth service.second.second.begin(), service.second.second.end(), 3524ca87faeSMatthew Barth [&intf](const auto& interface) { return intf == interface; }); 3534ca87faeSMatthew Barth if (itIntf != std::end(service.second.second)) 3544ca87faeSMatthew Barth { 3554ca87faeSMatthew Barth // Service found, return service name 3564ca87faeSMatthew Barth return service.first; 3574ca87faeSMatthew Barth } 3584ca87faeSMatthew Barth } 3594ca87faeSMatthew Barth } 3604ca87faeSMatthew Barth 3614ca87faeSMatthew Barth return empty; 3624ca87faeSMatthew Barth } 3634ca87faeSMatthew Barth 36498f6fc17SMatthew Barth void Manager::addServices(const std::string& intf, int32_t depth) 3654ca87faeSMatthew Barth { 3664ca87faeSMatthew Barth // Get all subtree objects for the given interface 36734835150SMatt Spinler auto objects = util::SDBusPlus::getSubTreeRaw(util::SDBusPlus::getBus(), 36834835150SMatt Spinler "/", intf, depth); 3694ca87faeSMatthew Barth // Add what's returned to the cache of path->services 3704ca87faeSMatthew Barth for (auto& itPath : objects) 3714ca87faeSMatthew Barth { 3724ca87faeSMatthew Barth auto pathIter = _servTree.find(itPath.first); 3734ca87faeSMatthew Barth if (pathIter != _servTree.end()) 3744ca87faeSMatthew Barth { 3754ca87faeSMatthew Barth // Path found in cache 3764ca87faeSMatthew Barth for (auto& itServ : itPath.second) 3774ca87faeSMatthew Barth { 3784ca87faeSMatthew Barth auto servIter = pathIter->second.find(itServ.first); 3794ca87faeSMatthew Barth if (servIter != pathIter->second.end()) 3804ca87faeSMatthew Barth { 3814ca87faeSMatthew Barth // Service found in cache 3824ca87faeSMatthew Barth for (auto& itIntf : itServ.second) 3834ca87faeSMatthew Barth { 3844ca87faeSMatthew Barth if (std::find(servIter->second.second.begin(), 3854ca87faeSMatthew Barth servIter->second.second.end(), 3864ca87faeSMatthew Barth itIntf) == servIter->second.second.end()) 3874ca87faeSMatthew Barth { 3884ca87faeSMatthew Barth // Add interface to cache 3894ca87faeSMatthew Barth servIter->second.second.emplace_back(itIntf); 3904ca87faeSMatthew Barth } 3914ca87faeSMatthew Barth } 3924ca87faeSMatthew Barth } 3934ca87faeSMatthew Barth else 3944ca87faeSMatthew Barth { 3954ca87faeSMatthew Barth // Service not found in cache 3964ca87faeSMatthew Barth auto intfs = {intf}; 3974ca87faeSMatthew Barth pathIter->second[itServ.first] = 3984ca87faeSMatthew Barth std::make_pair(true, intfs); 3994ca87faeSMatthew Barth } 4004ca87faeSMatthew Barth } 4014ca87faeSMatthew Barth } 4024ca87faeSMatthew Barth else 4034ca87faeSMatthew Barth { 4044ca87faeSMatthew Barth // Path not found in cache 4054ca87faeSMatthew Barth auto intfs = {intf}; 4064ca87faeSMatthew Barth _servTree[itPath.first] = { 4074ca87faeSMatthew Barth {itPath.second.begin()->first, std::make_pair(true, intfs)}}; 4084ca87faeSMatthew Barth } 4094ca87faeSMatthew Barth } 4104ca87faeSMatthew Barth } 4114ca87faeSMatthew Barth 4124ca87faeSMatthew Barth const std::string& Manager::getService(const std::string& path, 4134ca87faeSMatthew Barth const std::string& intf) 4144ca87faeSMatthew Barth { 4154ca87faeSMatthew Barth // Retrieve service from cache 4164ca87faeSMatthew Barth const auto& serviceName = findService(path, intf); 4174ca87faeSMatthew Barth if (serviceName.empty()) 4184ca87faeSMatthew Barth { 41998f6fc17SMatthew Barth addServices(intf, 0); 4204ca87faeSMatthew Barth return findService(path, intf); 4214ca87faeSMatthew Barth } 4224ca87faeSMatthew Barth 4234ca87faeSMatthew Barth return serviceName; 4244ca87faeSMatthew Barth } 4254ca87faeSMatthew Barth 426f41e947bSMatthew Barth std::vector<std::string> Manager::findPaths(const std::string& serv, 427f41e947bSMatthew Barth const std::string& intf) 428f41e947bSMatthew Barth { 429f41e947bSMatthew Barth std::vector<std::string> paths; 430f41e947bSMatthew Barth 431f41e947bSMatthew Barth for (const auto& path : _servTree) 432f41e947bSMatthew Barth { 433f41e947bSMatthew Barth auto itServ = path.second.find(serv); 434f41e947bSMatthew Barth if (itServ != path.second.end()) 435f41e947bSMatthew Barth { 436f41e947bSMatthew Barth if (std::find(itServ->second.second.begin(), 437f41e947bSMatthew Barth itServ->second.second.end(), 438f41e947bSMatthew Barth intf) != itServ->second.second.end()) 439f41e947bSMatthew Barth { 440f41e947bSMatthew Barth if (std::find(paths.begin(), paths.end(), path.first) == 441f41e947bSMatthew Barth paths.end()) 442f41e947bSMatthew Barth { 443f41e947bSMatthew Barth paths.push_back(path.first); 444f41e947bSMatthew Barth } 445f41e947bSMatthew Barth } 446f41e947bSMatthew Barth } 447f41e947bSMatthew Barth } 448f41e947bSMatthew Barth 449f41e947bSMatthew Barth return paths; 450f41e947bSMatthew Barth } 451f41e947bSMatthew Barth 452f41e947bSMatthew Barth std::vector<std::string> Manager::getPaths(const std::string& serv, 453f41e947bSMatthew Barth const std::string& intf) 454f41e947bSMatthew Barth { 455f41e947bSMatthew Barth auto paths = findPaths(serv, intf); 456f41e947bSMatthew Barth if (paths.empty()) 457f41e947bSMatthew Barth { 458f41e947bSMatthew Barth addServices(intf, 0); 459f41e947bSMatthew Barth return findPaths(serv, intf); 460f41e947bSMatthew Barth } 461f41e947bSMatthew Barth 462f41e947bSMatthew Barth return paths; 463f41e947bSMatthew Barth } 464f41e947bSMatthew Barth 465f41e947bSMatthew Barth void Manager::addObjects(const std::string& path, const std::string& intf, 466f41e947bSMatthew Barth const std::string& prop) 467f41e947bSMatthew Barth { 468f41e947bSMatthew Barth auto service = getService(path, intf); 469f41e947bSMatthew Barth if (service.empty()) 470f41e947bSMatthew Barth { 471f41e947bSMatthew Barth // Log service not found for object 47234835150SMatt Spinler log<level::DEBUG>( 473f41e947bSMatthew Barth fmt::format("Unable to get service name for path {}, interface {}", 474f41e947bSMatthew Barth path, intf) 475f41e947bSMatthew Barth .c_str()); 476f41e947bSMatthew Barth return; 477f41e947bSMatthew Barth } 478f41e947bSMatthew Barth 479f41e947bSMatthew Barth auto objMgrPaths = getPaths(service, "org.freedesktop.DBus.ObjectManager"); 480f41e947bSMatthew Barth if (objMgrPaths.empty()) 481f41e947bSMatthew Barth { 482f41e947bSMatthew Barth // No object manager interface provided by service? 483f41e947bSMatthew Barth // Attempt to retrieve property directly 484f41e947bSMatthew Barth auto variant = util::SDBusPlus::getPropertyVariant<PropertyVariantType>( 485f41e947bSMatthew Barth _bus, service, path, intf, prop); 486f41e947bSMatthew Barth _objects[path][intf][prop] = variant; 487f41e947bSMatthew Barth return; 488f41e947bSMatthew Barth } 489f41e947bSMatthew Barth 490f41e947bSMatthew Barth for (const auto& objMgrPath : objMgrPaths) 491f41e947bSMatthew Barth { 492f41e947bSMatthew Barth // Get all managed objects of service 493f41e947bSMatthew Barth auto objects = util::SDBusPlus::getManagedObjects<PropertyVariantType>( 494f41e947bSMatthew Barth _bus, service, objMgrPath); 495f41e947bSMatthew Barth 496f41e947bSMatthew Barth // Add what's returned to the cache of objects 497f41e947bSMatthew Barth for (auto& object : objects) 498f41e947bSMatthew Barth { 499f41e947bSMatthew Barth auto itPath = _objects.find(object.first); 500f41e947bSMatthew Barth if (itPath != _objects.end()) 501f41e947bSMatthew Barth { 502f41e947bSMatthew Barth // Path found in cache 503f41e947bSMatthew Barth for (auto& interface : itPath->second) 504f41e947bSMatthew Barth { 505f41e947bSMatthew Barth auto itIntf = itPath->second.find(interface.first); 506f41e947bSMatthew Barth if (itIntf != itPath->second.end()) 507f41e947bSMatthew Barth { 508f41e947bSMatthew Barth // Interface found in cache 509f41e947bSMatthew Barth for (auto& property : itIntf->second) 510f41e947bSMatthew Barth { 511f41e947bSMatthew Barth auto itProp = itIntf->second.find(property.first); 512f41e947bSMatthew Barth if (itProp != itIntf->second.end()) 513f41e947bSMatthew Barth { 514f41e947bSMatthew Barth // Property found, update value 515f41e947bSMatthew Barth itProp->second = property.second; 516f41e947bSMatthew Barth } 517f41e947bSMatthew Barth else 518f41e947bSMatthew Barth { 519f41e947bSMatthew Barth itIntf->second.insert(property); 520f41e947bSMatthew Barth } 521f41e947bSMatthew Barth } 522f41e947bSMatthew Barth } 523f41e947bSMatthew Barth else 524f41e947bSMatthew Barth { 525f41e947bSMatthew Barth // Interface not found in cache 526f41e947bSMatthew Barth itPath->second.insert(interface); 527f41e947bSMatthew Barth } 528f41e947bSMatthew Barth } 529f41e947bSMatthew Barth } 530f41e947bSMatthew Barth else 531f41e947bSMatthew Barth { 532f41e947bSMatthew Barth // Path not found in cache 533f41e947bSMatthew Barth _objects.insert(object); 534f41e947bSMatthew Barth } 535f41e947bSMatthew Barth } 536f41e947bSMatthew Barth } 537f41e947bSMatthew Barth } 538f41e947bSMatthew Barth 539f41e947bSMatthew Barth const std::optional<PropertyVariantType> 540f41e947bSMatthew Barth Manager::getProperty(const std::string& path, const std::string& intf, 541f41e947bSMatthew Barth const std::string& prop) 542f41e947bSMatthew Barth { 543f41e947bSMatthew Barth // TODO Objects hosted by fan control (i.e. ThermalMode) are required to 544f41e947bSMatthew Barth // update the cache upon being set/updated 545f41e947bSMatthew Barth auto itPath = _objects.find(path); 546f41e947bSMatthew Barth if (itPath != _objects.end()) 547f41e947bSMatthew Barth { 548f41e947bSMatthew Barth auto itIntf = itPath->second.find(intf); 549f41e947bSMatthew Barth if (itIntf != itPath->second.end()) 550f41e947bSMatthew Barth { 551f41e947bSMatthew Barth auto itProp = itIntf->second.find(prop); 552f41e947bSMatthew Barth if (itProp != itIntf->second.end()) 553f41e947bSMatthew Barth { 554f41e947bSMatthew Barth return itProp->second; 555f41e947bSMatthew Barth } 556f41e947bSMatthew Barth } 557f41e947bSMatthew Barth } 558f41e947bSMatthew Barth 559f41e947bSMatthew Barth return std::nullopt; 560f41e947bSMatthew Barth } 561f41e947bSMatthew Barth 562d9cb63b6SMatthew Barth void Manager::addTimer(const TimerType type, 563d9cb63b6SMatthew Barth const std::chrono::microseconds interval, 564d9cb63b6SMatthew Barth std::unique_ptr<TimerPkg> pkg) 565d9cb63b6SMatthew Barth { 566d9cb63b6SMatthew Barth auto dataPtr = 567d9cb63b6SMatthew Barth std::make_unique<TimerData>(std::make_pair(type, std::move(*pkg))); 568d9cb63b6SMatthew Barth Timer timer(_event, 569d9cb63b6SMatthew Barth std::bind(&Manager::timerExpired, this, std::ref(*dataPtr))); 570d9cb63b6SMatthew Barth if (type == TimerType::repeating) 571d9cb63b6SMatthew Barth { 572d9cb63b6SMatthew Barth timer.restart(interval); 573d9cb63b6SMatthew Barth } 574d9cb63b6SMatthew Barth else if (type == TimerType::oneshot) 575d9cb63b6SMatthew Barth { 576d9cb63b6SMatthew Barth timer.restartOnce(interval); 577d9cb63b6SMatthew Barth } 578d9cb63b6SMatthew Barth else 579d9cb63b6SMatthew Barth { 580d9cb63b6SMatthew Barth throw std::invalid_argument("Invalid Timer Type"); 581d9cb63b6SMatthew Barth } 582d9cb63b6SMatthew Barth _timers.emplace_back(std::move(dataPtr), std::move(timer)); 583d9cb63b6SMatthew Barth } 584d9cb63b6SMatthew Barth 585*ade0c377SMatt Spinler void Manager::addGroup(const Group& group) 586*ade0c377SMatt Spinler { 587*ade0c377SMatt Spinler const auto& members = group.getMembers(); 588*ade0c377SMatt Spinler for (const auto& member : members) 589*ade0c377SMatt Spinler { 590*ade0c377SMatt Spinler try 591*ade0c377SMatt Spinler { 592*ade0c377SMatt Spinler auto service = getService(member, group.getInterface()); 593*ade0c377SMatt Spinler 594*ade0c377SMatt Spinler auto variant = 595*ade0c377SMatt Spinler util::SDBusPlus::getPropertyVariant<PropertyVariantType>( 596*ade0c377SMatt Spinler service, member, group.getInterface(), group.getProperty()); 597*ade0c377SMatt Spinler 598*ade0c377SMatt Spinler setProperty(member, group.getInterface(), group.getProperty(), 599*ade0c377SMatt Spinler variant); 600*ade0c377SMatt Spinler } 601*ade0c377SMatt Spinler catch (const std::exception& e) 602*ade0c377SMatt Spinler { 603*ade0c377SMatt Spinler try 604*ade0c377SMatt Spinler { 605*ade0c377SMatt Spinler _objects.at(member) 606*ade0c377SMatt Spinler .at(group.getInterface()) 607*ade0c377SMatt Spinler .erase(group.getProperty()); 608*ade0c377SMatt Spinler } 609*ade0c377SMatt Spinler catch (const std::out_of_range&) 610*ade0c377SMatt Spinler {} 611*ade0c377SMatt Spinler } 612*ade0c377SMatt Spinler } 613*ade0c377SMatt Spinler } 614*ade0c377SMatt Spinler 615d9cb63b6SMatthew Barth void Manager::timerExpired(TimerData& data) 616d9cb63b6SMatthew Barth { 617*ade0c377SMatt Spinler if (std::get<bool>(data.second)) 618*ade0c377SMatt Spinler { 619*ade0c377SMatt Spinler const auto& groups = std::get<const std::vector<Group>&>(data.second); 620*ade0c377SMatt Spinler std::for_each(groups.begin(), groups.end(), 621*ade0c377SMatt Spinler [this](const auto& group) { addGroup(group); }); 622*ade0c377SMatt Spinler } 623*ade0c377SMatt Spinler 624d9cb63b6SMatthew Barth auto& actions = 625d9cb63b6SMatthew Barth std::get<std::vector<std::unique_ptr<ActionBase>>&>(data.second); 626d9cb63b6SMatthew Barth // Perform the actions in the timer data 627d9cb63b6SMatthew Barth std::for_each(actions.begin(), actions.end(), 62800f6aa09SMatthew Barth [](auto& action) { action->run(); }); 629d9cb63b6SMatthew Barth 630d9cb63b6SMatthew Barth // Remove oneshot timers after they expired 631d9cb63b6SMatthew Barth if (data.first == TimerType::oneshot) 632d9cb63b6SMatthew Barth { 633d9cb63b6SMatthew Barth auto itTimer = std::find_if( 634d9cb63b6SMatthew Barth _timers.begin(), _timers.end(), [&data](const auto& timer) { 635d9cb63b6SMatthew Barth return (data.first == timer.first->first && 636d9cb63b6SMatthew Barth (std::get<std::string>(data.second) == 637d9cb63b6SMatthew Barth std::get<std::string>(timer.first->second))); 638d9cb63b6SMatthew Barth }); 639d9cb63b6SMatthew Barth if (itTimer != std::end(_timers)) 640d9cb63b6SMatthew Barth { 641d9cb63b6SMatthew Barth _timers.erase(itTimer); 642d9cb63b6SMatthew Barth } 643d9cb63b6SMatthew Barth } 644d9cb63b6SMatthew Barth } 645d9cb63b6SMatthew Barth 646ebabc040SMatthew Barth void Manager::handleSignal(sdbusplus::message::message& msg, 647fac8a2feSMatthew Barth const std::vector<SignalPkg>& pkgs) 648ebabc040SMatthew Barth { 649fac8a2feSMatthew Barth for (auto& pkg : pkgs) 650ebabc040SMatthew Barth { 651ebabc040SMatthew Barth // Handle the signal callback and only run the actions if the handler 652ebabc040SMatthew Barth // updated the cache for the given SignalObject 653ebabc040SMatthew Barth if (std::get<SignalHandler>(pkg)(msg, std::get<SignalObject>(pkg), 654ebabc040SMatthew Barth *this)) 655ebabc040SMatthew Barth { 656ebabc040SMatthew Barth // Perform the actions in the handler package 657ebabc040SMatthew Barth auto& actions = std::get<SignalActions>(pkg); 658ebabc040SMatthew Barth std::for_each(actions.begin(), actions.end(), 659ebabc040SMatthew Barth [](auto& action) { action.get()->run(); }); 660ebabc040SMatthew Barth } 661ebabc040SMatthew Barth } 662ebabc040SMatthew Barth } 663ebabc040SMatthew Barth 664acd737cdSMatthew Barth void Manager::setProfiles() 665acd737cdSMatthew Barth { 666acd737cdSMatthew Barth // Profiles JSON config file is optional 667acd737cdSMatthew Barth auto confFile = fan::JsonConfig::getConfFile(_bus, confAppName, 668acd737cdSMatthew Barth Profile::confFileName, true); 669e91ac864SMatthew Barth 670e91ac864SMatthew Barth _profiles.clear(); 671acd737cdSMatthew Barth if (!confFile.empty()) 672acd737cdSMatthew Barth { 673acd737cdSMatthew Barth for (const auto& entry : fan::JsonConfig::load(confFile)) 674acd737cdSMatthew Barth { 675acd737cdSMatthew Barth auto obj = std::make_unique<Profile>(entry); 676acd737cdSMatthew Barth _profiles.emplace( 677acd737cdSMatthew Barth std::make_pair(obj->getName(), obj->getProfiles()), 678acd737cdSMatthew Barth std::move(obj)); 679acd737cdSMatthew Barth } 680acd737cdSMatthew Barth } 681e91ac864SMatthew Barth 682acd737cdSMatthew Barth // Ensure all configurations use the same set of active profiles 683acd737cdSMatthew Barth // (In case a profile's active state changes during configuration) 684e91ac864SMatthew Barth _activeProfiles.clear(); 685acd737cdSMatthew Barth for (const auto& profile : _profiles) 686acd737cdSMatthew Barth { 687acd737cdSMatthew Barth if (profile.second->isActive()) 688acd737cdSMatthew Barth { 689acd737cdSMatthew Barth _activeProfiles.emplace_back(profile.first.first); 690acd737cdSMatthew Barth } 691acd737cdSMatthew Barth } 692acd737cdSMatthew Barth } 693acd737cdSMatthew Barth 694a227a16dSMatthew Barth } // namespace phosphor::fan::control::json 695