blob: dd0dbfbc4e330a07d4d9b507b5268724e173c06d [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>
Matthew Barth4f0d3b72020-08-27 14:32:15 -050025
Matthew Barth651f03a2020-08-27 16:15:11 -050026#include <iterator>
27#include <map>
28#include <numeric>
Matthew Barth651f03a2020-08-27 16:15:11 -050029#include <utility>
Matthew Barth216229c2020-09-24 13:47:33 -050030#include <vector>
Matthew Barth651f03a2020-08-27 16:15:11 -050031
Matthew Barth4f0d3b72020-08-27 14:32:15 -050032namespace phosphor::fan::control::json
33{
34
35using json = nlohmann::json;
36using namespace phosphor::logging;
37
Matthew Barth216229c2020-09-24 13:47:33 -050038const std::map<std::string, std::map<std::string, propHandler>>
39 Zone::_intfPropHandlers = {{thermModeIntf,
40 {{supportedProp, zone::property::supported},
41 {currentProp, zone::property::current}}}};
Matthew Barth651f03a2020-08-27 16:15:11 -050042
Matthew Barth391ade02021-01-15 14:33:21 -060043Zone::Zone(const json& jsonObj) : ConfigBase(jsonObj), _incDelay(0)
Matthew Barth4f0d3b72020-08-27 14:32:15 -050044{
45 if (jsonObj.contains("profiles"))
46 {
47 for (const auto& profile : jsonObj["profiles"])
48 {
49 _profiles.emplace_back(profile.get<std::string>());
50 }
51 }
52 // Speed increase delay is optional, defaults to 0
53 if (jsonObj.contains("increase_delay"))
54 {
55 _incDelay = jsonObj["increase_delay"].get<uint64_t>();
56 }
57 setFullSpeed(jsonObj);
58 setDefaultFloor(jsonObj);
59 setDecInterval(jsonObj);
Matthew Barth651f03a2020-08-27 16:15:11 -050060 // Setting properties on interfaces to be served are optional
61 if (jsonObj.contains("interfaces"))
62 {
63 setInterfaces(jsonObj);
64 }
Matthew Barth4f0d3b72020-08-27 14:32:15 -050065}
66
67void Zone::setFullSpeed(const json& jsonObj)
68{
69 if (!jsonObj.contains("full_speed"))
70 {
71 log<level::ERR>("Missing required zone's full speed",
72 entry("JSON=%s", jsonObj.dump().c_str()));
73 throw std::runtime_error("Missing required zone's full speed");
74 }
75 _fullSpeed = jsonObj["full_speed"].get<uint64_t>();
76}
77
78void Zone::setDefaultFloor(const json& jsonObj)
79{
80 if (!jsonObj.contains("default_floor"))
81 {
82 log<level::ERR>("Missing required zone's default floor speed",
83 entry("JSON=%s", jsonObj.dump().c_str()));
84 throw std::runtime_error("Missing required zone's default floor speed");
85 }
86 _defaultFloor = jsonObj["default_floor"].get<uint64_t>();
87}
88
89void Zone::setDecInterval(const json& jsonObj)
90{
91 if (!jsonObj.contains("decrease_interval"))
92 {
93 log<level::ERR>("Missing required zone's decrease interval",
94 entry("JSON=%s", jsonObj.dump().c_str()));
95 throw std::runtime_error("Missing required zone's decrease interval");
96 }
97 _decInterval = jsonObj["decrease_interval"].get<uint64_t>();
98}
99
Matthew Barth651f03a2020-08-27 16:15:11 -0500100void Zone::setInterfaces(const json& jsonObj)
101{
102 for (const auto& interface : jsonObj["interfaces"])
103 {
104 if (!interface.contains("name") || !interface.contains("properties"))
105 {
106 log<level::ERR>("Missing required zone interface attributes",
107 entry("JSON=%s", interface.dump().c_str()));
108 throw std::runtime_error(
109 "Missing required zone interface attributes");
110 }
Matthew Barth216229c2020-09-24 13:47:33 -0500111 auto propFuncs =
112 _intfPropHandlers.find(interface["name"].get<std::string>());
113 if (propFuncs == _intfPropHandlers.end())
114 {
115 // Construct list of available configurable interfaces
116 auto intfs = std::accumulate(
117 std::next(_intfPropHandlers.begin()), _intfPropHandlers.end(),
118 _intfPropHandlers.begin()->first, [](auto list, auto intf) {
119 return std::move(list) + ", " + intf.first;
120 });
121 log<level::ERR>("Configured interface not available",
122 entry("JSON=%s", interface.dump().c_str()),
123 entry("AVAILABLE_INTFS=%s", intfs.c_str()));
124 throw std::runtime_error("Configured interface not available");
125 }
126
Matthew Barth651f03a2020-08-27 16:15:11 -0500127 for (const auto& property : interface["properties"])
128 {
129 if (!property.contains("name"))
130 {
131 log<level::ERR>(
132 "Missing required interface property attributes",
133 entry("JSON=%s", property.dump().c_str()));
134 throw std::runtime_error(
135 "Missing required interface property attributes");
136 }
137 // Attribute "persist" is optional, defaults to `false`
138 auto persist = false;
139 if (property.contains("persist"))
140 {
141 persist = property["persist"].get<bool>();
142 }
143 // Property name from JSON must exactly match supported
144 // index names to functions in property namespace
Matthew Barth216229c2020-09-24 13:47:33 -0500145 auto propFunc =
146 propFuncs->second.find(property["name"].get<std::string>());
147 if (propFunc == propFuncs->second.end())
Matthew Barth651f03a2020-08-27 16:15:11 -0500148 {
Matthew Barth216229c2020-09-24 13:47:33 -0500149 // Construct list of available configurable properties
Matthew Barth651f03a2020-08-27 16:15:11 -0500150 auto props = std::accumulate(
Matthew Barth216229c2020-09-24 13:47:33 -0500151 std::next(propFuncs->second.begin()),
152 propFuncs->second.end(), propFuncs->second.begin()->first,
153 [](auto list, auto prop) {
Matthew Barth651f03a2020-08-27 16:15:11 -0500154 return std::move(list) + ", " + prop.first;
155 });
Matthew Barth216229c2020-09-24 13:47:33 -0500156 log<level::ERR>("Configured property not available",
Matthew Barth651f03a2020-08-27 16:15:11 -0500157 entry("JSON=%s", property.dump().c_str()),
158 entry("AVAILABLE_PROPS=%s", props.c_str()));
159 throw std::runtime_error(
160 "Configured property function not available");
161 }
Matthew Barth216229c2020-09-24 13:47:33 -0500162 auto zHandler = propFunc->second(property, persist);
163 // Only add non-null zone handler functions
164 if (zHandler)
165 {
166 _zoneHandlers.emplace_back(zHandler);
167 }
Matthew Barth651f03a2020-08-27 16:15:11 -0500168 }
Matthew Barth651f03a2020-08-27 16:15:11 -0500169 }
170}
171
172/**
Matthew Barth216229c2020-09-24 13:47:33 -0500173 * Properties of interfaces supported by the zone configuration that return
174 * a ZoneHandler function that sets the zone's property value(s).
Matthew Barth651f03a2020-08-27 16:15:11 -0500175 */
176namespace zone::property
177{
Matthew Barth216229c2020-09-24 13:47:33 -0500178// Get a zone handler function for the configured values of the "Supported"
179// property
180ZoneHandler supported(const json& jsonObj, bool persist)
Matthew Barth651f03a2020-08-27 16:15:11 -0500181{
182 std::vector<std::string> values;
Matthew Barth216229c2020-09-24 13:47:33 -0500183 if (!jsonObj.contains("values"))
Matthew Barth651f03a2020-08-27 16:15:11 -0500184 {
Matthew Barth216229c2020-09-24 13:47:33 -0500185 log<level::ERR>(
186 "No 'values' found for \"Supported\" property, using an empty list",
187 entry("JSON=%s", jsonObj.dump().c_str()));
188 }
189 else
190 {
191 for (const auto& value : jsonObj["values"])
192 {
193 if (!value.contains("value"))
194 {
195 log<level::ERR>("No 'value' found for \"Supported\" property "
196 "entry, skipping",
197 entry("JSON=%s", value.dump().c_str()));
198 }
199 else
200 {
201 values.emplace_back(value["value"].get<std::string>());
202 }
203 }
Matthew Barth651f03a2020-08-27 16:15:11 -0500204 }
205
Matthew Barth216229c2020-09-24 13:47:33 -0500206 return make_zoneHandler(handler::setZoneProperty<std::vector<std::string>>(
207 Zone::thermModeIntf, Zone::supportedProp, &control::Zone::supported,
208 std::move(values), persist));
Matthew Barth651f03a2020-08-27 16:15:11 -0500209}
210
Matthew Barth216229c2020-09-24 13:47:33 -0500211// Get a zone handler function for a configured value of the "Current"
212// property
213ZoneHandler current(const json& jsonObj, bool persist)
Matthew Barth651f03a2020-08-27 16:15:11 -0500214{
Matthew Barth216229c2020-09-24 13:47:33 -0500215 // Use default value for "Current" property if no "value" entry given
216 if (!jsonObj.contains("value"))
217 {
218 log<level::ERR>("No 'value' found for \"Current\" property, "
219 "using default",
220 entry("JSON=%s", jsonObj.dump().c_str()));
221 return {};
222 }
223
224 return make_zoneHandler(handler::setZoneProperty<std::string>(
225 Zone::thermModeIntf, Zone::currentProp, &control::Zone::current,
226 jsonObj["value"].get<std::string>(), persist));
Matthew Barth651f03a2020-08-27 16:15:11 -0500227}
228} // namespace zone::property
229
Matthew Barth4f0d3b72020-08-27 14:32:15 -0500230} // namespace phosphor::fan::control::json