blob: 243fadeed0e09c13c9ca282ed238ca780c3eb76f [file] [log] [blame]
Matthew Barth4f0d3b72020-08-27 14:32:15 -05001/**
2 * Copyright © 2020 IBM Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16#include "zone.hpp"
17
Matthew Barth216229c2020-09-24 13:47:33 -050018#include "../zone.hpp"
Matthew Barthde90fb42021-03-04 16:34:28 -060019#include "fan.hpp"
Matthew Barth216229c2020-09-24 13:47:33 -050020#include "functor.hpp"
21#include "handlers.hpp"
22#include "types.hpp"
23
Matthew Barth4f0d3b72020-08-27 14:32:15 -050024#include <nlohmann/json.hpp>
25#include <phosphor-logging/log.hpp>
Matthew Barthacd737c2021-03-04 11:04:01 -060026#include <sdbusplus/bus.hpp>
Matthew Barth4f0d3b72020-08-27 14:32:15 -050027
Matthew Barth651f03a2020-08-27 16:15:11 -050028#include <iterator>
29#include <map>
30#include <numeric>
Matthew Barth651f03a2020-08-27 16:15:11 -050031#include <utility>
Matthew Barth216229c2020-09-24 13:47:33 -050032#include <vector>
Matthew Barth651f03a2020-08-27 16:15:11 -050033
Matthew Barth4f0d3b72020-08-27 14:32:15 -050034namespace phosphor::fan::control::json
35{
36
37using json = nlohmann::json;
38using namespace phosphor::logging;
39
Matthew Barth216229c2020-09-24 13:47:33 -050040const std::map<std::string, std::map<std::string, propHandler>>
41 Zone::_intfPropHandlers = {{thermModeIntf,
42 {{supportedProp, zone::property::supported},
43 {currentProp, zone::property::current}}}};
Matthew Barth651f03a2020-08-27 16:15:11 -050044
Matthew Barthacd737c2021-03-04 11:04:01 -060045Zone::Zone(sdbusplus::bus::bus& bus, const json& jsonObj) :
Matthew Barth12cb1252021-03-08 16:47:30 -060046 ConfigBase(jsonObj), _incDelay(0), _floor(0), _target(0)
Matthew Barth4f0d3b72020-08-27 14:32:15 -050047{
48 if (jsonObj.contains("profiles"))
49 {
50 for (const auto& profile : jsonObj["profiles"])
51 {
52 _profiles.emplace_back(profile.get<std::string>());
53 }
54 }
55 // Speed increase delay is optional, defaults to 0
56 if (jsonObj.contains("increase_delay"))
57 {
58 _incDelay = jsonObj["increase_delay"].get<uint64_t>();
59 }
60 setFullSpeed(jsonObj);
61 setDefaultFloor(jsonObj);
62 setDecInterval(jsonObj);
Matthew Barth651f03a2020-08-27 16:15:11 -050063 // Setting properties on interfaces to be served are optional
64 if (jsonObj.contains("interfaces"))
65 {
66 setInterfaces(jsonObj);
67 }
Matthew Barth4f0d3b72020-08-27 14:32:15 -050068}
69
Matthew Barthde90fb42021-03-04 16:34:28 -060070void Zone::addFan(std::unique_ptr<Fan> fan)
71{
72 _fans.emplace_back(std::move(fan));
73}
74
Matthew Barth12cb1252021-03-08 16:47:30 -060075void Zone::setFloor(uint64_t target)
76{
77 // Check all entries are set to allow floor to be set
78 auto pred = [](auto const& entry) { return entry.second; };
79 if (std::all_of(_floorChange.begin(), _floorChange.end(), pred))
80 {
81 _floor = target;
82 // Floor above target, update target to floor
83 if (_target < _floor)
84 {
85 requestIncrease(_floor - _target);
86 }
87 }
88}
89
90void Zone::requestIncrease(uint64_t targetDelta)
91{
92 // TODO Add from `requestSpeedIncrease` method in YAML zone object
93}
94
Matthew Barth4f0d3b72020-08-27 14:32:15 -050095void Zone::setFullSpeed(const json& jsonObj)
96{
97 if (!jsonObj.contains("full_speed"))
98 {
99 log<level::ERR>("Missing required zone's full speed",
100 entry("JSON=%s", jsonObj.dump().c_str()));
101 throw std::runtime_error("Missing required zone's full speed");
102 }
103 _fullSpeed = jsonObj["full_speed"].get<uint64_t>();
Matthew Barth12cb1252021-03-08 16:47:30 -0600104 // Start with the current target set as the default
105 _target = _fullSpeed;
Matthew Barth4f0d3b72020-08-27 14:32:15 -0500106}
107
108void Zone::setDefaultFloor(const json& jsonObj)
109{
110 if (!jsonObj.contains("default_floor"))
111 {
112 log<level::ERR>("Missing required zone's default floor speed",
113 entry("JSON=%s", jsonObj.dump().c_str()));
114 throw std::runtime_error("Missing required zone's default floor speed");
115 }
116 _defaultFloor = jsonObj["default_floor"].get<uint64_t>();
Matthew Barth12cb1252021-03-08 16:47:30 -0600117 // Start with the current floor set as the default
118 _floor = _defaultFloor;
Matthew Barth4f0d3b72020-08-27 14:32:15 -0500119}
120
121void Zone::setDecInterval(const json& jsonObj)
122{
123 if (!jsonObj.contains("decrease_interval"))
124 {
125 log<level::ERR>("Missing required zone's decrease interval",
126 entry("JSON=%s", jsonObj.dump().c_str()));
127 throw std::runtime_error("Missing required zone's decrease interval");
128 }
129 _decInterval = jsonObj["decrease_interval"].get<uint64_t>();
130}
131
Matthew Barth651f03a2020-08-27 16:15:11 -0500132void Zone::setInterfaces(const json& jsonObj)
133{
134 for (const auto& interface : jsonObj["interfaces"])
135 {
136 if (!interface.contains("name") || !interface.contains("properties"))
137 {
138 log<level::ERR>("Missing required zone interface attributes",
139 entry("JSON=%s", interface.dump().c_str()));
140 throw std::runtime_error(
141 "Missing required zone interface attributes");
142 }
Matthew Barth216229c2020-09-24 13:47:33 -0500143 auto propFuncs =
144 _intfPropHandlers.find(interface["name"].get<std::string>());
145 if (propFuncs == _intfPropHandlers.end())
146 {
147 // Construct list of available configurable interfaces
148 auto intfs = std::accumulate(
149 std::next(_intfPropHandlers.begin()), _intfPropHandlers.end(),
150 _intfPropHandlers.begin()->first, [](auto list, auto intf) {
151 return std::move(list) + ", " + intf.first;
152 });
153 log<level::ERR>("Configured interface not available",
154 entry("JSON=%s", interface.dump().c_str()),
155 entry("AVAILABLE_INTFS=%s", intfs.c_str()));
156 throw std::runtime_error("Configured interface not available");
157 }
158
Matthew Barth651f03a2020-08-27 16:15:11 -0500159 for (const auto& property : interface["properties"])
160 {
161 if (!property.contains("name"))
162 {
163 log<level::ERR>(
164 "Missing required interface property attributes",
165 entry("JSON=%s", property.dump().c_str()));
166 throw std::runtime_error(
167 "Missing required interface property attributes");
168 }
169 // Attribute "persist" is optional, defaults to `false`
170 auto persist = false;
171 if (property.contains("persist"))
172 {
173 persist = property["persist"].get<bool>();
174 }
175 // Property name from JSON must exactly match supported
176 // index names to functions in property namespace
Matthew Barth216229c2020-09-24 13:47:33 -0500177 auto propFunc =
178 propFuncs->second.find(property["name"].get<std::string>());
179 if (propFunc == propFuncs->second.end())
Matthew Barth651f03a2020-08-27 16:15:11 -0500180 {
Matthew Barth216229c2020-09-24 13:47:33 -0500181 // Construct list of available configurable properties
Matthew Barth651f03a2020-08-27 16:15:11 -0500182 auto props = std::accumulate(
Matthew Barth216229c2020-09-24 13:47:33 -0500183 std::next(propFuncs->second.begin()),
184 propFuncs->second.end(), propFuncs->second.begin()->first,
185 [](auto list, auto prop) {
Matthew Barth651f03a2020-08-27 16:15:11 -0500186 return std::move(list) + ", " + prop.first;
187 });
Matthew Barth216229c2020-09-24 13:47:33 -0500188 log<level::ERR>("Configured property not available",
Matthew Barth651f03a2020-08-27 16:15:11 -0500189 entry("JSON=%s", property.dump().c_str()),
190 entry("AVAILABLE_PROPS=%s", props.c_str()));
191 throw std::runtime_error(
192 "Configured property function not available");
193 }
Matthew Barth216229c2020-09-24 13:47:33 -0500194 auto zHandler = propFunc->second(property, persist);
195 // Only add non-null zone handler functions
196 if (zHandler)
197 {
198 _zoneHandlers.emplace_back(zHandler);
199 }
Matthew Barth651f03a2020-08-27 16:15:11 -0500200 }
Matthew Barth651f03a2020-08-27 16:15:11 -0500201 }
202}
203
204/**
Matthew Barth216229c2020-09-24 13:47:33 -0500205 * Properties of interfaces supported by the zone configuration that return
206 * a ZoneHandler function that sets the zone's property value(s).
Matthew Barth651f03a2020-08-27 16:15:11 -0500207 */
208namespace zone::property
209{
Matthew Barth216229c2020-09-24 13:47:33 -0500210// Get a zone handler function for the configured values of the "Supported"
211// property
212ZoneHandler supported(const json& jsonObj, bool persist)
Matthew Barth651f03a2020-08-27 16:15:11 -0500213{
214 std::vector<std::string> values;
Matthew Barth216229c2020-09-24 13:47:33 -0500215 if (!jsonObj.contains("values"))
Matthew Barth651f03a2020-08-27 16:15:11 -0500216 {
Matthew Barth216229c2020-09-24 13:47:33 -0500217 log<level::ERR>(
218 "No 'values' found for \"Supported\" property, using an empty list",
219 entry("JSON=%s", jsonObj.dump().c_str()));
220 }
221 else
222 {
223 for (const auto& value : jsonObj["values"])
224 {
225 if (!value.contains("value"))
226 {
227 log<level::ERR>("No 'value' found for \"Supported\" property "
228 "entry, skipping",
229 entry("JSON=%s", value.dump().c_str()));
230 }
231 else
232 {
233 values.emplace_back(value["value"].get<std::string>());
234 }
235 }
Matthew Barth651f03a2020-08-27 16:15:11 -0500236 }
237
Matthew Barth216229c2020-09-24 13:47:33 -0500238 return make_zoneHandler(handler::setZoneProperty<std::vector<std::string>>(
239 Zone::thermModeIntf, Zone::supportedProp, &control::Zone::supported,
240 std::move(values), persist));
Matthew Barth651f03a2020-08-27 16:15:11 -0500241}
242
Matthew Barth216229c2020-09-24 13:47:33 -0500243// Get a zone handler function for a configured value of the "Current"
244// property
245ZoneHandler current(const json& jsonObj, bool persist)
Matthew Barth651f03a2020-08-27 16:15:11 -0500246{
Matthew Barth216229c2020-09-24 13:47:33 -0500247 // Use default value for "Current" property if no "value" entry given
248 if (!jsonObj.contains("value"))
249 {
250 log<level::ERR>("No 'value' found for \"Current\" property, "
251 "using default",
252 entry("JSON=%s", jsonObj.dump().c_str()));
253 return {};
254 }
255
256 return make_zoneHandler(handler::setZoneProperty<std::string>(
257 Zone::thermModeIntf, Zone::currentProp, &control::Zone::current,
258 jsonObj["value"].get<std::string>(), persist));
Matthew Barth651f03a2020-08-27 16:15:11 -0500259}
260} // namespace zone::property
261
Matthew Barth4f0d3b72020-08-27 14:32:15 -0500262} // namespace phosphor::fan::control::json