1a227a16dSMatthew Barth /** 2b2e9a4fcSMike Capps * Copyright © 2022 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*bf8e56f6SMike Capps #include "dbus_paths.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" 29bd52ed02SMatthew Barth #include "utils/flight_recorder.hpp" 30acd737cdSMatthew Barth #include "zone.hpp" 31a227a16dSMatthew Barth 32c024d780SMatthew Barth #include <systemd/sd-bus.h> 33c024d780SMatthew Barth 34acd737cdSMatthew Barth #include <nlohmann/json.hpp> 35a227a16dSMatthew Barth #include <sdbusplus/bus.hpp> 361542fb5aSMatthew Barth #include <sdbusplus/server/manager.hpp> 37acd737cdSMatthew Barth #include <sdeventplus/event.hpp> 38d9cb63b6SMatthew Barth #include <sdeventplus/utility/timer.hpp> 39a227a16dSMatthew Barth 40de90fb4dSMatthew Barth #include <algorithm> 41d9cb63b6SMatthew Barth #include <chrono> 42a227a16dSMatthew Barth #include <filesystem> 43d9cb63b6SMatthew Barth #include <functional> 44d9cb63b6SMatthew Barth #include <map> 45d9cb63b6SMatthew Barth #include <memory> 46d9cb63b6SMatthew Barth #include <tuple> 47d9cb63b6SMatthew Barth #include <utility> 4806764946SMatthew Barth #include <vector> 49a227a16dSMatthew Barth 50a227a16dSMatthew Barth namespace phosphor::fan::control::json 51a227a16dSMatthew Barth { 52a227a16dSMatthew Barth 53acd737cdSMatthew Barth using json = nlohmann::json; 54acd737cdSMatthew Barth 55acd737cdSMatthew Barth std::vector<std::string> Manager::_activeProfiles; 5612cb125aSMatthew Barth std::map<std::string, 574ca87faeSMatthew Barth std::map<std::string, std::pair<bool, std::vector<std::string>>>> 5812cb125aSMatthew Barth Manager::_servTree; 5907fecfc6SMatthew Barth std::map<std::string, 6007fecfc6SMatthew Barth std::map<std::string, std::map<std::string, PropertyVariantType>>> 6107fecfc6SMatthew Barth Manager::_objects; 62d76351bdSMatt Spinler std::unordered_map<std::string, PropertyVariantType> Manager::_parameters; 63d0ba86a3SMatt Spinler std::unordered_map<std::string, TriggerActions> Manager::_parameterTriggers; 64acd737cdSMatthew Barth 657787def0SMatt Spinler const std::string Manager::dumpFile = "/tmp/fan_control_dump.json"; 667787def0SMatt Spinler 679403a217SMatthew Barth Manager::Manager(const sdeventplus::Event& event) : 6848f44daaSMatthew Barth _bus(util::SDBusPlus::getBus()), _event(event), 693770a1daSMatthew Barth _mgr(util::SDBusPlus::getBus(), CONTROL_OBJPATH), _loadAllowed(true), 7048f44daaSMatthew Barth _powerState(std::make_unique<PGoodState>( 7148f44daaSMatthew Barth util::SDBusPlus::getBus(), 7248f44daaSMatthew Barth std::bind(std::mem_fn(&Manager::powerStateChanged), this, 7348f44daaSMatthew Barth std::placeholders::_1))) 743770a1daSMatthew Barth {} 75e91ac864SMatthew Barth 76e91ac864SMatthew Barth void Manager::sighupHandler(sdeventplus::source::Signal&, 77e91ac864SMatthew Barth const struct signalfd_siginfo*) 78e91ac864SMatthew Barth { 79bd52ed02SMatthew Barth FlightRecorder::instance().log("main", "SIGHUP received"); 80e91ac864SMatthew Barth // Save current set of available and active profiles 81e91ac864SMatthew Barth std::map<configKey, std::unique_ptr<Profile>> profiles; 82e91ac864SMatthew Barth profiles.swap(_profiles); 83e91ac864SMatthew Barth std::vector<std::string> activeProfiles; 84e91ac864SMatthew Barth activeProfiles.swap(_activeProfiles); 85e91ac864SMatthew Barth 86e91ac864SMatthew Barth try 87e91ac864SMatthew Barth { 883770a1daSMatthew Barth _loadAllowed = true; 89e91ac864SMatthew Barth load(); 90e91ac864SMatthew Barth } 91ddb773b2SPatrick Williams catch (const std::runtime_error& re) 92e91ac864SMatthew Barth { 93e91ac864SMatthew Barth // Restore saved available and active profiles 943770a1daSMatthew Barth _loadAllowed = false; 95e91ac864SMatthew Barth _profiles.swap(profiles); 96e91ac864SMatthew Barth _activeProfiles.swap(activeProfiles); 97e91ac864SMatthew Barth log<level::ERR>("Error reloading configs, no changes made", 98e91ac864SMatthew Barth entry("LOAD_ERROR=%s", re.what())); 99bd52ed02SMatthew Barth FlightRecorder::instance().log( 100bd52ed02SMatthew Barth "main", fmt::format("Error reloading configs, no changes made: {}", 101bd52ed02SMatthew Barth re.what())); 102e91ac864SMatthew Barth } 103e91ac864SMatthew Barth } 104e91ac864SMatthew Barth 1052fc0a35dSMatt Spinler void Manager::sigUsr1Handler(sdeventplus::source::Signal&, 1062fc0a35dSMatt Spinler const struct signalfd_siginfo*) 1072fc0a35dSMatt Spinler { 1087787def0SMatt Spinler debugDumpEventSource = std::make_unique<sdeventplus::source::Defer>( 1097787def0SMatt Spinler _event, std::bind(std::mem_fn(&Manager::dumpDebugData), this, 1102fc0a35dSMatt Spinler std::placeholders::_1)); 1112fc0a35dSMatt Spinler } 1122fc0a35dSMatt Spinler 1137787def0SMatt Spinler void Manager::dumpDebugData(sdeventplus::source::EventBase& /*source*/) 1142fc0a35dSMatt Spinler { 1157787def0SMatt Spinler json data; 1167787def0SMatt Spinler FlightRecorder::instance().dump(data); 117b5c21a24SMatt Spinler dumpCache(data); 1187787def0SMatt Spinler 1199db6dd1dSMatt Spinler std::for_each(_zones.begin(), _zones.end(), [&data](const auto& zone) { 1209db6dd1dSMatt Spinler data["zones"][zone.second->getName()] = zone.second->dump(); 1219db6dd1dSMatt Spinler }); 1229db6dd1dSMatt Spinler 1237787def0SMatt Spinler std::ofstream file{Manager::dumpFile}; 1247787def0SMatt Spinler if (!file) 1257787def0SMatt Spinler { 1267787def0SMatt Spinler log<level::ERR>("Could not open file for fan dump"); 1277787def0SMatt Spinler return; 1287787def0SMatt Spinler } 1297787def0SMatt Spinler 1307787def0SMatt Spinler file << std::setw(4) << data; 1317787def0SMatt Spinler 1327787def0SMatt Spinler debugDumpEventSource.reset(); 1332fc0a35dSMatt Spinler } 1342fc0a35dSMatt Spinler 135b5c21a24SMatt Spinler void Manager::dumpCache(json& data) 136b5c21a24SMatt Spinler { 137b5c21a24SMatt Spinler auto& objects = data["objects"]; 138b5c21a24SMatt Spinler for (const auto& [path, interfaces] : _objects) 139b5c21a24SMatt Spinler { 140b5c21a24SMatt Spinler auto& interfaceJSON = objects[path]; 141b5c21a24SMatt Spinler 142b5c21a24SMatt Spinler for (const auto& [interface, properties] : interfaces) 143b5c21a24SMatt Spinler { 144b5c21a24SMatt Spinler auto& propertyJSON = interfaceJSON[interface]; 145b5c21a24SMatt Spinler for (const auto& [propName, propValue] : properties) 146b5c21a24SMatt Spinler { 147b5c21a24SMatt Spinler std::visit( 148b5c21a24SMatt Spinler [&obj = propertyJSON[propName]](auto&& val) { obj = val; }, 149b5c21a24SMatt Spinler propValue); 150b5c21a24SMatt Spinler } 151b5c21a24SMatt Spinler } 152b5c21a24SMatt Spinler } 153b5c21a24SMatt Spinler 154b5c21a24SMatt Spinler auto& parameters = data["parameters"]; 155b5c21a24SMatt Spinler for (const auto& [name, value] : _parameters) 156b5c21a24SMatt Spinler { 15729088e79SMatt Spinler std::visit([&obj = parameters[name]](auto&& val) { obj = val; }, value); 158b5c21a24SMatt Spinler } 159b5c21a24SMatt Spinler 160c3eb7b3cSMatt Spinler std::for_each(_events.begin(), _events.end(), [&data](const auto& event) { 161c3eb7b3cSMatt Spinler data["events"][event.second->getName()] = event.second->dump(); 162c3eb7b3cSMatt Spinler }); 163c3eb7b3cSMatt Spinler 164b5c21a24SMatt Spinler data["services"] = _servTree; 165b5c21a24SMatt Spinler } 166b5c21a24SMatt Spinler 167e91ac864SMatthew Barth void Manager::load() 168e91ac864SMatthew Barth { 1693770a1daSMatthew Barth if (_loadAllowed) 1703770a1daSMatthew Barth { 171e91ac864SMatthew Barth // Load the available profiles and which are active 172acd737cdSMatthew Barth setProfiles(); 173acd737cdSMatthew Barth 174acd737cdSMatthew Barth // Load the zone configurations 175e91ac864SMatthew Barth auto zones = getConfig<Zone>(false, _event, this); 176de90fb4dSMatthew Barth // Load the fan configurations and move each fan into its zone 1779403a217SMatthew Barth auto fans = getConfig<Fan>(false); 178de90fb4dSMatthew Barth for (auto& fan : fans) 179de90fb4dSMatthew Barth { 1800206c728SMatthew Barth configKey fanProfile = 1810206c728SMatthew Barth std::make_pair(fan.second->getZone(), fan.first.second); 1820206c728SMatthew Barth auto itZone = std::find_if( 183e91ac864SMatthew Barth zones.begin(), zones.end(), [&fanProfile](const auto& zone) { 1840206c728SMatthew Barth return Manager::inConfig(fanProfile, zone.first); 185de90fb4dSMatthew Barth }); 186e91ac864SMatthew Barth if (itZone != zones.end()) 187de90fb4dSMatthew Barth { 1886f787309SMatthew Barth if (itZone->second->getTarget() != fan.second->getTarget() && 1896f787309SMatthew Barth fan.second->getTarget() != 0) 1906f787309SMatthew Barth { 191e91ac864SMatthew Barth // Update zone target to current target of the fan in the 192e91ac864SMatthew Barth // zone 1936f787309SMatthew Barth itZone->second->setTarget(fan.second->getTarget()); 1946f787309SMatthew Barth } 195de90fb4dSMatthew Barth itZone->second->addFan(std::move(fan.second)); 196de90fb4dSMatthew Barth } 197de90fb4dSMatthew Barth } 198e91ac864SMatthew Barth 1993695ac30SMatthew Barth // Save all currently available groups, if any, then clear for reloading 2003695ac30SMatthew Barth auto groups = std::move(Event::getAllGroups(false)); 2013695ac30SMatthew Barth Event::clearAllGroups(); 2023695ac30SMatthew Barth 2033695ac30SMatthew Barth std::map<configKey, std::unique_ptr<Event>> events; 2043695ac30SMatthew Barth try 2053695ac30SMatthew Barth { 2063695ac30SMatthew Barth // Load any events configured, including all the groups 2073695ac30SMatthew Barth events = getConfig<Event>(true, this, zones); 2083695ac30SMatthew Barth } 2093695ac30SMatthew Barth catch (const std::runtime_error& re) 2103695ac30SMatthew Barth { 2113695ac30SMatthew Barth // Restore saved set of all available groups for current events 2123695ac30SMatthew Barth Event::setAllGroups(std::move(groups)); 2133695ac30SMatthew Barth throw re; 2143695ac30SMatthew Barth } 215e91ac864SMatthew Barth 21614303a45SMatthew Barth // Enable zones 217e91ac864SMatthew Barth _zones = std::move(zones); 21814303a45SMatthew Barth std::for_each(_zones.begin(), _zones.end(), 21914303a45SMatthew Barth [](const auto& entry) { entry.second->enable(); }); 220b584d818SMatthew Barth 221e91ac864SMatthew Barth // Clear current timers and signal subscriptions before enabling events 2223770a1daSMatthew Barth // To save reloading services and/or objects into cache, do not clear 2233770a1daSMatthew Barth // cache 224e91ac864SMatthew Barth _timers.clear(); 225e91ac864SMatthew Barth _signals.clear(); 226e91ac864SMatthew Barth 227e91ac864SMatthew Barth // Enable events 228e91ac864SMatthew Barth _events = std::move(events); 22954b5a24fSMatthew Barth std::for_each(_events.begin(), _events.end(), 23054b5a24fSMatthew Barth [](const auto& entry) { entry.second->enable(); }); 2313770a1daSMatthew Barth 2323770a1daSMatthew Barth _loadAllowed = false; 2333770a1daSMatthew Barth } 23406764946SMatthew Barth } 235acd737cdSMatthew Barth 23648f44daaSMatthew Barth void Manager::powerStateChanged(bool powerStateOn) 23748f44daaSMatthew Barth { 23848f44daaSMatthew Barth if (powerStateOn) 23948f44daaSMatthew Barth { 2406a2418a2SMatthew Barth if (_zones.empty()) 2416a2418a2SMatthew Barth { 2426a2418a2SMatthew Barth throw std::runtime_error("No configured zones found at poweron"); 2436a2418a2SMatthew Barth } 24448f44daaSMatthew Barth std::for_each(_zones.begin(), _zones.end(), [](const auto& entry) { 24548f44daaSMatthew Barth entry.second->setTarget(entry.second->getPoweronTarget()); 24648f44daaSMatthew Barth }); 247d1f97f43SMatt Spinler 248d1f97f43SMatt Spinler // Tell events to run their power on triggers 249d1f97f43SMatt Spinler std::for_each(_events.begin(), _events.end(), 250d1f97f43SMatt Spinler [](const auto& entry) { entry.second->powerOn(); }); 251d1f97f43SMatt Spinler } 252d1f97f43SMatt Spinler else 253d1f97f43SMatt Spinler { 254d1f97f43SMatt Spinler // Tell events to run their power off triggers 255d1f97f43SMatt Spinler std::for_each(_events.begin(), _events.end(), 256d1f97f43SMatt Spinler [](const auto& entry) { entry.second->powerOff(); }); 25748f44daaSMatthew Barth } 25848f44daaSMatthew Barth } 25948f44daaSMatthew Barth 260acd737cdSMatthew Barth const std::vector<std::string>& Manager::getActiveProfiles() 261acd737cdSMatthew Barth { 262acd737cdSMatthew Barth return _activeProfiles; 263a227a16dSMatthew Barth } 264a227a16dSMatthew Barth 2650206c728SMatthew Barth bool Manager::inConfig(const configKey& input, const configKey& comp) 2660206c728SMatthew Barth { 2670206c728SMatthew Barth // Config names dont match, do not include in config 2680206c728SMatthew Barth if (input.first != comp.first) 2690206c728SMatthew Barth { 2700206c728SMatthew Barth return false; 2710206c728SMatthew Barth } 2720206c728SMatthew Barth // No profiles specified by input config, can be used in any config 2730206c728SMatthew Barth if (input.second.empty()) 2740206c728SMatthew Barth { 2750206c728SMatthew Barth return true; 2760206c728SMatthew Barth } 2770206c728SMatthew Barth else 2780206c728SMatthew Barth { 2790206c728SMatthew Barth // Profiles must have one match in the other's profiles(and they must be 2800206c728SMatthew Barth // an active profile) to be used in the config 2810206c728SMatthew Barth return std::any_of( 2820206c728SMatthew Barth input.second.begin(), input.second.end(), 2830206c728SMatthew Barth [&comp](const auto& lProfile) { 2840206c728SMatthew Barth return std::any_of( 2850206c728SMatthew Barth comp.second.begin(), comp.second.end(), 2860206c728SMatthew Barth [&lProfile](const auto& rProfile) { 2870206c728SMatthew Barth if (lProfile != rProfile) 2880206c728SMatthew Barth { 2890206c728SMatthew Barth return false; 2900206c728SMatthew Barth } 2910206c728SMatthew Barth auto activeProfs = getActiveProfiles(); 2920206c728SMatthew Barth return std::find(activeProfs.begin(), activeProfs.end(), 2930206c728SMatthew Barth lProfile) != activeProfs.end(); 2940206c728SMatthew Barth }); 2950206c728SMatthew Barth }); 2960206c728SMatthew Barth } 2970206c728SMatthew Barth } 2980206c728SMatthew Barth 29912cb125aSMatthew Barth bool Manager::hasOwner(const std::string& path, const std::string& intf) 30012cb125aSMatthew Barth { 30112cb125aSMatthew Barth auto itServ = _servTree.find(path); 30212cb125aSMatthew Barth if (itServ == _servTree.end()) 30312cb125aSMatthew Barth { 30412cb125aSMatthew Barth // Path not found in cache, therefore owner missing 30512cb125aSMatthew Barth return false; 30612cb125aSMatthew Barth } 3074ca87faeSMatthew Barth for (const auto& service : itServ->second) 30812cb125aSMatthew Barth { 30912cb125aSMatthew Barth auto itIntf = std::find_if( 3104ca87faeSMatthew Barth service.second.second.begin(), service.second.second.end(), 31112cb125aSMatthew Barth [&intf](const auto& interface) { return intf == interface; }); 3124ca87faeSMatthew Barth if (itIntf != std::end(service.second.second)) 31312cb125aSMatthew Barth { 31412cb125aSMatthew Barth // Service found, return owner state 3154ca87faeSMatthew Barth return service.second.first; 31612cb125aSMatthew Barth } 31712cb125aSMatthew Barth } 31812cb125aSMatthew Barth // Interface not found in cache, therefore owner missing 31912cb125aSMatthew Barth return false; 32012cb125aSMatthew Barth } 32112cb125aSMatthew Barth 3226d8e2d3eSMatthew Barth void Manager::setOwner(const std::string& serv, bool hasOwner) 3236d8e2d3eSMatthew Barth { 3246d8e2d3eSMatthew Barth // Update owner state on all entries of `serv` 3256d8e2d3eSMatthew Barth for (auto& itPath : _servTree) 3266d8e2d3eSMatthew Barth { 3276d8e2d3eSMatthew Barth auto itServ = itPath.second.find(serv); 3286d8e2d3eSMatthew Barth if (itServ != itPath.second.end()) 3296d8e2d3eSMatthew Barth { 3306d8e2d3eSMatthew Barth itServ->second.first = hasOwner; 3316d8e2d3eSMatthew Barth 3326d8e2d3eSMatthew Barth // Remove associated interfaces from object cache when service no 3336d8e2d3eSMatthew Barth // longer has an owner 3346d8e2d3eSMatthew Barth if (!hasOwner && _objects.find(itPath.first) != _objects.end()) 3356d8e2d3eSMatthew Barth { 3366d8e2d3eSMatthew Barth for (auto& intf : itServ->second.second) 3376d8e2d3eSMatthew Barth { 3386d8e2d3eSMatthew Barth _objects[itPath.first].erase(intf); 3396d8e2d3eSMatthew Barth } 3406d8e2d3eSMatthew Barth } 3416d8e2d3eSMatthew Barth } 3426d8e2d3eSMatthew Barth } 3436d8e2d3eSMatthew Barth } 3446d8e2d3eSMatthew Barth 3454ca87faeSMatthew Barth void Manager::setOwner(const std::string& path, const std::string& serv, 3464ca87faeSMatthew Barth const std::string& intf, bool isOwned) 3474ca87faeSMatthew Barth { 3482a9e7b2eSMatthew Barth // Set owner state for specific object given 3492a9e7b2eSMatthew Barth auto& ownIntf = _servTree[path][serv]; 3502a9e7b2eSMatthew Barth ownIntf.first = isOwned; 3514ca87faeSMatthew Barth auto itIntf = std::find_if( 3522a9e7b2eSMatthew Barth ownIntf.second.begin(), ownIntf.second.end(), 3534ca87faeSMatthew Barth [&intf](const auto& interface) { return intf == interface; }); 3542a9e7b2eSMatthew Barth if (itIntf == std::end(ownIntf.second)) 3554ca87faeSMatthew Barth { 3562a9e7b2eSMatthew Barth ownIntf.second.emplace_back(intf); 3572a9e7b2eSMatthew Barth } 3582a9e7b2eSMatthew Barth 3592a9e7b2eSMatthew Barth // Update owner state on all entries of the same `serv` & `intf` 3602a9e7b2eSMatthew Barth for (auto& itPath : _servTree) 3614ca87faeSMatthew Barth { 3622a9e7b2eSMatthew Barth if (itPath.first == path) 3632a9e7b2eSMatthew Barth { 3642a9e7b2eSMatthew Barth // Already set/updated owner on this path for `serv` & `intf` 3652a9e7b2eSMatthew Barth continue; 3662a9e7b2eSMatthew Barth } 3672a9e7b2eSMatthew Barth for (auto& itServ : itPath.second) 3682a9e7b2eSMatthew Barth { 3692a9e7b2eSMatthew Barth if (itServ.first != serv) 3702a9e7b2eSMatthew Barth { 3712a9e7b2eSMatthew Barth continue; 3722a9e7b2eSMatthew Barth } 3732a9e7b2eSMatthew Barth auto itIntf = std::find_if( 3742a9e7b2eSMatthew Barth itServ.second.second.begin(), itServ.second.second.end(), 3752a9e7b2eSMatthew Barth [&intf](const auto& interface) { return intf == interface; }); 3762a9e7b2eSMatthew Barth if (itIntf != std::end(itServ.second.second)) 3772a9e7b2eSMatthew Barth { 3782a9e7b2eSMatthew Barth itServ.second.first = isOwned; 3794ca87faeSMatthew Barth } 3804ca87faeSMatthew Barth } 3814ca87faeSMatthew Barth } 3824ca87faeSMatthew Barth } 3834ca87faeSMatthew Barth 3844ca87faeSMatthew Barth const std::string& Manager::findService(const std::string& path, 3854ca87faeSMatthew Barth const std::string& intf) 3864ca87faeSMatthew Barth { 3874ca87faeSMatthew Barth static const std::string empty = ""; 3884ca87faeSMatthew Barth 3894ca87faeSMatthew Barth auto itServ = _servTree.find(path); 3904ca87faeSMatthew Barth if (itServ != _servTree.end()) 3914ca87faeSMatthew Barth { 3924ca87faeSMatthew Barth for (const auto& service : itServ->second) 3934ca87faeSMatthew Barth { 3944ca87faeSMatthew Barth auto itIntf = std::find_if( 3954ca87faeSMatthew Barth service.second.second.begin(), service.second.second.end(), 3964ca87faeSMatthew Barth [&intf](const auto& interface) { return intf == interface; }); 3974ca87faeSMatthew Barth if (itIntf != std::end(service.second.second)) 3984ca87faeSMatthew Barth { 3994ca87faeSMatthew Barth // Service found, return service name 4004ca87faeSMatthew Barth return service.first; 4014ca87faeSMatthew Barth } 4024ca87faeSMatthew Barth } 4034ca87faeSMatthew Barth } 4044ca87faeSMatthew Barth 4054ca87faeSMatthew Barth return empty; 4064ca87faeSMatthew Barth } 4074ca87faeSMatthew Barth 40898f6fc17SMatthew Barth void Manager::addServices(const std::string& intf, int32_t depth) 4094ca87faeSMatthew Barth { 4104ca87faeSMatthew Barth // Get all subtree objects for the given interface 41134835150SMatt Spinler auto objects = util::SDBusPlus::getSubTreeRaw(util::SDBusPlus::getBus(), 41234835150SMatt Spinler "/", intf, depth); 4134ca87faeSMatthew Barth // Add what's returned to the cache of path->services 4144ca87faeSMatthew Barth for (auto& itPath : objects) 4154ca87faeSMatthew Barth { 4164ca87faeSMatthew Barth auto pathIter = _servTree.find(itPath.first); 4174ca87faeSMatthew Barth if (pathIter != _servTree.end()) 4184ca87faeSMatthew Barth { 4194ca87faeSMatthew Barth // Path found in cache 4204ca87faeSMatthew Barth for (auto& itServ : itPath.second) 4214ca87faeSMatthew Barth { 4224ca87faeSMatthew Barth auto servIter = pathIter->second.find(itServ.first); 4234ca87faeSMatthew Barth if (servIter != pathIter->second.end()) 4244ca87faeSMatthew Barth { 4254ca87faeSMatthew Barth if (std::find(servIter->second.second.begin(), 4264ca87faeSMatthew Barth servIter->second.second.end(), 427d9f85c9aSMatt Spinler intf) == servIter->second.second.end()) 4284ca87faeSMatthew Barth { 4294ca87faeSMatthew Barth // Add interface to cache 430d9f85c9aSMatt Spinler servIter->second.second.emplace_back(intf); 4314ca87faeSMatthew Barth } 4324ca87faeSMatthew Barth } 4334ca87faeSMatthew Barth else 4344ca87faeSMatthew Barth { 4354ca87faeSMatthew Barth // Service not found in cache 4364ca87faeSMatthew Barth auto intfs = {intf}; 4374ca87faeSMatthew Barth pathIter->second[itServ.first] = 4384ca87faeSMatthew Barth std::make_pair(true, intfs); 4394ca87faeSMatthew Barth } 4404ca87faeSMatthew Barth } 4414ca87faeSMatthew Barth } 4424ca87faeSMatthew Barth else 4434ca87faeSMatthew Barth { 4444ca87faeSMatthew Barth // Path not found in cache 4454ca87faeSMatthew Barth auto intfs = {intf}; 446a0b8a68fSMatt Spinler for (const auto& [servName, servIntfs] : itPath.second) 447a0b8a68fSMatt Spinler { 448a0b8a68fSMatt Spinler _servTree[itPath.first][servName] = std::make_pair(true, intfs); 449a0b8a68fSMatt Spinler } 4504ca87faeSMatthew Barth } 4514ca87faeSMatthew Barth } 4524ca87faeSMatthew Barth } 4534ca87faeSMatthew Barth 4544ca87faeSMatthew Barth const std::string& Manager::getService(const std::string& path, 4554ca87faeSMatthew Barth const std::string& intf) 4564ca87faeSMatthew Barth { 4574ca87faeSMatthew Barth // Retrieve service from cache 4584ca87faeSMatthew Barth const auto& serviceName = findService(path, intf); 4594ca87faeSMatthew Barth if (serviceName.empty()) 4604ca87faeSMatthew Barth { 46198f6fc17SMatthew Barth addServices(intf, 0); 4624ca87faeSMatthew Barth return findService(path, intf); 4634ca87faeSMatthew Barth } 4644ca87faeSMatthew Barth 4654ca87faeSMatthew Barth return serviceName; 4664ca87faeSMatthew Barth } 4674ca87faeSMatthew Barth 468f41e947bSMatthew Barth std::vector<std::string> Manager::findPaths(const std::string& serv, 469f41e947bSMatthew Barth const std::string& intf) 470f41e947bSMatthew Barth { 471f41e947bSMatthew Barth std::vector<std::string> paths; 472f41e947bSMatthew Barth 473f41e947bSMatthew Barth for (const auto& path : _servTree) 474f41e947bSMatthew Barth { 475f41e947bSMatthew Barth auto itServ = path.second.find(serv); 476f41e947bSMatthew Barth if (itServ != path.second.end()) 477f41e947bSMatthew Barth { 478f41e947bSMatthew Barth if (std::find(itServ->second.second.begin(), 479f41e947bSMatthew Barth itServ->second.second.end(), 480f41e947bSMatthew Barth intf) != itServ->second.second.end()) 481f41e947bSMatthew Barth { 482f41e947bSMatthew Barth if (std::find(paths.begin(), paths.end(), path.first) == 483f41e947bSMatthew Barth paths.end()) 484f41e947bSMatthew Barth { 485f41e947bSMatthew Barth paths.push_back(path.first); 486f41e947bSMatthew Barth } 487f41e947bSMatthew Barth } 488f41e947bSMatthew Barth } 489f41e947bSMatthew Barth } 490f41e947bSMatthew Barth 491f41e947bSMatthew Barth return paths; 492f41e947bSMatthew Barth } 493f41e947bSMatthew Barth 494f41e947bSMatthew Barth std::vector<std::string> Manager::getPaths(const std::string& serv, 495f41e947bSMatthew Barth const std::string& intf) 496f41e947bSMatthew Barth { 497f41e947bSMatthew Barth auto paths = findPaths(serv, intf); 498f41e947bSMatthew Barth if (paths.empty()) 499f41e947bSMatthew Barth { 500f41e947bSMatthew Barth addServices(intf, 0); 501f41e947bSMatthew Barth return findPaths(serv, intf); 502f41e947bSMatthew Barth } 503f41e947bSMatthew Barth 504f41e947bSMatthew Barth return paths; 505f41e947bSMatthew Barth } 506f41e947bSMatthew Barth 5071a19eaddSMike Capps void Manager::insertFilteredObjects(ManagedObjects& ref) 5081a19eaddSMike Capps { 509c2c2db7dSMatt Spinler // Filter out objects that aren't part of a group 510c2c2db7dSMatt Spinler const auto& allGroupMembers = Group::getAllMembers(); 511c2c2db7dSMatt Spinler auto it = ref.begin(); 512c2c2db7dSMatt Spinler 513c2c2db7dSMatt Spinler while (it != ref.end()) 514c2c2db7dSMatt Spinler { 515c2c2db7dSMatt Spinler if (allGroupMembers.find(it->first) == allGroupMembers.end()) 516c2c2db7dSMatt Spinler { 517c2c2db7dSMatt Spinler it = ref.erase(it); 518c2c2db7dSMatt Spinler } 519c2c2db7dSMatt Spinler else 520c2c2db7dSMatt Spinler { 521c2c2db7dSMatt Spinler it++; 522c2c2db7dSMatt Spinler } 523c2c2db7dSMatt Spinler } 524c2c2db7dSMatt Spinler 5251a19eaddSMike Capps for (auto& [path, pathMap] : ref) 5261a19eaddSMike Capps { 5271a19eaddSMike Capps for (auto& [intf, intfMap] : pathMap) 5281a19eaddSMike Capps { 5291a19eaddSMike Capps // for each property on this path+interface 5301a19eaddSMike Capps for (auto& [prop, value] : intfMap) 5311a19eaddSMike Capps { 5321a19eaddSMike Capps setProperty(path, intf, prop, value); 5331a19eaddSMike Capps } 5341a19eaddSMike Capps } 5351a19eaddSMike Capps } 5361a19eaddSMike Capps } 5371a19eaddSMike Capps 538f41e947bSMatthew Barth void Manager::addObjects(const std::string& path, const std::string& intf, 5399ac325c5SMatt Spinler const std::string& prop, 5409ac325c5SMatt Spinler const std::string& serviceName) 541f41e947bSMatthew Barth { 5429ac325c5SMatt Spinler auto service = serviceName; 5439ac325c5SMatt Spinler if (service.empty()) 5449ac325c5SMatt Spinler { 5459ac325c5SMatt Spinler service = getService(path, intf); 546f41e947bSMatthew Barth if (service.empty()) 547f41e947bSMatthew Barth { 548f41e947bSMatthew Barth // Log service not found for object 54934835150SMatt Spinler log<level::DEBUG>( 5509ac325c5SMatt Spinler fmt::format( 5519ac325c5SMatt Spinler "Unable to get service name for path {}, interface {}", 552f41e947bSMatthew Barth path, intf) 553f41e947bSMatthew Barth .c_str()); 554f41e947bSMatthew Barth return; 555f41e947bSMatthew Barth } 5569ac325c5SMatt Spinler } 5579ac325c5SMatt Spinler else 5589ac325c5SMatt Spinler { 5599ac325c5SMatt Spinler // The service is known, so the service cache can be 5609ac325c5SMatt Spinler // populated even if the path itself isn't present. 5619ac325c5SMatt Spinler const auto& s = findService(path, intf); 5629ac325c5SMatt Spinler if (s.empty()) 5639ac325c5SMatt Spinler { 5649ac325c5SMatt Spinler addServices(intf, 0); 5659ac325c5SMatt Spinler } 5669ac325c5SMatt Spinler } 567f41e947bSMatthew Barth 568f41e947bSMatthew Barth auto objMgrPaths = getPaths(service, "org.freedesktop.DBus.ObjectManager"); 569f41e947bSMatthew Barth if (objMgrPaths.empty()) 570f41e947bSMatthew Barth { 571f41e947bSMatthew Barth // No object manager interface provided by service? 572f41e947bSMatthew Barth // Attempt to retrieve property directly 573f16f063bSMatt Spinler try 574f16f063bSMatt Spinler { 575f16f063bSMatt Spinler auto value = 576f16f063bSMatt Spinler util::SDBusPlus::getPropertyVariant<PropertyVariantType>( 577f41e947bSMatthew Barth _bus, service, path, intf, prop); 5781a19eaddSMike Capps 5791a19eaddSMike Capps setProperty(path, intf, prop, value); 580f16f063bSMatt Spinler } 581f16f063bSMatt Spinler catch (const std::exception& e) 582f16f063bSMatt Spinler {} 583f41e947bSMatthew Barth return; 584f41e947bSMatthew Barth } 585f41e947bSMatthew Barth 586f41e947bSMatthew Barth for (const auto& objMgrPath : objMgrPaths) 587f41e947bSMatthew Barth { 588f41e947bSMatthew Barth // Get all managed objects of service 589f41e947bSMatthew Barth auto objects = util::SDBusPlus::getManagedObjects<PropertyVariantType>( 590f41e947bSMatthew Barth _bus, service, objMgrPath); 591f41e947bSMatthew Barth 592c2c2db7dSMatt Spinler // insert all objects that are in groups but remove any NaN values 5931a19eaddSMike Capps insertFilteredObjects(objects); 594f41e947bSMatthew Barth } 595f41e947bSMatthew Barth } 596f41e947bSMatthew Barth 597f41e947bSMatthew Barth const std::optional<PropertyVariantType> 598f41e947bSMatthew Barth Manager::getProperty(const std::string& path, const std::string& intf, 599f41e947bSMatthew Barth const std::string& prop) 600f41e947bSMatthew Barth { 601f41e947bSMatthew Barth // TODO Objects hosted by fan control (i.e. ThermalMode) are required to 602f41e947bSMatthew Barth // update the cache upon being set/updated 603f41e947bSMatthew Barth auto itPath = _objects.find(path); 604f41e947bSMatthew Barth if (itPath != _objects.end()) 605f41e947bSMatthew Barth { 606f41e947bSMatthew Barth auto itIntf = itPath->second.find(intf); 607f41e947bSMatthew Barth if (itIntf != itPath->second.end()) 608f41e947bSMatthew Barth { 609f41e947bSMatthew Barth auto itProp = itIntf->second.find(prop); 610f41e947bSMatthew Barth if (itProp != itIntf->second.end()) 611f41e947bSMatthew Barth { 612f41e947bSMatthew Barth return itProp->second; 613f41e947bSMatthew Barth } 614f41e947bSMatthew Barth } 615f41e947bSMatthew Barth } 616f41e947bSMatthew Barth 617f41e947bSMatthew Barth return std::nullopt; 618f41e947bSMatthew Barth } 619f41e947bSMatthew Barth 6201a19eaddSMike Capps void Manager::setProperty(const std::string& path, const std::string& intf, 6211a19eaddSMike Capps const std::string& prop, PropertyVariantType value) 6221a19eaddSMike Capps { 6231a19eaddSMike Capps // filter NaNs out of the cache 6241a19eaddSMike Capps if (PropertyContainsNan(value)) 6251a19eaddSMike Capps { 6261a19eaddSMike Capps // dont use operator [] if paths dont exist 6271a19eaddSMike Capps if (_objects.find(path) != _objects.end() && 6281a19eaddSMike Capps _objects[path].find(intf) != _objects[path].end()) 6291a19eaddSMike Capps { 6301a19eaddSMike Capps _objects[path][intf].erase(prop); 6311a19eaddSMike Capps } 6321a19eaddSMike Capps } 6331a19eaddSMike Capps else 6341a19eaddSMike Capps { 6351a19eaddSMike Capps _objects[path][intf][prop] = std::move(value); 6361a19eaddSMike Capps } 6371a19eaddSMike Capps } 6381a19eaddSMike Capps 639d9cb63b6SMatthew Barth void Manager::addTimer(const TimerType type, 640d9cb63b6SMatthew Barth const std::chrono::microseconds interval, 641d9cb63b6SMatthew Barth std::unique_ptr<TimerPkg> pkg) 642d9cb63b6SMatthew Barth { 643d9cb63b6SMatthew Barth auto dataPtr = 644d9cb63b6SMatthew Barth std::make_unique<TimerData>(std::make_pair(type, std::move(*pkg))); 645d9cb63b6SMatthew Barth Timer timer(_event, 646d9cb63b6SMatthew Barth std::bind(&Manager::timerExpired, this, std::ref(*dataPtr))); 647d9cb63b6SMatthew Barth if (type == TimerType::repeating) 648d9cb63b6SMatthew Barth { 649d9cb63b6SMatthew Barth timer.restart(interval); 650d9cb63b6SMatthew Barth } 651d9cb63b6SMatthew Barth else if (type == TimerType::oneshot) 652d9cb63b6SMatthew Barth { 653d9cb63b6SMatthew Barth timer.restartOnce(interval); 654d9cb63b6SMatthew Barth } 655d9cb63b6SMatthew Barth else 656d9cb63b6SMatthew Barth { 657d9cb63b6SMatthew Barth throw std::invalid_argument("Invalid Timer Type"); 658d9cb63b6SMatthew Barth } 659d9cb63b6SMatthew Barth _timers.emplace_back(std::move(dataPtr), std::move(timer)); 660d9cb63b6SMatthew Barth } 661d9cb63b6SMatthew Barth 6622f359f72SMatthew Barth void Manager::addGroups(const std::vector<Group>& groups) 663ade0c377SMatt Spinler { 6641a5c6236SMatthew Barth std::string lastServ; 6651a5c6236SMatthew Barth std::vector<std::string> objMgrPaths; 6662f359f72SMatthew Barth std::set<std::string> services; 6672f359f72SMatthew Barth for (const auto& group : groups) 6682f359f72SMatthew Barth { 66955627adfSMatthew Barth for (const auto& member : group.getMembers()) 670ade0c377SMatt Spinler { 671ade0c377SMatt Spinler try 672ade0c377SMatt Spinler { 6731a5c6236SMatthew Barth auto service = group.getService(); 67495d73490SMatthew Barth if (service.empty()) 67595d73490SMatthew Barth { 67695d73490SMatthew Barth service = getService(member, group.getInterface()); 67795d73490SMatthew Barth } 678ade0c377SMatt Spinler 6791a5c6236SMatthew Barth if (!service.empty()) 6801a5c6236SMatthew Barth { 6811a5c6236SMatthew Barth if (lastServ != service) 6821a5c6236SMatthew Barth { 6832f359f72SMatthew Barth objMgrPaths = getPaths( 6842f359f72SMatthew Barth service, "org.freedesktop.DBus.ObjectManager"); 6851a5c6236SMatthew Barth lastServ = service; 6861a5c6236SMatthew Barth } 68755627adfSMatthew Barth 6882f359f72SMatthew Barth // Look for the ObjectManager as an ancestor from the 6892f359f72SMatthew Barth // member. 6901a5c6236SMatthew Barth auto hasObjMgr = std::any_of( 6911a5c6236SMatthew Barth objMgrPaths.begin(), objMgrPaths.end(), 69255627adfSMatthew Barth [&member](const auto& path) { 69355627adfSMatthew Barth return member.find(path) != std::string::npos; 69455627adfSMatthew Barth }); 69555627adfSMatthew Barth 69655627adfSMatthew Barth if (!hasObjMgr) 69755627adfSMatthew Barth { 69855627adfSMatthew Barth // No object manager interface provided for group member 69955627adfSMatthew Barth // Attempt to retrieve group member property directly 700f16f063bSMatt Spinler try 701f16f063bSMatt Spinler { 7021a5c6236SMatthew Barth auto value = util::SDBusPlus::getPropertyVariant< 7031a5c6236SMatthew Barth PropertyVariantType>(_bus, service, member, 7041a5c6236SMatthew Barth group.getInterface(), 70555627adfSMatthew Barth group.getProperty()); 7061a5c6236SMatthew Barth setProperty(member, group.getInterface(), 7071a5c6236SMatthew Barth group.getProperty(), value); 708f16f063bSMatt Spinler } 709f16f063bSMatt Spinler catch (const std::exception& e) 710f16f063bSMatt Spinler {} 71155627adfSMatthew Barth continue; 712ade0c377SMatt Spinler } 71355627adfSMatthew Barth 7142f359f72SMatthew Barth if (services.find(service) == services.end()) 715ade0c377SMatt Spinler { 7162f359f72SMatthew Barth services.insert(service); 71755627adfSMatthew Barth for (const auto& objMgrPath : objMgrPaths) 718ade0c377SMatt Spinler { 71955627adfSMatthew Barth // Get all managed objects from the service 7201a5c6236SMatthew Barth auto objects = util::SDBusPlus::getManagedObjects< 7211a5c6236SMatthew Barth PropertyVariantType>(_bus, service, objMgrPath); 72255627adfSMatthew Barth 72355627adfSMatthew Barth // Insert objects into cache 72455627adfSMatthew Barth insertFilteredObjects(objects); 725ade0c377SMatt Spinler } 72655627adfSMatthew Barth } 72755627adfSMatthew Barth } 7281a5c6236SMatthew Barth } 72995d73490SMatthew Barth catch (const util::DBusError&) 73055627adfSMatthew Barth { 73195d73490SMatthew Barth // No service or property found for group member with the 73295d73490SMatthew Barth // group's configured interface 73355627adfSMatthew Barth continue; 734ade0c377SMatt Spinler } 735ade0c377SMatt Spinler } 736ade0c377SMatt Spinler } 7372f359f72SMatthew Barth } 738ade0c377SMatt Spinler 739d9cb63b6SMatthew Barth void Manager::timerExpired(TimerData& data) 740d9cb63b6SMatthew Barth { 741ade0c377SMatt Spinler if (std::get<bool>(data.second)) 742ade0c377SMatt Spinler { 7432f359f72SMatthew Barth addGroups(std::get<const std::vector<Group>&>(data.second)); 744ade0c377SMatt Spinler } 745ade0c377SMatt Spinler 746d9cb63b6SMatthew Barth auto& actions = 747d9cb63b6SMatthew Barth std::get<std::vector<std::unique_ptr<ActionBase>>&>(data.second); 748d9cb63b6SMatthew Barth // Perform the actions in the timer data 749d9cb63b6SMatthew Barth std::for_each(actions.begin(), actions.end(), 75000f6aa09SMatthew Barth [](auto& action) { action->run(); }); 751d9cb63b6SMatthew Barth 752d9cb63b6SMatthew Barth // Remove oneshot timers after they expired 753d9cb63b6SMatthew Barth if (data.first == TimerType::oneshot) 754d9cb63b6SMatthew Barth { 755d9cb63b6SMatthew Barth auto itTimer = std::find_if( 756d9cb63b6SMatthew Barth _timers.begin(), _timers.end(), [&data](const auto& timer) { 757d9cb63b6SMatthew Barth return (data.first == timer.first->first && 758d9cb63b6SMatthew Barth (std::get<std::string>(data.second) == 759d9cb63b6SMatthew Barth std::get<std::string>(timer.first->second))); 760d9cb63b6SMatthew Barth }); 761d9cb63b6SMatthew Barth if (itTimer != std::end(_timers)) 762d9cb63b6SMatthew Barth { 763d9cb63b6SMatthew Barth _timers.erase(itTimer); 764d9cb63b6SMatthew Barth } 765d9cb63b6SMatthew Barth } 766d9cb63b6SMatthew Barth } 767d9cb63b6SMatthew Barth 768cb356d48SPatrick Williams void Manager::handleSignal(sdbusplus::message_t& msg, 769c024d780SMatthew Barth const std::vector<SignalPkg>* pkgs) 770ebabc040SMatthew Barth { 771c024d780SMatthew Barth for (auto& pkg : *pkgs) 772ebabc040SMatthew Barth { 773ebabc040SMatthew Barth // Handle the signal callback and only run the actions if the handler 774ebabc040SMatthew Barth // updated the cache for the given SignalObject 775ebabc040SMatthew Barth if (std::get<SignalHandler>(pkg)(msg, std::get<SignalObject>(pkg), 776ebabc040SMatthew Barth *this)) 777ebabc040SMatthew Barth { 778ebabc040SMatthew Barth // Perform the actions in the handler package 779d0ba86a3SMatt Spinler auto& actions = std::get<TriggerActions>(pkg); 780c3a69087SMatthew Barth std::for_each(actions.begin(), actions.end(), [](auto& action) { 781c3a69087SMatthew Barth if (action.get()) 782c3a69087SMatthew Barth { 783c3a69087SMatthew Barth action.get()->run(); 784c3a69087SMatthew Barth } 785c3a69087SMatthew Barth }); 786ebabc040SMatthew Barth } 787c024d780SMatthew Barth // Only rewind message when not last package 788c024d780SMatthew Barth if (&pkg != &pkgs->back()) 789c024d780SMatthew Barth { 790c024d780SMatthew Barth sd_bus_message_rewind(msg.get(), true); 791c024d780SMatthew Barth } 792ebabc040SMatthew Barth } 793ebabc040SMatthew Barth } 794ebabc040SMatthew Barth 795acd737cdSMatthew Barth void Manager::setProfiles() 796acd737cdSMatthew Barth { 797acd737cdSMatthew Barth // Profiles JSON config file is optional 798808d7fe8SMike Capps auto confFile = 799808d7fe8SMike Capps fan::JsonConfig::getConfFile(confAppName, Profile::confFileName, true); 800e91ac864SMatthew Barth 801e91ac864SMatthew Barth _profiles.clear(); 802acd737cdSMatthew Barth if (!confFile.empty()) 803acd737cdSMatthew Barth { 804acd737cdSMatthew Barth for (const auto& entry : fan::JsonConfig::load(confFile)) 805acd737cdSMatthew Barth { 806acd737cdSMatthew Barth auto obj = std::make_unique<Profile>(entry); 807acd737cdSMatthew Barth _profiles.emplace( 808acd737cdSMatthew Barth std::make_pair(obj->getName(), obj->getProfiles()), 809acd737cdSMatthew Barth std::move(obj)); 810acd737cdSMatthew Barth } 811acd737cdSMatthew Barth } 812e91ac864SMatthew Barth 813acd737cdSMatthew Barth // Ensure all configurations use the same set of active profiles 814acd737cdSMatthew Barth // (In case a profile's active state changes during configuration) 815e91ac864SMatthew Barth _activeProfiles.clear(); 816acd737cdSMatthew Barth for (const auto& profile : _profiles) 817acd737cdSMatthew Barth { 818acd737cdSMatthew Barth if (profile.second->isActive()) 819acd737cdSMatthew Barth { 820acd737cdSMatthew Barth _activeProfiles.emplace_back(profile.first.first); 821acd737cdSMatthew Barth } 822acd737cdSMatthew Barth } 823acd737cdSMatthew Barth } 824acd737cdSMatthew Barth 825d0ba86a3SMatt Spinler void Manager::addParameterTrigger( 826d0ba86a3SMatt Spinler const std::string& name, std::vector<std::unique_ptr<ActionBase>>& actions) 827d0ba86a3SMatt Spinler { 828d0ba86a3SMatt Spinler auto it = _parameterTriggers.find(name); 829d0ba86a3SMatt Spinler if (it != _parameterTriggers.end()) 830d0ba86a3SMatt Spinler { 831d0ba86a3SMatt Spinler std::for_each(actions.begin(), actions.end(), 832d0ba86a3SMatt Spinler [&actList = it->second](auto& action) { 833d0ba86a3SMatt Spinler actList.emplace_back(std::ref(action)); 834d0ba86a3SMatt Spinler }); 835d0ba86a3SMatt Spinler } 836d0ba86a3SMatt Spinler else 837d0ba86a3SMatt Spinler { 838d0ba86a3SMatt Spinler TriggerActions triggerActions; 839d0ba86a3SMatt Spinler std::for_each(actions.begin(), actions.end(), 840d0ba86a3SMatt Spinler [&triggerActions](auto& action) { 841d0ba86a3SMatt Spinler triggerActions.emplace_back(std::ref(action)); 842d0ba86a3SMatt Spinler }); 843d0ba86a3SMatt Spinler _parameterTriggers[name] = std::move(triggerActions); 844d0ba86a3SMatt Spinler } 845d0ba86a3SMatt Spinler } 846d0ba86a3SMatt Spinler 847d0ba86a3SMatt Spinler void Manager::runParameterActions(const std::string& name) 848d0ba86a3SMatt Spinler { 849d0ba86a3SMatt Spinler auto it = _parameterTriggers.find(name); 850d0ba86a3SMatt Spinler if (it != _parameterTriggers.end()) 851d0ba86a3SMatt Spinler { 852d0ba86a3SMatt Spinler std::for_each(it->second.begin(), it->second.end(), 853d0ba86a3SMatt Spinler [](auto& action) { action.get()->run(); }); 854d0ba86a3SMatt Spinler } 855d0ba86a3SMatt Spinler } 856d0ba86a3SMatt Spinler 857a227a16dSMatthew Barth } // namespace phosphor::fan::control::json 858