14f0d3b74SMatthew Barth /** 24f0d3b74SMatthew Barth * Copyright © 2020 IBM Corporation 34f0d3b74SMatthew Barth * 44f0d3b74SMatthew Barth * Licensed under the Apache License, Version 2.0 (the "License"); 54f0d3b74SMatthew Barth * you may not use this file except in compliance with the License. 64f0d3b74SMatthew Barth * You may obtain a copy of the License at 74f0d3b74SMatthew Barth * 84f0d3b74SMatthew Barth * http://www.apache.org/licenses/LICENSE-2.0 94f0d3b74SMatthew Barth * 104f0d3b74SMatthew Barth * Unless required by applicable law or agreed to in writing, software 114f0d3b74SMatthew Barth * distributed under the License is distributed on an "AS IS" BASIS, 124f0d3b74SMatthew Barth * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 134f0d3b74SMatthew Barth * See the License for the specific language governing permissions and 144f0d3b74SMatthew Barth * limitations under the License. 154f0d3b74SMatthew Barth */ 164f0d3b74SMatthew Barth #include "zone.hpp" 174f0d3b74SMatthew Barth 18*40554d8cSMatt Spinler #include "../utils/flight_recorder.hpp" 19bc89a8a0SMatthew Barth #include "dbus_zone.hpp" 20de90fb4dSMatthew Barth #include "fan.hpp" 219403a217SMatthew Barth #include "sdbusplus.hpp" 22216229c1SMatthew Barth 234f0d3b74SMatthew Barth #include <nlohmann/json.hpp> 244f0d3b74SMatthew Barth #include <phosphor-logging/log.hpp> 25603ef164SMatthew Barth #include <sdeventplus/event.hpp> 264f0d3b74SMatthew Barth 27a0dd1350SMatthew Barth #include <algorithm> 28007de099SMatthew Barth #include <chrono> 29651f03a4SMatthew Barth #include <iterator> 30651f03a4SMatthew Barth #include <map> 31bc89a8a0SMatthew Barth #include <memory> 32651f03a4SMatthew Barth #include <numeric> 33651f03a4SMatthew Barth #include <utility> 34216229c1SMatthew Barth #include <vector> 35651f03a4SMatthew Barth 364f0d3b74SMatthew Barth namespace phosphor::fan::control::json 374f0d3b74SMatthew Barth { 384f0d3b74SMatthew Barth 394f0d3b74SMatthew Barth using json = nlohmann::json; 404f0d3b74SMatthew Barth using namespace phosphor::logging; 414f0d3b74SMatthew Barth 42bc89a8a0SMatthew Barth const std::map< 43bc89a8a0SMatthew Barth std::string, 44bc89a8a0SMatthew Barth std::map<std::string, std::function<std::function<void(DBusZone&, Zone&)>( 45b584d818SMatthew Barth const json&, bool)>>> 46bc89a8a0SMatthew Barth Zone::_intfPropHandlers = { 47bc89a8a0SMatthew Barth {DBusZone::thermalModeIntf, 48bc89a8a0SMatthew Barth {{DBusZone::supportedProp, zone::property::supported}, 49bc89a8a0SMatthew Barth {DBusZone::currentProp, zone::property::current}}}}; 50651f03a4SMatthew Barth 519403a217SMatthew Barth Zone::Zone(const json& jsonObj, const sdeventplus::Event& event, Manager* mgr) : 52ab8e4b82SMatthew Barth ConfigBase(jsonObj), _dbusZone{}, _manager(mgr), _defaultFloor(0), 532504c77cSMatthew Barth _incDelay(0), _decInterval(0), _floor(0), _target(0), _incDelta(0), 542504c77cSMatthew Barth _decDelta(0), _requestTargetBase(0), _isActive(true), 55ab8e4b82SMatthew Barth _incTimer(event, std::bind(&Zone::incTimerExpired, this)), 56007de099SMatthew Barth _decTimer(event, std::bind(&Zone::decTimerExpired, this)) 574f0d3b74SMatthew Barth { 58e47c9588SMatthew Barth // Increase delay is optional, defaults to 0 594f0d3b74SMatthew Barth if (jsonObj.contains("increase_delay")) 604f0d3b74SMatthew Barth { 61007de099SMatthew Barth _incDelay = 62007de099SMatthew Barth std::chrono::seconds(jsonObj["increase_delay"].get<uint64_t>()); 634f0d3b74SMatthew Barth } 64ab8e4b82SMatthew Barth 65ab8e4b82SMatthew Barth // Poweron target is required 66ab8e4b82SMatthew Barth setPowerOnTarget(jsonObj); 67ab8e4b82SMatthew Barth 68ab8e4b82SMatthew Barth // Default ceiling is optional, defaults to poweron target 69ab8e4b82SMatthew Barth _defaultCeiling = _poweronTarget; 70ab8e4b82SMatthew Barth if (jsonObj.contains("default_ceiling")) 71ab8e4b82SMatthew Barth { 72ab8e4b82SMatthew Barth _defaultCeiling = jsonObj["default_ceiling"].get<uint64_t>(); 73ab8e4b82SMatthew Barth } 74ab8e4b82SMatthew Barth // Start with the current ceiling set as the default ceiling 75ab8e4b82SMatthew Barth _ceiling = _defaultCeiling; 76ab8e4b82SMatthew Barth 77ab8e4b82SMatthew Barth // Default floor is optional, defaults to 0 78ab8e4b82SMatthew Barth if (jsonObj.contains("default_floor")) 79ab8e4b82SMatthew Barth { 80ab8e4b82SMatthew Barth _defaultFloor = jsonObj["default_floor"].get<uint64_t>(); 81ab8e4b82SMatthew Barth // Start with the current floor set as the default 82ab8e4b82SMatthew Barth _floor = _defaultFloor; 83ab8e4b82SMatthew Barth } 84ab8e4b82SMatthew Barth 852504c77cSMatthew Barth // Decrease interval is optional, defaults to 0 862504c77cSMatthew Barth // A decrease interval of 0sec disables the decrease timer 872504c77cSMatthew Barth if (jsonObj.contains("decrease_interval")) 882504c77cSMatthew Barth { 892504c77cSMatthew Barth _decInterval = 902504c77cSMatthew Barth std::chrono::seconds(jsonObj["decrease_interval"].get<uint64_t>()); 912504c77cSMatthew Barth } 92ab8e4b82SMatthew Barth 93651f03a4SMatthew Barth // Setting properties on interfaces to be served are optional 94651f03a4SMatthew Barth if (jsonObj.contains("interfaces")) 95651f03a4SMatthew Barth { 96651f03a4SMatthew Barth setInterfaces(jsonObj); 97651f03a4SMatthew Barth } 9814303a45SMatthew Barth } 99007de099SMatthew Barth 10014303a45SMatthew Barth void Zone::enable() 10114303a45SMatthew Barth { 102bc89a8a0SMatthew Barth // Create thermal control dbus object 103bc89a8a0SMatthew Barth _dbusZone = std::make_unique<DBusZone>(*this); 104a4483746SMatthew Barth 105bc89a8a0SMatthew Barth // Init all configured dbus interfaces' property states 106bc89a8a0SMatthew Barth for (const auto& func : _propInitFunctions) 107bc89a8a0SMatthew Barth { 108bc89a8a0SMatthew Barth // Only call non-null init property functions 109bc89a8a0SMatthew Barth if (func) 110bc89a8a0SMatthew Barth { 111bc89a8a0SMatthew Barth func(*_dbusZone, *this); 112bc89a8a0SMatthew Barth } 113bc89a8a0SMatthew Barth } 114bc89a8a0SMatthew Barth 115bc89a8a0SMatthew Barth // TODO - Restore any persisted properties in init function 116bc89a8a0SMatthew Barth // Restore thermal control current mode state, if exists 117bc89a8a0SMatthew Barth _dbusZone->restoreCurrentMode(); 118bc89a8a0SMatthew Barth 119bc89a8a0SMatthew Barth // Emit object added for this zone's associated dbus object 120bc89a8a0SMatthew Barth _dbusZone->emit_object_added(); 121a4483746SMatthew Barth 1222504c77cSMatthew Barth // A decrease interval of 0sec disables the decrease timer 1232504c77cSMatthew Barth if (_decInterval != std::chrono::seconds::zero()) 1242504c77cSMatthew Barth { 125007de099SMatthew Barth // Start timer for fan target decreases 126007de099SMatthew Barth _decTimer.restart(_decInterval); 1274f0d3b74SMatthew Barth } 1282504c77cSMatthew Barth } 1294f0d3b74SMatthew Barth 130de90fb4dSMatthew Barth void Zone::addFan(std::unique_ptr<Fan> fan) 131de90fb4dSMatthew Barth { 132de90fb4dSMatthew Barth _fans.emplace_back(std::move(fan)); 133de90fb4dSMatthew Barth } 134de90fb4dSMatthew Barth 1358ba715e1SMatthew Barth void Zone::setTarget(uint64_t target) 1368ba715e1SMatthew Barth { 1375a2b5017SMatt Spinler if (_isActive) 1388ba715e1SMatthew Barth { 1398ba715e1SMatthew Barth _target = target; 1408ba715e1SMatthew Barth for (auto& fan : _fans) 1418ba715e1SMatthew Barth { 1428ba715e1SMatthew Barth fan->setTarget(_target); 1438ba715e1SMatthew Barth } 1448ba715e1SMatthew Barth } 1458ba715e1SMatthew Barth } 1468ba715e1SMatthew Barth 1475368011eSMatthew Barth void Zone::setTargetHold(const std::string& ident, uint64_t target, bool hold) 1485368011eSMatthew Barth { 1495368011eSMatthew Barth if (!hold) 1505368011eSMatthew Barth { 151*40554d8cSMatt Spinler _targetHolds.erase(ident); 1525368011eSMatthew Barth } 1535368011eSMatthew Barth else 1545368011eSMatthew Barth { 155*40554d8cSMatt Spinler _targetHolds[ident] = target; 1565368011eSMatthew Barth _isActive = false; 1575368011eSMatthew Barth } 1585368011eSMatthew Barth 159*40554d8cSMatt Spinler auto itHoldMax = std::max_element(_targetHolds.begin(), _targetHolds.end(), 1605368011eSMatthew Barth [](const auto& aHold, const auto& bHold) { 1615368011eSMatthew Barth return aHold.second < bHold.second; 1625368011eSMatthew Barth }); 163*40554d8cSMatt Spinler if (itHoldMax == _targetHolds.end()) 1645368011eSMatthew Barth { 1655368011eSMatthew Barth _isActive = true; 1665368011eSMatthew Barth } 1675368011eSMatthew Barth else 1685368011eSMatthew Barth { 1695368011eSMatthew Barth _target = itHoldMax->second; 1705368011eSMatthew Barth for (auto& fan : _fans) 1715368011eSMatthew Barth { 1725368011eSMatthew Barth fan->setTarget(_target); 1735368011eSMatthew Barth } 1745368011eSMatthew Barth } 1755368011eSMatthew Barth } 1765368011eSMatthew Barth 177*40554d8cSMatt Spinler void Zone::setFloorHold(const std::string& ident, uint64_t target, bool hold) 178*40554d8cSMatt Spinler { 179*40554d8cSMatt Spinler using namespace std::string_literals; 180*40554d8cSMatt Spinler 181*40554d8cSMatt Spinler if (!hold) 182*40554d8cSMatt Spinler { 183*40554d8cSMatt Spinler size_t removed = _floorHolds.erase(ident); 184*40554d8cSMatt Spinler if (removed) 185*40554d8cSMatt Spinler { 186*40554d8cSMatt Spinler FlightRecorder::instance().log( 187*40554d8cSMatt Spinler "zone-floor"s + getName(), 188*40554d8cSMatt Spinler fmt::format("{} is removing floor hold", ident)); 189*40554d8cSMatt Spinler } 190*40554d8cSMatt Spinler } 191*40554d8cSMatt Spinler else 192*40554d8cSMatt Spinler { 193*40554d8cSMatt Spinler if (!((_floorHolds.find(ident) != _floorHolds.end()) && 194*40554d8cSMatt Spinler (_floorHolds[ident] == target))) 195*40554d8cSMatt Spinler { 196*40554d8cSMatt Spinler FlightRecorder::instance().log( 197*40554d8cSMatt Spinler "zone-floor"s + getName(), 198*40554d8cSMatt Spinler fmt::format("{} is setting floor hold to {}", ident, target)); 199*40554d8cSMatt Spinler } 200*40554d8cSMatt Spinler _floorHolds[ident] = target; 201*40554d8cSMatt Spinler } 202*40554d8cSMatt Spinler 203*40554d8cSMatt Spinler if (!std::all_of(_floorChange.begin(), _floorChange.end(), 204*40554d8cSMatt Spinler [](const auto& entry) { return entry.second; })) 205*40554d8cSMatt Spinler { 206*40554d8cSMatt Spinler return; 207*40554d8cSMatt Spinler } 208*40554d8cSMatt Spinler 209*40554d8cSMatt Spinler auto itHoldMax = std::max_element(_floorHolds.begin(), _floorHolds.end(), 210*40554d8cSMatt Spinler [](const auto& aHold, const auto& bHold) { 211*40554d8cSMatt Spinler return aHold.second < bHold.second; 212*40554d8cSMatt Spinler }); 213*40554d8cSMatt Spinler if (itHoldMax == _floorHolds.end()) 214*40554d8cSMatt Spinler { 215*40554d8cSMatt Spinler if (_floor != _defaultFloor) 216*40554d8cSMatt Spinler { 217*40554d8cSMatt Spinler FlightRecorder::instance().log( 218*40554d8cSMatt Spinler "zone-floor"s + getName(), 219*40554d8cSMatt Spinler fmt::format("No set floor exists, using default floor", 220*40554d8cSMatt Spinler _defaultFloor)); 221*40554d8cSMatt Spinler } 222*40554d8cSMatt Spinler _floor = _defaultFloor; 223*40554d8cSMatt Spinler } 224*40554d8cSMatt Spinler else 225*40554d8cSMatt Spinler { 226*40554d8cSMatt Spinler if (_floor != itHoldMax->second) 227*40554d8cSMatt Spinler { 228*40554d8cSMatt Spinler FlightRecorder::instance().log( 229*40554d8cSMatt Spinler "zone-floor"s + getName(), 230*40554d8cSMatt Spinler fmt::format("Setting new floor to {}", itHoldMax->second)); 231*40554d8cSMatt Spinler } 232*40554d8cSMatt Spinler _floor = itHoldMax->second; 233*40554d8cSMatt Spinler } 234*40554d8cSMatt Spinler 235*40554d8cSMatt Spinler // Floor above target, update target to floor 236*40554d8cSMatt Spinler if (_target < _floor) 237*40554d8cSMatt Spinler { 238*40554d8cSMatt Spinler requestIncrease(_floor - _target); 239*40554d8cSMatt Spinler } 240*40554d8cSMatt Spinler } 241*40554d8cSMatt Spinler 24212cb125aSMatthew Barth void Zone::setFloor(uint64_t target) 24312cb125aSMatthew Barth { 24412cb125aSMatthew Barth // Check all entries are set to allow floor to be set 2458ba715e1SMatthew Barth auto pred = [](const auto& entry) { return entry.second; }; 24612cb125aSMatthew Barth if (std::all_of(_floorChange.begin(), _floorChange.end(), pred)) 24712cb125aSMatthew Barth { 24812cb125aSMatthew Barth _floor = target; 24912cb125aSMatthew Barth // Floor above target, update target to floor 25012cb125aSMatthew Barth if (_target < _floor) 25112cb125aSMatthew Barth { 25212cb125aSMatthew Barth requestIncrease(_floor - _target); 25312cb125aSMatthew Barth } 25412cb125aSMatthew Barth } 25512cb125aSMatthew Barth } 25612cb125aSMatthew Barth 25712cb125aSMatthew Barth void Zone::requestIncrease(uint64_t targetDelta) 25812cb125aSMatthew Barth { 2592b3253e3SMatthew Barth // Only increase when delta is higher than the current increase delta for 2602b3253e3SMatthew Barth // the zone and currently under ceiling 2612b3253e3SMatthew Barth if (targetDelta > _incDelta && _target < _ceiling) 2622b3253e3SMatthew Barth { 2632b3253e3SMatthew Barth auto requestTarget = getRequestTargetBase(); 2642b3253e3SMatthew Barth requestTarget = (targetDelta - _incDelta) + requestTarget; 2652b3253e3SMatthew Barth _incDelta = targetDelta; 2662b3253e3SMatthew Barth // Target can not go above a current ceiling 2672b3253e3SMatthew Barth if (requestTarget > _ceiling) 2682b3253e3SMatthew Barth { 2692b3253e3SMatthew Barth requestTarget = _ceiling; 2702b3253e3SMatthew Barth } 2718ba715e1SMatthew Barth setTarget(requestTarget); 272007de099SMatthew Barth // Restart timer countdown for fan target increase 273007de099SMatthew Barth _incTimer.restartOnce(_incDelay); 2742b3253e3SMatthew Barth } 27512cb125aSMatthew Barth } 27612cb125aSMatthew Barth 277007de099SMatthew Barth void Zone::incTimerExpired() 278007de099SMatthew Barth { 279007de099SMatthew Barth // Clear increase delta when timer expires allowing additional target 280007de099SMatthew Barth // increase requests or target decreases to occur 281007de099SMatthew Barth _incDelta = 0; 282007de099SMatthew Barth } 283007de099SMatthew Barth 28445c44ea0SMatthew Barth void Zone::requestDecrease(uint64_t targetDelta) 28545c44ea0SMatthew Barth { 28645c44ea0SMatthew Barth // Only decrease the lowest target delta requested 28745c44ea0SMatthew Barth if (_decDelta == 0 || targetDelta < _decDelta) 28845c44ea0SMatthew Barth { 28945c44ea0SMatthew Barth _decDelta = targetDelta; 29045c44ea0SMatthew Barth } 29145c44ea0SMatthew Barth } 29245c44ea0SMatthew Barth 293007de099SMatthew Barth void Zone::decTimerExpired() 294007de099SMatthew Barth { 295007de099SMatthew Barth // Check all entries are set to allow a decrease 296007de099SMatthew Barth auto pred = [](auto const& entry) { return entry.second; }; 297007de099SMatthew Barth auto decAllowed = std::all_of(_decAllowed.begin(), _decAllowed.end(), pred); 298007de099SMatthew Barth 299007de099SMatthew Barth // Only decrease targets when allowed, a requested decrease target delta 300007de099SMatthew Barth // exists, where no requested increases exist and the increase timer is not 301007de099SMatthew Barth // running (i.e. not in the middle of increasing) 302007de099SMatthew Barth if (decAllowed && _decDelta != 0 && _incDelta == 0 && 303007de099SMatthew Barth !_incTimer.isEnabled()) 304007de099SMatthew Barth { 305007de099SMatthew Barth auto requestTarget = getRequestTargetBase(); 306007de099SMatthew Barth // Request target should not start above ceiling 307007de099SMatthew Barth if (requestTarget > _ceiling) 308007de099SMatthew Barth { 309007de099SMatthew Barth requestTarget = _ceiling; 310007de099SMatthew Barth } 311007de099SMatthew Barth // Target can not go below the defined floor 312007de099SMatthew Barth if ((requestTarget < _decDelta) || (requestTarget - _decDelta < _floor)) 313007de099SMatthew Barth { 314007de099SMatthew Barth requestTarget = _floor; 315007de099SMatthew Barth } 316007de099SMatthew Barth else 317007de099SMatthew Barth { 318007de099SMatthew Barth requestTarget = requestTarget - _decDelta; 319007de099SMatthew Barth } 320007de099SMatthew Barth setTarget(requestTarget); 321007de099SMatthew Barth } 322007de099SMatthew Barth // Clear decrease delta when timer expires 323007de099SMatthew Barth _decDelta = 0; 324007de099SMatthew Barth // Decrease timer is restarted since its repeating 325007de099SMatthew Barth } 326007de099SMatthew Barth 327a0dd1350SMatthew Barth void Zone::setPersisted(const std::string& intf, const std::string& prop) 328a0dd1350SMatthew Barth { 329a0dd1350SMatthew Barth if (std::find_if(_propsPersisted[intf].begin(), _propsPersisted[intf].end(), 330bc89a8a0SMatthew Barth [&prop](const auto& p) { return prop == p; }) == 331a0dd1350SMatthew Barth _propsPersisted[intf].end()) 332a0dd1350SMatthew Barth { 333a0dd1350SMatthew Barth _propsPersisted[intf].emplace_back(prop); 334a0dd1350SMatthew Barth } 335a0dd1350SMatthew Barth } 336a0dd1350SMatthew Barth 337279183feSMatthew Barth bool Zone::isPersisted(const std::string& intf, const std::string& prop) const 338279183feSMatthew Barth { 339279183feSMatthew Barth auto it = _propsPersisted.find(intf); 340279183feSMatthew Barth if (it == _propsPersisted.end()) 341279183feSMatthew Barth { 342279183feSMatthew Barth return false; 343279183feSMatthew Barth } 344279183feSMatthew Barth 345279183feSMatthew Barth return std::any_of(it->second.begin(), it->second.end(), 346279183feSMatthew Barth [&prop](const auto& p) { return prop == p; }); 347279183feSMatthew Barth } 348279183feSMatthew Barth 349ab8e4b82SMatthew Barth void Zone::setPowerOnTarget(const json& jsonObj) 3504f0d3b74SMatthew Barth { 35112e888fbSMatthew Barth if (!jsonObj.contains("poweron_target")) 3524f0d3b74SMatthew Barth { 353ab8e4b82SMatthew Barth auto msg = "Missing required zone's poweron target"; 354ab8e4b82SMatthew Barth log<level::ERR>(msg, entry("JSON=%s", jsonObj.dump().c_str())); 355ab8e4b82SMatthew Barth throw std::runtime_error(msg); 3564f0d3b74SMatthew Barth } 357ab8e4b82SMatthew Barth _poweronTarget = jsonObj["poweron_target"].get<uint64_t>(); 3584f0d3b74SMatthew Barth } 3594f0d3b74SMatthew Barth 360651f03a4SMatthew Barth void Zone::setInterfaces(const json& jsonObj) 361651f03a4SMatthew Barth { 362651f03a4SMatthew Barth for (const auto& interface : jsonObj["interfaces"]) 363651f03a4SMatthew Barth { 364651f03a4SMatthew Barth if (!interface.contains("name") || !interface.contains("properties")) 365651f03a4SMatthew Barth { 366651f03a4SMatthew Barth log<level::ERR>("Missing required zone interface attributes", 367651f03a4SMatthew Barth entry("JSON=%s", interface.dump().c_str())); 368651f03a4SMatthew Barth throw std::runtime_error( 369651f03a4SMatthew Barth "Missing required zone interface attributes"); 370651f03a4SMatthew Barth } 371216229c1SMatthew Barth auto propFuncs = 372216229c1SMatthew Barth _intfPropHandlers.find(interface["name"].get<std::string>()); 373216229c1SMatthew Barth if (propFuncs == _intfPropHandlers.end()) 374216229c1SMatthew Barth { 375216229c1SMatthew Barth // Construct list of available configurable interfaces 376216229c1SMatthew Barth auto intfs = std::accumulate( 377216229c1SMatthew Barth std::next(_intfPropHandlers.begin()), _intfPropHandlers.end(), 378216229c1SMatthew Barth _intfPropHandlers.begin()->first, [](auto list, auto intf) { 379216229c1SMatthew Barth return std::move(list) + ", " + intf.first; 380216229c1SMatthew Barth }); 381216229c1SMatthew Barth log<level::ERR>("Configured interface not available", 382216229c1SMatthew Barth entry("JSON=%s", interface.dump().c_str()), 383216229c1SMatthew Barth entry("AVAILABLE_INTFS=%s", intfs.c_str())); 384216229c1SMatthew Barth throw std::runtime_error("Configured interface not available"); 385216229c1SMatthew Barth } 386216229c1SMatthew Barth 387651f03a4SMatthew Barth for (const auto& property : interface["properties"]) 388651f03a4SMatthew Barth { 389651f03a4SMatthew Barth if (!property.contains("name")) 390651f03a4SMatthew Barth { 391651f03a4SMatthew Barth log<level::ERR>( 392651f03a4SMatthew Barth "Missing required interface property attributes", 393651f03a4SMatthew Barth entry("JSON=%s", property.dump().c_str())); 394651f03a4SMatthew Barth throw std::runtime_error( 395651f03a4SMatthew Barth "Missing required interface property attributes"); 396651f03a4SMatthew Barth } 397651f03a4SMatthew Barth // Attribute "persist" is optional, defaults to `false` 398651f03a4SMatthew Barth auto persist = false; 399651f03a4SMatthew Barth if (property.contains("persist")) 400651f03a4SMatthew Barth { 401651f03a4SMatthew Barth persist = property["persist"].get<bool>(); 402651f03a4SMatthew Barth } 403651f03a4SMatthew Barth // Property name from JSON must exactly match supported 404651f03a4SMatthew Barth // index names to functions in property namespace 405216229c1SMatthew Barth auto propFunc = 406216229c1SMatthew Barth propFuncs->second.find(property["name"].get<std::string>()); 407216229c1SMatthew Barth if (propFunc == propFuncs->second.end()) 408651f03a4SMatthew Barth { 409216229c1SMatthew Barth // Construct list of available configurable properties 410651f03a4SMatthew Barth auto props = std::accumulate( 411216229c1SMatthew Barth std::next(propFuncs->second.begin()), 412216229c1SMatthew Barth propFuncs->second.end(), propFuncs->second.begin()->first, 413216229c1SMatthew Barth [](auto list, auto prop) { 414651f03a4SMatthew Barth return std::move(list) + ", " + prop.first; 415651f03a4SMatthew Barth }); 416216229c1SMatthew Barth log<level::ERR>("Configured property not available", 417651f03a4SMatthew Barth entry("JSON=%s", property.dump().c_str()), 418651f03a4SMatthew Barth entry("AVAILABLE_PROPS=%s", props.c_str())); 419651f03a4SMatthew Barth throw std::runtime_error( 420651f03a4SMatthew Barth "Configured property function not available"); 421651f03a4SMatthew Barth } 422651f03a4SMatthew Barth 423bc89a8a0SMatthew Barth _propInitFunctions.emplace_back( 424bc89a8a0SMatthew Barth propFunc->second(property, persist)); 425a4483746SMatthew Barth } 426a4483746SMatthew Barth } 427a4483746SMatthew Barth } 428a4483746SMatthew Barth 4299db6dd1dSMatt Spinler json Zone::dump() const 4309db6dd1dSMatt Spinler { 4319db6dd1dSMatt Spinler json output; 4329db6dd1dSMatt Spinler 4339db6dd1dSMatt Spinler output["active"] = _isActive; 4349db6dd1dSMatt Spinler output["floor"] = _floor; 4359db6dd1dSMatt Spinler output["target"] = _target; 4369db6dd1dSMatt Spinler output["increase_delta"] = _incDelta; 4379db6dd1dSMatt Spinler output["decrease_delta"] = _decDelta; 4389db6dd1dSMatt Spinler output["power_on_target"] = _poweronTarget; 4399db6dd1dSMatt Spinler output["default_ceiling"] = _defaultCeiling; 4409db6dd1dSMatt Spinler output["default_floor"] = _defaultFloor; 4419db6dd1dSMatt Spinler output["increase_delay"] = _incDelay.count(); 4429db6dd1dSMatt Spinler output["decrease_interval"] = _decInterval.count(); 4439db6dd1dSMatt Spinler output["requested_target_base"] = _requestTargetBase; 4449db6dd1dSMatt Spinler output["floor_change"] = _floorChange; 4459db6dd1dSMatt Spinler output["decrease_allowed"] = _decAllowed; 4469db6dd1dSMatt Spinler output["persisted_props"] = _propsPersisted; 447*40554d8cSMatt Spinler output["target_holds"] = _targetHolds; 448*40554d8cSMatt Spinler output["floor_holds"] = _floorHolds; 4499db6dd1dSMatt Spinler 4509db6dd1dSMatt Spinler return output; 4519db6dd1dSMatt Spinler } 4529db6dd1dSMatt Spinler 453651f03a4SMatthew Barth /** 454216229c1SMatthew Barth * Properties of interfaces supported by the zone configuration that return 455ab8e4b82SMatthew Barth * a handler function that sets the zone's property value(s) and persist 456ab8e4b82SMatthew Barth * state. 457651f03a4SMatthew Barth */ 458651f03a4SMatthew Barth namespace zone::property 459651f03a4SMatthew Barth { 460b584d818SMatthew Barth // Get a set property handler function for the configured values of the 461b584d818SMatthew Barth // "Supported" property 462bc89a8a0SMatthew Barth std::function<void(DBusZone&, Zone&)> supported(const json& jsonObj, 463bc89a8a0SMatthew Barth bool persist) 464651f03a4SMatthew Barth { 465651f03a4SMatthew Barth std::vector<std::string> values; 466216229c1SMatthew Barth if (!jsonObj.contains("values")) 467216229c1SMatthew Barth { 468ab8e4b82SMatthew Barth log<level::ERR>("No 'values' found for \"Supported\" property, " 469ab8e4b82SMatthew Barth "using an empty list", 470216229c1SMatthew Barth entry("JSON=%s", jsonObj.dump().c_str())); 471216229c1SMatthew Barth } 472216229c1SMatthew Barth else 473216229c1SMatthew Barth { 474651f03a4SMatthew Barth for (const auto& value : jsonObj["values"]) 475651f03a4SMatthew Barth { 476216229c1SMatthew Barth if (!value.contains("value")) 477216229c1SMatthew Barth { 478216229c1SMatthew Barth log<level::ERR>("No 'value' found for \"Supported\" property " 479216229c1SMatthew Barth "entry, skipping", 480216229c1SMatthew Barth entry("JSON=%s", value.dump().c_str())); 481216229c1SMatthew Barth } 482216229c1SMatthew Barth else 483216229c1SMatthew Barth { 484651f03a4SMatthew Barth values.emplace_back(value["value"].get<std::string>()); 485651f03a4SMatthew Barth } 486216229c1SMatthew Barth } 487651f03a4SMatthew Barth } 488651f03a4SMatthew Barth 489b584d818SMatthew Barth return Zone::setProperty<std::vector<std::string>>( 490bc89a8a0SMatthew Barth DBusZone::thermalModeIntf, DBusZone::supportedProp, 491bc89a8a0SMatthew Barth &DBusZone::supported, std::move(values), persist); 492216229c1SMatthew Barth } 493216229c1SMatthew Barth 494ab8e4b82SMatthew Barth // Get a set property handler function for a configured value of the 495ab8e4b82SMatthew Barth // "Current" property 496bc89a8a0SMatthew Barth std::function<void(DBusZone&, Zone&)> current(const json& jsonObj, bool persist) 497651f03a4SMatthew Barth { 498216229c1SMatthew Barth // Use default value for "Current" property if no "value" entry given 499216229c1SMatthew Barth if (!jsonObj.contains("value")) 500216229c1SMatthew Barth { 501b584d818SMatthew Barth log<level::INFO>("No 'value' found for \"Current\" property, " 502216229c1SMatthew Barth "using default", 503216229c1SMatthew Barth entry("JSON=%s", jsonObj.dump().c_str())); 504b584d818SMatthew Barth // Set persist state of property 505bc89a8a0SMatthew Barth return Zone::setPropertyPersist(DBusZone::thermalModeIntf, 506bc89a8a0SMatthew Barth DBusZone::currentProp, persist); 507216229c1SMatthew Barth } 508216229c1SMatthew Barth 509b584d818SMatthew Barth return Zone::setProperty<std::string>( 510bc89a8a0SMatthew Barth DBusZone::thermalModeIntf, DBusZone::currentProp, &DBusZone::current, 511b584d818SMatthew Barth jsonObj["value"].get<std::string>(), persist); 512651f03a4SMatthew Barth } 513b584d818SMatthew Barth 514651f03a4SMatthew Barth } // namespace zone::property 515651f03a4SMatthew Barth 5164f0d3b74SMatthew Barth } // namespace phosphor::fan::control::json 517