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 31c024d780SMatthew Barth #include <systemd/sd-bus.h> 32c024d780SMatthew Barth 33acd737cdSMatthew Barth #include <nlohmann/json.hpp> 34a227a16dSMatthew Barth #include <sdbusplus/bus.hpp> 351542fb5aSMatthew Barth #include <sdbusplus/server/manager.hpp> 36acd737cdSMatthew Barth #include <sdeventplus/event.hpp> 37d9cb63b6SMatthew Barth #include <sdeventplus/utility/timer.hpp> 38a227a16dSMatthew Barth 39de90fb4dSMatthew Barth #include <algorithm> 40d9cb63b6SMatthew Barth #include <chrono> 41a227a16dSMatthew Barth #include <filesystem> 42d9cb63b6SMatthew Barth #include <functional> 43d9cb63b6SMatthew Barth #include <map> 44d9cb63b6SMatthew Barth #include <memory> 45d9cb63b6SMatthew Barth #include <tuple> 46d9cb63b6SMatthew Barth #include <utility> 4706764946SMatthew Barth #include <vector> 48a227a16dSMatthew Barth 49a227a16dSMatthew Barth namespace phosphor::fan::control::json 50a227a16dSMatthew Barth { 51a227a16dSMatthew Barth 52acd737cdSMatthew Barth using json = nlohmann::json; 53acd737cdSMatthew Barth 54acd737cdSMatthew Barth std::vector<std::string> Manager::_activeProfiles; 5512cb125aSMatthew Barth std::map<std::string, 564ca87faeSMatthew Barth std::map<std::string, std::pair<bool, std::vector<std::string>>>> 5712cb125aSMatthew Barth Manager::_servTree; 5807fecfc6SMatthew Barth std::map<std::string, 5907fecfc6SMatthew Barth std::map<std::string, std::map<std::string, PropertyVariantType>>> 6007fecfc6SMatthew Barth Manager::_objects; 61d76351bdSMatt Spinler std::unordered_map<std::string, PropertyVariantType> Manager::_parameters; 62d0ba86a3SMatt Spinler std::unordered_map<std::string, TriggerActions> Manager::_parameterTriggers; 63acd737cdSMatthew Barth 647787def0SMatt Spinler const std::string Manager::dumpFile = "/tmp/fan_control_dump.json"; 657787def0SMatt Spinler 669403a217SMatthew Barth Manager::Manager(const sdeventplus::Event& event) : 6748f44daaSMatthew Barth _bus(util::SDBusPlus::getBus()), _event(event), 683770a1daSMatthew Barth _mgr(util::SDBusPlus::getBus(), CONTROL_OBJPATH), _loadAllowed(true), 6948f44daaSMatthew Barth _powerState(std::make_unique<PGoodState>( 7048f44daaSMatthew Barth util::SDBusPlus::getBus(), 7148f44daaSMatthew Barth std::bind(std::mem_fn(&Manager::powerStateChanged), this, 7248f44daaSMatthew Barth std::placeholders::_1))) 733770a1daSMatthew Barth {} 74e91ac864SMatthew Barth 75e91ac864SMatthew Barth void Manager::sighupHandler(sdeventplus::source::Signal&, 76e91ac864SMatthew Barth const struct signalfd_siginfo*) 77e91ac864SMatthew Barth { 78e91ac864SMatthew Barth // Save current set of available and active profiles 79e91ac864SMatthew Barth std::map<configKey, std::unique_ptr<Profile>> profiles; 80e91ac864SMatthew Barth profiles.swap(_profiles); 81e91ac864SMatthew Barth std::vector<std::string> activeProfiles; 82e91ac864SMatthew Barth activeProfiles.swap(_activeProfiles); 83e91ac864SMatthew Barth 84e91ac864SMatthew Barth try 85e91ac864SMatthew Barth { 863770a1daSMatthew Barth _loadAllowed = true; 87e91ac864SMatthew Barth load(); 88e91ac864SMatthew Barth } 89ddb773b2SPatrick Williams catch (const std::runtime_error& re) 90e91ac864SMatthew Barth { 91e91ac864SMatthew Barth // Restore saved available and active profiles 923770a1daSMatthew Barth _loadAllowed = false; 93e91ac864SMatthew Barth _profiles.swap(profiles); 94e91ac864SMatthew Barth _activeProfiles.swap(activeProfiles); 95e91ac864SMatthew Barth log<level::ERR>("Error reloading configs, no changes made", 96e91ac864SMatthew Barth entry("LOAD_ERROR=%s", re.what())); 97e91ac864SMatthew Barth } 98e91ac864SMatthew Barth } 99e91ac864SMatthew Barth 1002fc0a35dSMatt Spinler void Manager::sigUsr1Handler(sdeventplus::source::Signal&, 1012fc0a35dSMatt Spinler const struct signalfd_siginfo*) 1022fc0a35dSMatt Spinler { 1037787def0SMatt Spinler debugDumpEventSource = std::make_unique<sdeventplus::source::Defer>( 1047787def0SMatt Spinler _event, std::bind(std::mem_fn(&Manager::dumpDebugData), this, 1052fc0a35dSMatt Spinler std::placeholders::_1)); 1062fc0a35dSMatt Spinler } 1072fc0a35dSMatt Spinler 1087787def0SMatt Spinler void Manager::dumpDebugData(sdeventplus::source::EventBase& /*source*/) 1092fc0a35dSMatt Spinler { 1107787def0SMatt Spinler json data; 1117787def0SMatt Spinler FlightRecorder::instance().dump(data); 112b5c21a24SMatt Spinler dumpCache(data); 1137787def0SMatt Spinler 1149db6dd1dSMatt Spinler std::for_each(_zones.begin(), _zones.end(), [&data](const auto& zone) { 1159db6dd1dSMatt Spinler data["zones"][zone.second->getName()] = zone.second->dump(); 1169db6dd1dSMatt Spinler }); 1179db6dd1dSMatt Spinler 1187787def0SMatt Spinler std::ofstream file{Manager::dumpFile}; 1197787def0SMatt Spinler if (!file) 1207787def0SMatt Spinler { 1217787def0SMatt Spinler log<level::ERR>("Could not open file for fan dump"); 1227787def0SMatt Spinler return; 1237787def0SMatt Spinler } 1247787def0SMatt Spinler 1257787def0SMatt Spinler file << std::setw(4) << data; 1267787def0SMatt Spinler 1277787def0SMatt Spinler debugDumpEventSource.reset(); 1282fc0a35dSMatt Spinler } 1292fc0a35dSMatt Spinler 130b5c21a24SMatt Spinler void Manager::dumpCache(json& data) 131b5c21a24SMatt Spinler { 132b5c21a24SMatt Spinler auto& objects = data["objects"]; 133b5c21a24SMatt Spinler for (const auto& [path, interfaces] : _objects) 134b5c21a24SMatt Spinler { 135b5c21a24SMatt Spinler auto& interfaceJSON = objects[path]; 136b5c21a24SMatt Spinler 137b5c21a24SMatt Spinler for (const auto& [interface, properties] : interfaces) 138b5c21a24SMatt Spinler { 139b5c21a24SMatt Spinler auto& propertyJSON = interfaceJSON[interface]; 140b5c21a24SMatt Spinler for (const auto& [propName, propValue] : properties) 141b5c21a24SMatt Spinler { 142b5c21a24SMatt Spinler std::visit( 143b5c21a24SMatt Spinler [&obj = propertyJSON[propName]](auto&& val) { obj = val; }, 144b5c21a24SMatt Spinler propValue); 145b5c21a24SMatt Spinler } 146b5c21a24SMatt Spinler } 147b5c21a24SMatt Spinler } 148b5c21a24SMatt Spinler 149b5c21a24SMatt Spinler auto& parameters = data["parameters"]; 150b5c21a24SMatt Spinler for (const auto& [name, value] : _parameters) 151b5c21a24SMatt Spinler { 15229088e79SMatt Spinler std::visit([&obj = parameters[name]](auto&& val) { obj = val; }, value); 153b5c21a24SMatt Spinler } 154b5c21a24SMatt Spinler 155b5c21a24SMatt Spinler data["services"] = _servTree; 156b5c21a24SMatt Spinler } 157b5c21a24SMatt Spinler 158e91ac864SMatthew Barth void Manager::load() 159e91ac864SMatthew Barth { 1603770a1daSMatthew Barth if (_loadAllowed) 1613770a1daSMatthew Barth { 162e91ac864SMatthew Barth // Load the available profiles and which are active 163acd737cdSMatthew Barth setProfiles(); 164acd737cdSMatthew Barth 165acd737cdSMatthew Barth // Load the zone configurations 166e91ac864SMatthew Barth auto zones = getConfig<Zone>(false, _event, this); 167de90fb4dSMatthew Barth // Load the fan configurations and move each fan into its zone 1689403a217SMatthew Barth auto fans = getConfig<Fan>(false); 169de90fb4dSMatthew Barth for (auto& fan : fans) 170de90fb4dSMatthew Barth { 1710206c728SMatthew Barth configKey fanProfile = 1720206c728SMatthew Barth std::make_pair(fan.second->getZone(), fan.first.second); 1730206c728SMatthew Barth auto itZone = std::find_if( 174e91ac864SMatthew Barth zones.begin(), zones.end(), [&fanProfile](const auto& zone) { 1750206c728SMatthew Barth return Manager::inConfig(fanProfile, zone.first); 176de90fb4dSMatthew Barth }); 177e91ac864SMatthew Barth if (itZone != zones.end()) 178de90fb4dSMatthew Barth { 1796f787309SMatthew Barth if (itZone->second->getTarget() != fan.second->getTarget() && 1806f787309SMatthew Barth fan.second->getTarget() != 0) 1816f787309SMatthew Barth { 182e91ac864SMatthew Barth // Update zone target to current target of the fan in the 183e91ac864SMatthew Barth // zone 1846f787309SMatthew Barth itZone->second->setTarget(fan.second->getTarget()); 1856f787309SMatthew Barth } 186de90fb4dSMatthew Barth itZone->second->addFan(std::move(fan.second)); 187de90fb4dSMatthew Barth } 188de90fb4dSMatthew Barth } 189e91ac864SMatthew Barth 1903695ac30SMatthew Barth // Save all currently available groups, if any, then clear for reloading 1913695ac30SMatthew Barth auto groups = std::move(Event::getAllGroups(false)); 1923695ac30SMatthew Barth Event::clearAllGroups(); 1933695ac30SMatthew Barth 1943695ac30SMatthew Barth std::map<configKey, std::unique_ptr<Event>> events; 1953695ac30SMatthew Barth try 1963695ac30SMatthew Barth { 1973695ac30SMatthew Barth // Load any events configured, including all the groups 1983695ac30SMatthew Barth events = getConfig<Event>(true, this, zones); 1993695ac30SMatthew Barth } 2003695ac30SMatthew Barth catch (const std::runtime_error& re) 2013695ac30SMatthew Barth { 2023695ac30SMatthew Barth // Restore saved set of all available groups for current events 2033695ac30SMatthew Barth Event::setAllGroups(std::move(groups)); 2043695ac30SMatthew Barth throw re; 2053695ac30SMatthew Barth } 206e91ac864SMatthew Barth 20714303a45SMatthew Barth // Enable zones 208e91ac864SMatthew Barth _zones = std::move(zones); 20914303a45SMatthew Barth std::for_each(_zones.begin(), _zones.end(), 21014303a45SMatthew Barth [](const auto& entry) { entry.second->enable(); }); 211b584d818SMatthew Barth 212e91ac864SMatthew Barth // Clear current timers and signal subscriptions before enabling events 2133770a1daSMatthew Barth // To save reloading services and/or objects into cache, do not clear 2143770a1daSMatthew Barth // cache 215e91ac864SMatthew Barth _timers.clear(); 216e91ac864SMatthew Barth _signals.clear(); 217e91ac864SMatthew Barth 218e91ac864SMatthew Barth // Enable events 219e91ac864SMatthew Barth _events = std::move(events); 22054b5a24fSMatthew Barth std::for_each(_events.begin(), _events.end(), 22154b5a24fSMatthew Barth [](const auto& entry) { entry.second->enable(); }); 2223770a1daSMatthew Barth 2233770a1daSMatthew Barth _loadAllowed = false; 2243770a1daSMatthew Barth } 22506764946SMatthew Barth } 226acd737cdSMatthew Barth 22748f44daaSMatthew Barth void Manager::powerStateChanged(bool powerStateOn) 22848f44daaSMatthew Barth { 22948f44daaSMatthew Barth if (powerStateOn) 23048f44daaSMatthew Barth { 2316a2418a2SMatthew Barth if (_zones.empty()) 2326a2418a2SMatthew Barth { 2336a2418a2SMatthew Barth throw std::runtime_error("No configured zones found at poweron"); 2346a2418a2SMatthew Barth } 23548f44daaSMatthew Barth std::for_each(_zones.begin(), _zones.end(), [](const auto& entry) { 23648f44daaSMatthew Barth entry.second->setTarget(entry.second->getPoweronTarget()); 23748f44daaSMatthew Barth }); 238d1f97f43SMatt Spinler 239d1f97f43SMatt Spinler // Tell events to run their power on triggers 240d1f97f43SMatt Spinler std::for_each(_events.begin(), _events.end(), 241d1f97f43SMatt Spinler [](const auto& entry) { entry.second->powerOn(); }); 242d1f97f43SMatt Spinler } 243d1f97f43SMatt Spinler else 244d1f97f43SMatt Spinler { 245d1f97f43SMatt Spinler // Tell events to run their power off triggers 246d1f97f43SMatt Spinler std::for_each(_events.begin(), _events.end(), 247d1f97f43SMatt Spinler [](const auto& entry) { entry.second->powerOff(); }); 24848f44daaSMatthew Barth } 24948f44daaSMatthew Barth } 25048f44daaSMatthew Barth 251acd737cdSMatthew Barth const std::vector<std::string>& Manager::getActiveProfiles() 252acd737cdSMatthew Barth { 253acd737cdSMatthew Barth return _activeProfiles; 254a227a16dSMatthew Barth } 255a227a16dSMatthew Barth 2560206c728SMatthew Barth bool Manager::inConfig(const configKey& input, const configKey& comp) 2570206c728SMatthew Barth { 2580206c728SMatthew Barth // Config names dont match, do not include in config 2590206c728SMatthew Barth if (input.first != comp.first) 2600206c728SMatthew Barth { 2610206c728SMatthew Barth return false; 2620206c728SMatthew Barth } 2630206c728SMatthew Barth // No profiles specified by input config, can be used in any config 2640206c728SMatthew Barth if (input.second.empty()) 2650206c728SMatthew Barth { 2660206c728SMatthew Barth return true; 2670206c728SMatthew Barth } 2680206c728SMatthew Barth else 2690206c728SMatthew Barth { 2700206c728SMatthew Barth // Profiles must have one match in the other's profiles(and they must be 2710206c728SMatthew Barth // an active profile) to be used in the config 2720206c728SMatthew Barth return std::any_of( 2730206c728SMatthew Barth input.second.begin(), input.second.end(), 2740206c728SMatthew Barth [&comp](const auto& lProfile) { 2750206c728SMatthew Barth return std::any_of( 2760206c728SMatthew Barth comp.second.begin(), comp.second.end(), 2770206c728SMatthew Barth [&lProfile](const auto& rProfile) { 2780206c728SMatthew Barth if (lProfile != rProfile) 2790206c728SMatthew Barth { 2800206c728SMatthew Barth return false; 2810206c728SMatthew Barth } 2820206c728SMatthew Barth auto activeProfs = getActiveProfiles(); 2830206c728SMatthew Barth return std::find(activeProfs.begin(), activeProfs.end(), 2840206c728SMatthew Barth lProfile) != activeProfs.end(); 2850206c728SMatthew Barth }); 2860206c728SMatthew Barth }); 2870206c728SMatthew Barth } 2880206c728SMatthew Barth } 2890206c728SMatthew Barth 29012cb125aSMatthew Barth bool Manager::hasOwner(const std::string& path, const std::string& intf) 29112cb125aSMatthew Barth { 29212cb125aSMatthew Barth auto itServ = _servTree.find(path); 29312cb125aSMatthew Barth if (itServ == _servTree.end()) 29412cb125aSMatthew Barth { 29512cb125aSMatthew Barth // Path not found in cache, therefore owner missing 29612cb125aSMatthew Barth return false; 29712cb125aSMatthew Barth } 2984ca87faeSMatthew Barth for (const auto& service : itServ->second) 29912cb125aSMatthew Barth { 30012cb125aSMatthew Barth auto itIntf = std::find_if( 3014ca87faeSMatthew Barth service.second.second.begin(), service.second.second.end(), 30212cb125aSMatthew Barth [&intf](const auto& interface) { return intf == interface; }); 3034ca87faeSMatthew Barth if (itIntf != std::end(service.second.second)) 30412cb125aSMatthew Barth { 30512cb125aSMatthew Barth // Service found, return owner state 3064ca87faeSMatthew Barth return service.second.first; 30712cb125aSMatthew Barth } 30812cb125aSMatthew Barth } 30912cb125aSMatthew Barth // Interface not found in cache, therefore owner missing 31012cb125aSMatthew Barth return false; 31112cb125aSMatthew Barth } 31212cb125aSMatthew Barth 313*6d8e2d3eSMatthew Barth void Manager::setOwner(const std::string& serv, bool hasOwner) 314*6d8e2d3eSMatthew Barth { 315*6d8e2d3eSMatthew Barth // Update owner state on all entries of `serv` 316*6d8e2d3eSMatthew Barth for (auto& itPath : _servTree) 317*6d8e2d3eSMatthew Barth { 318*6d8e2d3eSMatthew Barth auto itServ = itPath.second.find(serv); 319*6d8e2d3eSMatthew Barth if (itServ != itPath.second.end()) 320*6d8e2d3eSMatthew Barth { 321*6d8e2d3eSMatthew Barth itServ->second.first = hasOwner; 322*6d8e2d3eSMatthew Barth 323*6d8e2d3eSMatthew Barth // Remove associated interfaces from object cache when service no 324*6d8e2d3eSMatthew Barth // longer has an owner 325*6d8e2d3eSMatthew Barth if (!hasOwner && _objects.find(itPath.first) != _objects.end()) 326*6d8e2d3eSMatthew Barth { 327*6d8e2d3eSMatthew Barth for (auto& intf : itServ->second.second) 328*6d8e2d3eSMatthew Barth { 329*6d8e2d3eSMatthew Barth _objects[itPath.first].erase(intf); 330*6d8e2d3eSMatthew Barth } 331*6d8e2d3eSMatthew Barth } 332*6d8e2d3eSMatthew Barth } 333*6d8e2d3eSMatthew Barth } 334*6d8e2d3eSMatthew Barth } 335*6d8e2d3eSMatthew Barth 3364ca87faeSMatthew Barth void Manager::setOwner(const std::string& path, const std::string& serv, 3374ca87faeSMatthew Barth const std::string& intf, bool isOwned) 3384ca87faeSMatthew Barth { 3392a9e7b2eSMatthew Barth // Set owner state for specific object given 3402a9e7b2eSMatthew Barth auto& ownIntf = _servTree[path][serv]; 3412a9e7b2eSMatthew Barth ownIntf.first = isOwned; 3424ca87faeSMatthew Barth auto itIntf = std::find_if( 3432a9e7b2eSMatthew Barth ownIntf.second.begin(), ownIntf.second.end(), 3444ca87faeSMatthew Barth [&intf](const auto& interface) { return intf == interface; }); 3452a9e7b2eSMatthew Barth if (itIntf == std::end(ownIntf.second)) 3464ca87faeSMatthew Barth { 3472a9e7b2eSMatthew Barth ownIntf.second.emplace_back(intf); 3482a9e7b2eSMatthew Barth } 3492a9e7b2eSMatthew Barth 3502a9e7b2eSMatthew Barth // Update owner state on all entries of the same `serv` & `intf` 3512a9e7b2eSMatthew Barth for (auto& itPath : _servTree) 3524ca87faeSMatthew Barth { 3532a9e7b2eSMatthew Barth if (itPath.first == path) 3542a9e7b2eSMatthew Barth { 3552a9e7b2eSMatthew Barth // Already set/updated owner on this path for `serv` & `intf` 3562a9e7b2eSMatthew Barth continue; 3572a9e7b2eSMatthew Barth } 3582a9e7b2eSMatthew Barth for (auto& itServ : itPath.second) 3592a9e7b2eSMatthew Barth { 3602a9e7b2eSMatthew Barth if (itServ.first != serv) 3612a9e7b2eSMatthew Barth { 3622a9e7b2eSMatthew Barth continue; 3632a9e7b2eSMatthew Barth } 3642a9e7b2eSMatthew Barth auto itIntf = std::find_if( 3652a9e7b2eSMatthew Barth itServ.second.second.begin(), itServ.second.second.end(), 3662a9e7b2eSMatthew Barth [&intf](const auto& interface) { return intf == interface; }); 3672a9e7b2eSMatthew Barth if (itIntf != std::end(itServ.second.second)) 3682a9e7b2eSMatthew Barth { 3692a9e7b2eSMatthew Barth itServ.second.first = isOwned; 3704ca87faeSMatthew Barth } 3714ca87faeSMatthew Barth } 3724ca87faeSMatthew Barth } 3734ca87faeSMatthew Barth } 3744ca87faeSMatthew Barth 3754ca87faeSMatthew Barth const std::string& Manager::findService(const std::string& path, 3764ca87faeSMatthew Barth const std::string& intf) 3774ca87faeSMatthew Barth { 3784ca87faeSMatthew Barth static const std::string empty = ""; 3794ca87faeSMatthew Barth 3804ca87faeSMatthew Barth auto itServ = _servTree.find(path); 3814ca87faeSMatthew Barth if (itServ != _servTree.end()) 3824ca87faeSMatthew Barth { 3834ca87faeSMatthew Barth for (const auto& service : itServ->second) 3844ca87faeSMatthew Barth { 3854ca87faeSMatthew Barth auto itIntf = std::find_if( 3864ca87faeSMatthew Barth service.second.second.begin(), service.second.second.end(), 3874ca87faeSMatthew Barth [&intf](const auto& interface) { return intf == interface; }); 3884ca87faeSMatthew Barth if (itIntf != std::end(service.second.second)) 3894ca87faeSMatthew Barth { 3904ca87faeSMatthew Barth // Service found, return service name 3914ca87faeSMatthew Barth return service.first; 3924ca87faeSMatthew Barth } 3934ca87faeSMatthew Barth } 3944ca87faeSMatthew Barth } 3954ca87faeSMatthew Barth 3964ca87faeSMatthew Barth return empty; 3974ca87faeSMatthew Barth } 3984ca87faeSMatthew Barth 39998f6fc17SMatthew Barth void Manager::addServices(const std::string& intf, int32_t depth) 4004ca87faeSMatthew Barth { 4014ca87faeSMatthew Barth // Get all subtree objects for the given interface 40234835150SMatt Spinler auto objects = util::SDBusPlus::getSubTreeRaw(util::SDBusPlus::getBus(), 40334835150SMatt Spinler "/", intf, depth); 4044ca87faeSMatthew Barth // Add what's returned to the cache of path->services 4054ca87faeSMatthew Barth for (auto& itPath : objects) 4064ca87faeSMatthew Barth { 4074ca87faeSMatthew Barth auto pathIter = _servTree.find(itPath.first); 4084ca87faeSMatthew Barth if (pathIter != _servTree.end()) 4094ca87faeSMatthew Barth { 4104ca87faeSMatthew Barth // Path found in cache 4114ca87faeSMatthew Barth for (auto& itServ : itPath.second) 4124ca87faeSMatthew Barth { 4134ca87faeSMatthew Barth auto servIter = pathIter->second.find(itServ.first); 4144ca87faeSMatthew Barth if (servIter != pathIter->second.end()) 4154ca87faeSMatthew Barth { 4164ca87faeSMatthew Barth // Service found in cache 4174ca87faeSMatthew Barth for (auto& itIntf : itServ.second) 4184ca87faeSMatthew Barth { 4194ca87faeSMatthew Barth if (std::find(servIter->second.second.begin(), 4204ca87faeSMatthew Barth servIter->second.second.end(), 4214ca87faeSMatthew Barth itIntf) == servIter->second.second.end()) 4224ca87faeSMatthew Barth { 4234ca87faeSMatthew Barth // Add interface to cache 4244ca87faeSMatthew Barth servIter->second.second.emplace_back(itIntf); 4254ca87faeSMatthew Barth } 4264ca87faeSMatthew Barth } 4274ca87faeSMatthew Barth } 4284ca87faeSMatthew Barth else 4294ca87faeSMatthew Barth { 4304ca87faeSMatthew Barth // Service not found in cache 4314ca87faeSMatthew Barth auto intfs = {intf}; 4324ca87faeSMatthew Barth pathIter->second[itServ.first] = 4334ca87faeSMatthew Barth std::make_pair(true, intfs); 4344ca87faeSMatthew Barth } 4354ca87faeSMatthew Barth } 4364ca87faeSMatthew Barth } 4374ca87faeSMatthew Barth else 4384ca87faeSMatthew Barth { 4394ca87faeSMatthew Barth // Path not found in cache 4404ca87faeSMatthew Barth auto intfs = {intf}; 441a0b8a68fSMatt Spinler for (const auto& [servName, servIntfs] : itPath.second) 442a0b8a68fSMatt Spinler { 443a0b8a68fSMatt Spinler _servTree[itPath.first][servName] = std::make_pair(true, intfs); 444a0b8a68fSMatt Spinler } 4454ca87faeSMatthew Barth } 4464ca87faeSMatthew Barth } 4474ca87faeSMatthew Barth } 4484ca87faeSMatthew Barth 4494ca87faeSMatthew Barth const std::string& Manager::getService(const std::string& path, 4504ca87faeSMatthew Barth const std::string& intf) 4514ca87faeSMatthew Barth { 4524ca87faeSMatthew Barth // Retrieve service from cache 4534ca87faeSMatthew Barth const auto& serviceName = findService(path, intf); 4544ca87faeSMatthew Barth if (serviceName.empty()) 4554ca87faeSMatthew Barth { 45698f6fc17SMatthew Barth addServices(intf, 0); 4574ca87faeSMatthew Barth return findService(path, intf); 4584ca87faeSMatthew Barth } 4594ca87faeSMatthew Barth 4604ca87faeSMatthew Barth return serviceName; 4614ca87faeSMatthew Barth } 4624ca87faeSMatthew Barth 463f41e947bSMatthew Barth std::vector<std::string> Manager::findPaths(const std::string& serv, 464f41e947bSMatthew Barth const std::string& intf) 465f41e947bSMatthew Barth { 466f41e947bSMatthew Barth std::vector<std::string> paths; 467f41e947bSMatthew Barth 468f41e947bSMatthew Barth for (const auto& path : _servTree) 469f41e947bSMatthew Barth { 470f41e947bSMatthew Barth auto itServ = path.second.find(serv); 471f41e947bSMatthew Barth if (itServ != path.second.end()) 472f41e947bSMatthew Barth { 473f41e947bSMatthew Barth if (std::find(itServ->second.second.begin(), 474f41e947bSMatthew Barth itServ->second.second.end(), 475f41e947bSMatthew Barth intf) != itServ->second.second.end()) 476f41e947bSMatthew Barth { 477f41e947bSMatthew Barth if (std::find(paths.begin(), paths.end(), path.first) == 478f41e947bSMatthew Barth paths.end()) 479f41e947bSMatthew Barth { 480f41e947bSMatthew Barth paths.push_back(path.first); 481f41e947bSMatthew Barth } 482f41e947bSMatthew Barth } 483f41e947bSMatthew Barth } 484f41e947bSMatthew Barth } 485f41e947bSMatthew Barth 486f41e947bSMatthew Barth return paths; 487f41e947bSMatthew Barth } 488f41e947bSMatthew Barth 489f41e947bSMatthew Barth std::vector<std::string> Manager::getPaths(const std::string& serv, 490f41e947bSMatthew Barth const std::string& intf) 491f41e947bSMatthew Barth { 492f41e947bSMatthew Barth auto paths = findPaths(serv, intf); 493f41e947bSMatthew Barth if (paths.empty()) 494f41e947bSMatthew Barth { 495f41e947bSMatthew Barth addServices(intf, 0); 496f41e947bSMatthew Barth return findPaths(serv, intf); 497f41e947bSMatthew Barth } 498f41e947bSMatthew Barth 499f41e947bSMatthew Barth return paths; 500f41e947bSMatthew Barth } 501f41e947bSMatthew Barth 5021a19eaddSMike Capps void Manager::insertFilteredObjects(ManagedObjects& ref) 5031a19eaddSMike Capps { 5041a19eaddSMike Capps for (auto& [path, pathMap] : ref) 5051a19eaddSMike Capps { 5061a19eaddSMike Capps for (auto& [intf, intfMap] : pathMap) 5071a19eaddSMike Capps { 5081a19eaddSMike Capps // for each property on this path+interface 5091a19eaddSMike Capps for (auto& [prop, value] : intfMap) 5101a19eaddSMike Capps { 5111a19eaddSMike Capps setProperty(path, intf, prop, value); 5121a19eaddSMike Capps } 5131a19eaddSMike Capps } 5141a19eaddSMike Capps } 5151a19eaddSMike Capps } 5161a19eaddSMike Capps 517f41e947bSMatthew Barth void Manager::addObjects(const std::string& path, const std::string& intf, 518f41e947bSMatthew Barth const std::string& prop) 519f41e947bSMatthew Barth { 520f41e947bSMatthew Barth auto service = getService(path, intf); 521f41e947bSMatthew Barth if (service.empty()) 522f41e947bSMatthew Barth { 523f41e947bSMatthew Barth // Log service not found for object 52434835150SMatt Spinler log<level::DEBUG>( 525f41e947bSMatthew Barth fmt::format("Unable to get service name for path {}, interface {}", 526f41e947bSMatthew Barth path, intf) 527f41e947bSMatthew Barth .c_str()); 528f41e947bSMatthew Barth return; 529f41e947bSMatthew Barth } 530f41e947bSMatthew Barth 531f41e947bSMatthew Barth auto objMgrPaths = getPaths(service, "org.freedesktop.DBus.ObjectManager"); 532f41e947bSMatthew Barth if (objMgrPaths.empty()) 533f41e947bSMatthew Barth { 534f41e947bSMatthew Barth // No object manager interface provided by service? 535f41e947bSMatthew Barth // Attempt to retrieve property directly 5361a19eaddSMike Capps auto value = util::SDBusPlus::getPropertyVariant<PropertyVariantType>( 537f41e947bSMatthew Barth _bus, service, path, intf, prop); 5381a19eaddSMike Capps 5391a19eaddSMike Capps setProperty(path, intf, prop, value); 540f41e947bSMatthew Barth return; 541f41e947bSMatthew Barth } 542f41e947bSMatthew Barth 543f41e947bSMatthew Barth for (const auto& objMgrPath : objMgrPaths) 544f41e947bSMatthew Barth { 545f41e947bSMatthew Barth // Get all managed objects of service 5461a19eaddSMike Capps // want to filter here... 547f41e947bSMatthew Barth auto objects = util::SDBusPlus::getManagedObjects<PropertyVariantType>( 548f41e947bSMatthew Barth _bus, service, objMgrPath); 549f41e947bSMatthew Barth 5501a19eaddSMike Capps // insert all objects but remove any NaN values 5511a19eaddSMike Capps insertFilteredObjects(objects); 552f41e947bSMatthew Barth } 553f41e947bSMatthew Barth } 554f41e947bSMatthew Barth 555f41e947bSMatthew Barth const std::optional<PropertyVariantType> 556f41e947bSMatthew Barth Manager::getProperty(const std::string& path, const std::string& intf, 557f41e947bSMatthew Barth const std::string& prop) 558f41e947bSMatthew Barth { 559f41e947bSMatthew Barth // TODO Objects hosted by fan control (i.e. ThermalMode) are required to 560f41e947bSMatthew Barth // update the cache upon being set/updated 561f41e947bSMatthew Barth auto itPath = _objects.find(path); 562f41e947bSMatthew Barth if (itPath != _objects.end()) 563f41e947bSMatthew Barth { 564f41e947bSMatthew Barth auto itIntf = itPath->second.find(intf); 565f41e947bSMatthew Barth if (itIntf != itPath->second.end()) 566f41e947bSMatthew Barth { 567f41e947bSMatthew Barth auto itProp = itIntf->second.find(prop); 568f41e947bSMatthew Barth if (itProp != itIntf->second.end()) 569f41e947bSMatthew Barth { 570f41e947bSMatthew Barth return itProp->second; 571f41e947bSMatthew Barth } 572f41e947bSMatthew Barth } 573f41e947bSMatthew Barth } 574f41e947bSMatthew Barth 575f41e947bSMatthew Barth return std::nullopt; 576f41e947bSMatthew Barth } 577f41e947bSMatthew Barth 5781a19eaddSMike Capps void Manager::setProperty(const std::string& path, const std::string& intf, 5791a19eaddSMike Capps const std::string& prop, PropertyVariantType value) 5801a19eaddSMike Capps { 5811a19eaddSMike Capps // filter NaNs out of the cache 5821a19eaddSMike Capps if (PropertyContainsNan(value)) 5831a19eaddSMike Capps { 5841a19eaddSMike Capps // dont use operator [] if paths dont exist 5851a19eaddSMike Capps if (_objects.find(path) != _objects.end() && 5861a19eaddSMike Capps _objects[path].find(intf) != _objects[path].end()) 5871a19eaddSMike Capps { 5881a19eaddSMike Capps _objects[path][intf].erase(prop); 5891a19eaddSMike Capps } 5901a19eaddSMike Capps } 5911a19eaddSMike Capps else 5921a19eaddSMike Capps { 5931a19eaddSMike Capps _objects[path][intf][prop] = std::move(value); 5941a19eaddSMike Capps } 5951a19eaddSMike Capps } 5961a19eaddSMike Capps 597d9cb63b6SMatthew Barth void Manager::addTimer(const TimerType type, 598d9cb63b6SMatthew Barth const std::chrono::microseconds interval, 599d9cb63b6SMatthew Barth std::unique_ptr<TimerPkg> pkg) 600d9cb63b6SMatthew Barth { 601d9cb63b6SMatthew Barth auto dataPtr = 602d9cb63b6SMatthew Barth std::make_unique<TimerData>(std::make_pair(type, std::move(*pkg))); 603d9cb63b6SMatthew Barth Timer timer(_event, 604d9cb63b6SMatthew Barth std::bind(&Manager::timerExpired, this, std::ref(*dataPtr))); 605d9cb63b6SMatthew Barth if (type == TimerType::repeating) 606d9cb63b6SMatthew Barth { 607d9cb63b6SMatthew Barth timer.restart(interval); 608d9cb63b6SMatthew Barth } 609d9cb63b6SMatthew Barth else if (type == TimerType::oneshot) 610d9cb63b6SMatthew Barth { 611d9cb63b6SMatthew Barth timer.restartOnce(interval); 612d9cb63b6SMatthew Barth } 613d9cb63b6SMatthew Barth else 614d9cb63b6SMatthew Barth { 615d9cb63b6SMatthew Barth throw std::invalid_argument("Invalid Timer Type"); 616d9cb63b6SMatthew Barth } 617d9cb63b6SMatthew Barth _timers.emplace_back(std::move(dataPtr), std::move(timer)); 618d9cb63b6SMatthew Barth } 619d9cb63b6SMatthew Barth 620ade0c377SMatt Spinler void Manager::addGroup(const Group& group) 621ade0c377SMatt Spinler { 62255627adfSMatthew Barth std::set<std::string> services; 62355627adfSMatthew Barth for (const auto& member : group.getMembers()) 624ade0c377SMatt Spinler { 625ade0c377SMatt Spinler try 626ade0c377SMatt Spinler { 62755627adfSMatthew Barth const auto& service = 62855627adfSMatthew Barth util::SDBusPlus::getService(member, group.getInterface()); 629ade0c377SMatt Spinler 63055627adfSMatthew Barth // TODO - Optimize to only retrieve the paths on this service 63155627adfSMatthew Barth auto objMgrPaths = 63255627adfSMatthew Barth getPaths(service, "org.freedesktop.DBus.ObjectManager"); 63355627adfSMatthew Barth 63455627adfSMatthew Barth // Look for the ObjectManager as an ancestor from the member. 63555627adfSMatthew Barth auto hasObjMgr = 63655627adfSMatthew Barth std::any_of(objMgrPaths.begin(), objMgrPaths.end(), 63755627adfSMatthew Barth [&member](const auto& path) { 63855627adfSMatthew Barth return member.find(path) != std::string::npos; 63955627adfSMatthew Barth }); 64055627adfSMatthew Barth 64155627adfSMatthew Barth if (!hasObjMgr) 64255627adfSMatthew Barth { 64355627adfSMatthew Barth // No object manager interface provided for group member 64455627adfSMatthew Barth // Attempt to retrieve group member property directly 64555627adfSMatthew Barth auto value = 646ade0c377SMatt Spinler util::SDBusPlus::getPropertyVariant<PropertyVariantType>( 64755627adfSMatthew Barth _bus, service, member, group.getInterface(), 64855627adfSMatthew Barth group.getProperty()); 649ade0c377SMatt Spinler 650ade0c377SMatt Spinler setProperty(member, group.getInterface(), group.getProperty(), 65155627adfSMatthew Barth value); 65255627adfSMatthew Barth continue; 653ade0c377SMatt Spinler } 65455627adfSMatthew Barth 65555627adfSMatthew Barth if (services.find(service) == services.end()) 656ade0c377SMatt Spinler { 65755627adfSMatthew Barth services.insert(service); 65855627adfSMatthew Barth for (const auto& objMgrPath : objMgrPaths) 659ade0c377SMatt Spinler { 66055627adfSMatthew Barth // Get all managed objects from the service 66155627adfSMatthew Barth auto objects = 66255627adfSMatthew Barth util::SDBusPlus::getManagedObjects<PropertyVariantType>( 66355627adfSMatthew Barth _bus, service, objMgrPath); 66455627adfSMatthew Barth 66555627adfSMatthew Barth // Insert objects into cache 66655627adfSMatthew Barth insertFilteredObjects(objects); 667ade0c377SMatt Spinler } 66855627adfSMatthew Barth } 66955627adfSMatthew Barth } 67055627adfSMatthew Barth catch (const util::DBusServiceError&) 67155627adfSMatthew Barth { 67255627adfSMatthew Barth // No service found for group member containing the group's 67355627adfSMatthew Barth // configured interface 67455627adfSMatthew Barth continue; 675ade0c377SMatt Spinler } 676ade0c377SMatt Spinler } 677ade0c377SMatt Spinler } 678ade0c377SMatt Spinler 679d9cb63b6SMatthew Barth void Manager::timerExpired(TimerData& data) 680d9cb63b6SMatthew Barth { 681ade0c377SMatt Spinler if (std::get<bool>(data.second)) 682ade0c377SMatt Spinler { 683ade0c377SMatt Spinler const auto& groups = std::get<const std::vector<Group>&>(data.second); 684ade0c377SMatt Spinler std::for_each(groups.begin(), groups.end(), 685ade0c377SMatt Spinler [this](const auto& group) { addGroup(group); }); 686ade0c377SMatt Spinler } 687ade0c377SMatt Spinler 688d9cb63b6SMatthew Barth auto& actions = 689d9cb63b6SMatthew Barth std::get<std::vector<std::unique_ptr<ActionBase>>&>(data.second); 690d9cb63b6SMatthew Barth // Perform the actions in the timer data 691d9cb63b6SMatthew Barth std::for_each(actions.begin(), actions.end(), 69200f6aa09SMatthew Barth [](auto& action) { action->run(); }); 693d9cb63b6SMatthew Barth 694d9cb63b6SMatthew Barth // Remove oneshot timers after they expired 695d9cb63b6SMatthew Barth if (data.first == TimerType::oneshot) 696d9cb63b6SMatthew Barth { 697d9cb63b6SMatthew Barth auto itTimer = std::find_if( 698d9cb63b6SMatthew Barth _timers.begin(), _timers.end(), [&data](const auto& timer) { 699d9cb63b6SMatthew Barth return (data.first == timer.first->first && 700d9cb63b6SMatthew Barth (std::get<std::string>(data.second) == 701d9cb63b6SMatthew Barth std::get<std::string>(timer.first->second))); 702d9cb63b6SMatthew Barth }); 703d9cb63b6SMatthew Barth if (itTimer != std::end(_timers)) 704d9cb63b6SMatthew Barth { 705d9cb63b6SMatthew Barth _timers.erase(itTimer); 706d9cb63b6SMatthew Barth } 707d9cb63b6SMatthew Barth } 708d9cb63b6SMatthew Barth } 709d9cb63b6SMatthew Barth 710ebabc040SMatthew Barth void Manager::handleSignal(sdbusplus::message::message& msg, 711c024d780SMatthew Barth const std::vector<SignalPkg>* pkgs) 712ebabc040SMatthew Barth { 713c024d780SMatthew Barth for (auto& pkg : *pkgs) 714ebabc040SMatthew Barth { 715ebabc040SMatthew Barth // Handle the signal callback and only run the actions if the handler 716ebabc040SMatthew Barth // updated the cache for the given SignalObject 717ebabc040SMatthew Barth if (std::get<SignalHandler>(pkg)(msg, std::get<SignalObject>(pkg), 718ebabc040SMatthew Barth *this)) 719ebabc040SMatthew Barth { 720ebabc040SMatthew Barth // Perform the actions in the handler package 721d0ba86a3SMatt Spinler auto& actions = std::get<TriggerActions>(pkg); 722c3a69087SMatthew Barth std::for_each(actions.begin(), actions.end(), [](auto& action) { 723c3a69087SMatthew Barth if (action.get()) 724c3a69087SMatthew Barth { 725c3a69087SMatthew Barth action.get()->run(); 726c3a69087SMatthew Barth } 727c3a69087SMatthew Barth }); 728ebabc040SMatthew Barth } 729c024d780SMatthew Barth // Only rewind message when not last package 730c024d780SMatthew Barth if (&pkg != &pkgs->back()) 731c024d780SMatthew Barth { 732c024d780SMatthew Barth sd_bus_message_rewind(msg.get(), true); 733c024d780SMatthew Barth } 734ebabc040SMatthew Barth } 735ebabc040SMatthew Barth } 736ebabc040SMatthew Barth 737acd737cdSMatthew Barth void Manager::setProfiles() 738acd737cdSMatthew Barth { 739acd737cdSMatthew Barth // Profiles JSON config file is optional 740acd737cdSMatthew Barth auto confFile = fan::JsonConfig::getConfFile(_bus, confAppName, 741acd737cdSMatthew Barth Profile::confFileName, true); 742e91ac864SMatthew Barth 743e91ac864SMatthew Barth _profiles.clear(); 744acd737cdSMatthew Barth if (!confFile.empty()) 745acd737cdSMatthew Barth { 746acd737cdSMatthew Barth for (const auto& entry : fan::JsonConfig::load(confFile)) 747acd737cdSMatthew Barth { 748acd737cdSMatthew Barth auto obj = std::make_unique<Profile>(entry); 749acd737cdSMatthew Barth _profiles.emplace( 750acd737cdSMatthew Barth std::make_pair(obj->getName(), obj->getProfiles()), 751acd737cdSMatthew Barth std::move(obj)); 752acd737cdSMatthew Barth } 753acd737cdSMatthew Barth } 754e91ac864SMatthew Barth 755acd737cdSMatthew Barth // Ensure all configurations use the same set of active profiles 756acd737cdSMatthew Barth // (In case a profile's active state changes during configuration) 757e91ac864SMatthew Barth _activeProfiles.clear(); 758acd737cdSMatthew Barth for (const auto& profile : _profiles) 759acd737cdSMatthew Barth { 760acd737cdSMatthew Barth if (profile.second->isActive()) 761acd737cdSMatthew Barth { 762acd737cdSMatthew Barth _activeProfiles.emplace_back(profile.first.first); 763acd737cdSMatthew Barth } 764acd737cdSMatthew Barth } 765acd737cdSMatthew Barth } 766acd737cdSMatthew Barth 767d0ba86a3SMatt Spinler void Manager::addParameterTrigger( 768d0ba86a3SMatt Spinler const std::string& name, std::vector<std::unique_ptr<ActionBase>>& actions) 769d0ba86a3SMatt Spinler { 770d0ba86a3SMatt Spinler auto it = _parameterTriggers.find(name); 771d0ba86a3SMatt Spinler if (it != _parameterTriggers.end()) 772d0ba86a3SMatt Spinler { 773d0ba86a3SMatt Spinler std::for_each(actions.begin(), actions.end(), 774d0ba86a3SMatt Spinler [&actList = it->second](auto& action) { 775d0ba86a3SMatt Spinler actList.emplace_back(std::ref(action)); 776d0ba86a3SMatt Spinler }); 777d0ba86a3SMatt Spinler } 778d0ba86a3SMatt Spinler else 779d0ba86a3SMatt Spinler { 780d0ba86a3SMatt Spinler TriggerActions triggerActions; 781d0ba86a3SMatt Spinler std::for_each(actions.begin(), actions.end(), 782d0ba86a3SMatt Spinler [&triggerActions](auto& action) { 783d0ba86a3SMatt Spinler triggerActions.emplace_back(std::ref(action)); 784d0ba86a3SMatt Spinler }); 785d0ba86a3SMatt Spinler _parameterTriggers[name] = std::move(triggerActions); 786d0ba86a3SMatt Spinler } 787d0ba86a3SMatt Spinler } 788d0ba86a3SMatt Spinler 789d0ba86a3SMatt Spinler void Manager::runParameterActions(const std::string& name) 790d0ba86a3SMatt Spinler { 791d0ba86a3SMatt Spinler auto it = _parameterTriggers.find(name); 792d0ba86a3SMatt Spinler if (it != _parameterTriggers.end()) 793d0ba86a3SMatt Spinler { 794d0ba86a3SMatt Spinler std::for_each(it->second.begin(), it->second.end(), 795d0ba86a3SMatt Spinler [](auto& action) { action.get()->run(); }); 796d0ba86a3SMatt Spinler } 797d0ba86a3SMatt Spinler } 798d0ba86a3SMatt Spinler 799a227a16dSMatthew Barth } // namespace phosphor::fan::control::json 800