blob: 33ab048a9e392e10a9d27f1ac80a15fe98162f3c [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"
19#include "functor.hpp"
20#include "handlers.hpp"
21#include "types.hpp"
22
Matthew Barth4f0d3b72020-08-27 14:32:15 -050023#include <nlohmann/json.hpp>
24#include <phosphor-logging/log.hpp>
25#include <sdbusplus/bus.hpp>
26
Matthew Barth651f03a2020-08-27 16:15:11 -050027#include <iterator>
28#include <map>
29#include <numeric>
Matthew Barth651f03a2020-08-27 16:15:11 -050030#include <utility>
Matthew Barth216229c2020-09-24 13:47:33 -050031#include <vector>
Matthew Barth651f03a2020-08-27 16:15:11 -050032
Matthew Barth4f0d3b72020-08-27 14:32:15 -050033namespace phosphor::fan::control::json
34{
35
36using json = nlohmann::json;
37using namespace phosphor::logging;
38
Matthew Barth216229c2020-09-24 13:47:33 -050039const std::map<std::string, std::map<std::string, propHandler>>
40 Zone::_intfPropHandlers = {{thermModeIntf,
41 {{supportedProp, zone::property::supported},
42 {currentProp, zone::property::current}}}};
Matthew Barth651f03a2020-08-27 16:15:11 -050043
Matthew Barth4f0d3b72020-08-27 14:32:15 -050044Zone::Zone(sdbusplus::bus::bus& bus, const json& jsonObj) :
45 ConfigBase(jsonObj), _incDelay(0)
46{
47 if (jsonObj.contains("profiles"))
48 {
49 for (const auto& profile : jsonObj["profiles"])
50 {
51 _profiles.emplace_back(profile.get<std::string>());
52 }
53 }
54 // Speed increase delay is optional, defaults to 0
55 if (jsonObj.contains("increase_delay"))
56 {
57 _incDelay = jsonObj["increase_delay"].get<uint64_t>();
58 }
59 setFullSpeed(jsonObj);
60 setDefaultFloor(jsonObj);
61 setDecInterval(jsonObj);
Matthew Barth651f03a2020-08-27 16:15:11 -050062 // Setting properties on interfaces to be served are optional
63 if (jsonObj.contains("interfaces"))
64 {
65 setInterfaces(jsonObj);
66 }
Matthew Barth4f0d3b72020-08-27 14:32:15 -050067}
68
69void Zone::setFullSpeed(const json& jsonObj)
70{
71 if (!jsonObj.contains("full_speed"))
72 {
73 log<level::ERR>("Missing required zone's full speed",
74 entry("JSON=%s", jsonObj.dump().c_str()));
75 throw std::runtime_error("Missing required zone's full speed");
76 }
77 _fullSpeed = jsonObj["full_speed"].get<uint64_t>();
78}
79
80void Zone::setDefaultFloor(const json& jsonObj)
81{
82 if (!jsonObj.contains("default_floor"))
83 {
84 log<level::ERR>("Missing required zone's default floor speed",
85 entry("JSON=%s", jsonObj.dump().c_str()));
86 throw std::runtime_error("Missing required zone's default floor speed");
87 }
88 _defaultFloor = jsonObj["default_floor"].get<uint64_t>();
89}
90
91void Zone::setDecInterval(const json& jsonObj)
92{
93 if (!jsonObj.contains("decrease_interval"))
94 {
95 log<level::ERR>("Missing required zone's decrease interval",
96 entry("JSON=%s", jsonObj.dump().c_str()));
97 throw std::runtime_error("Missing required zone's decrease interval");
98 }
99 _decInterval = jsonObj["decrease_interval"].get<uint64_t>();
100}
101
Matthew Barth651f03a2020-08-27 16:15:11 -0500102void Zone::setInterfaces(const json& jsonObj)
103{
104 for (const auto& interface : jsonObj["interfaces"])
105 {
106 if (!interface.contains("name") || !interface.contains("properties"))
107 {
108 log<level::ERR>("Missing required zone interface attributes",
109 entry("JSON=%s", interface.dump().c_str()));
110 throw std::runtime_error(
111 "Missing required zone interface attributes");
112 }
Matthew Barth216229c2020-09-24 13:47:33 -0500113 auto propFuncs =
114 _intfPropHandlers.find(interface["name"].get<std::string>());
115 if (propFuncs == _intfPropHandlers.end())
116 {
117 // Construct list of available configurable interfaces
118 auto intfs = std::accumulate(
119 std::next(_intfPropHandlers.begin()), _intfPropHandlers.end(),
120 _intfPropHandlers.begin()->first, [](auto list, auto intf) {
121 return std::move(list) + ", " + intf.first;
122 });
123 log<level::ERR>("Configured interface not available",
124 entry("JSON=%s", interface.dump().c_str()),
125 entry("AVAILABLE_INTFS=%s", intfs.c_str()));
126 throw std::runtime_error("Configured interface not available");
127 }
128
Matthew Barth651f03a2020-08-27 16:15:11 -0500129 for (const auto& property : interface["properties"])
130 {
131 if (!property.contains("name"))
132 {
133 log<level::ERR>(
134 "Missing required interface property attributes",
135 entry("JSON=%s", property.dump().c_str()));
136 throw std::runtime_error(
137 "Missing required interface property attributes");
138 }
139 // Attribute "persist" is optional, defaults to `false`
140 auto persist = false;
141 if (property.contains("persist"))
142 {
143 persist = property["persist"].get<bool>();
144 }
145 // Property name from JSON must exactly match supported
146 // index names to functions in property namespace
Matthew Barth216229c2020-09-24 13:47:33 -0500147 auto propFunc =
148 propFuncs->second.find(property["name"].get<std::string>());
149 if (propFunc == propFuncs->second.end())
Matthew Barth651f03a2020-08-27 16:15:11 -0500150 {
Matthew Barth216229c2020-09-24 13:47:33 -0500151 // Construct list of available configurable properties
Matthew Barth651f03a2020-08-27 16:15:11 -0500152 auto props = std::accumulate(
Matthew Barth216229c2020-09-24 13:47:33 -0500153 std::next(propFuncs->second.begin()),
154 propFuncs->second.end(), propFuncs->second.begin()->first,
155 [](auto list, auto prop) {
Matthew Barth651f03a2020-08-27 16:15:11 -0500156 return std::move(list) + ", " + prop.first;
157 });
Matthew Barth216229c2020-09-24 13:47:33 -0500158 log<level::ERR>("Configured property not available",
Matthew Barth651f03a2020-08-27 16:15:11 -0500159 entry("JSON=%s", property.dump().c_str()),
160 entry("AVAILABLE_PROPS=%s", props.c_str()));
161 throw std::runtime_error(
162 "Configured property function not available");
163 }
Matthew Barth216229c2020-09-24 13:47:33 -0500164 auto zHandler = propFunc->second(property, persist);
165 // Only add non-null zone handler functions
166 if (zHandler)
167 {
168 _zoneHandlers.emplace_back(zHandler);
169 }
Matthew Barth651f03a2020-08-27 16:15:11 -0500170 }
Matthew Barth651f03a2020-08-27 16:15:11 -0500171 }
172}
173
174/**
Matthew Barth216229c2020-09-24 13:47:33 -0500175 * Properties of interfaces supported by the zone configuration that return
176 * a ZoneHandler function that sets the zone's property value(s).
Matthew Barth651f03a2020-08-27 16:15:11 -0500177 */
178namespace zone::property
179{
Matthew Barth216229c2020-09-24 13:47:33 -0500180// Get a zone handler function for the configured values of the "Supported"
181// property
182ZoneHandler supported(const json& jsonObj, bool persist)
Matthew Barth651f03a2020-08-27 16:15:11 -0500183{
184 std::vector<std::string> values;
Matthew Barth216229c2020-09-24 13:47:33 -0500185 if (!jsonObj.contains("values"))
Matthew Barth651f03a2020-08-27 16:15:11 -0500186 {
Matthew Barth216229c2020-09-24 13:47:33 -0500187 log<level::ERR>(
188 "No 'values' found for \"Supported\" property, using an empty list",
189 entry("JSON=%s", jsonObj.dump().c_str()));
190 }
191 else
192 {
193 for (const auto& value : jsonObj["values"])
194 {
195 if (!value.contains("value"))
196 {
197 log<level::ERR>("No 'value' found for \"Supported\" property "
198 "entry, skipping",
199 entry("JSON=%s", value.dump().c_str()));
200 }
201 else
202 {
203 values.emplace_back(value["value"].get<std::string>());
204 }
205 }
Matthew Barth651f03a2020-08-27 16:15:11 -0500206 }
207
Matthew Barth216229c2020-09-24 13:47:33 -0500208 return make_zoneHandler(handler::setZoneProperty<std::vector<std::string>>(
209 Zone::thermModeIntf, Zone::supportedProp, &control::Zone::supported,
210 std::move(values), persist));
Matthew Barth651f03a2020-08-27 16:15:11 -0500211}
212
Matthew Barth216229c2020-09-24 13:47:33 -0500213// Get a zone handler function for a configured value of the "Current"
214// property
215ZoneHandler current(const json& jsonObj, bool persist)
Matthew Barth651f03a2020-08-27 16:15:11 -0500216{
Matthew Barth216229c2020-09-24 13:47:33 -0500217 // Use default value for "Current" property if no "value" entry given
218 if (!jsonObj.contains("value"))
219 {
220 log<level::ERR>("No 'value' found for \"Current\" property, "
221 "using default",
222 entry("JSON=%s", jsonObj.dump().c_str()));
223 return {};
224 }
225
226 return make_zoneHandler(handler::setZoneProperty<std::string>(
227 Zone::thermModeIntf, Zone::currentProp, &control::Zone::current,
228 jsonObj["value"].get<std::string>(), persist));
Matthew Barth651f03a2020-08-27 16:15:11 -0500229}
230} // namespace zone::property
231
Matthew Barth4f0d3b72020-08-27 14:32:15 -0500232} // namespace phosphor::fan::control::json