blob: 11b781400d0b6c5dee532080db9bf43461130b1e [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) :
46 ConfigBase(jsonObj), _incDelay(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 Barth4f0d3b72020-08-27 14:32:15 -050075void Zone::setFullSpeed(const json& jsonObj)
76{
77 if (!jsonObj.contains("full_speed"))
78 {
79 log<level::ERR>("Missing required zone's full speed",
80 entry("JSON=%s", jsonObj.dump().c_str()));
81 throw std::runtime_error("Missing required zone's full speed");
82 }
83 _fullSpeed = jsonObj["full_speed"].get<uint64_t>();
84}
85
86void Zone::setDefaultFloor(const json& jsonObj)
87{
88 if (!jsonObj.contains("default_floor"))
89 {
90 log<level::ERR>("Missing required zone's default floor speed",
91 entry("JSON=%s", jsonObj.dump().c_str()));
92 throw std::runtime_error("Missing required zone's default floor speed");
93 }
94 _defaultFloor = jsonObj["default_floor"].get<uint64_t>();
95}
96
97void Zone::setDecInterval(const json& jsonObj)
98{
99 if (!jsonObj.contains("decrease_interval"))
100 {
101 log<level::ERR>("Missing required zone's decrease interval",
102 entry("JSON=%s", jsonObj.dump().c_str()));
103 throw std::runtime_error("Missing required zone's decrease interval");
104 }
105 _decInterval = jsonObj["decrease_interval"].get<uint64_t>();
106}
107
Matthew Barth651f03a2020-08-27 16:15:11 -0500108void Zone::setInterfaces(const json& jsonObj)
109{
110 for (const auto& interface : jsonObj["interfaces"])
111 {
112 if (!interface.contains("name") || !interface.contains("properties"))
113 {
114 log<level::ERR>("Missing required zone interface attributes",
115 entry("JSON=%s", interface.dump().c_str()));
116 throw std::runtime_error(
117 "Missing required zone interface attributes");
118 }
Matthew Barth216229c2020-09-24 13:47:33 -0500119 auto propFuncs =
120 _intfPropHandlers.find(interface["name"].get<std::string>());
121 if (propFuncs == _intfPropHandlers.end())
122 {
123 // Construct list of available configurable interfaces
124 auto intfs = std::accumulate(
125 std::next(_intfPropHandlers.begin()), _intfPropHandlers.end(),
126 _intfPropHandlers.begin()->first, [](auto list, auto intf) {
127 return std::move(list) + ", " + intf.first;
128 });
129 log<level::ERR>("Configured interface not available",
130 entry("JSON=%s", interface.dump().c_str()),
131 entry("AVAILABLE_INTFS=%s", intfs.c_str()));
132 throw std::runtime_error("Configured interface not available");
133 }
134
Matthew Barth651f03a2020-08-27 16:15:11 -0500135 for (const auto& property : interface["properties"])
136 {
137 if (!property.contains("name"))
138 {
139 log<level::ERR>(
140 "Missing required interface property attributes",
141 entry("JSON=%s", property.dump().c_str()));
142 throw std::runtime_error(
143 "Missing required interface property attributes");
144 }
145 // Attribute "persist" is optional, defaults to `false`
146 auto persist = false;
147 if (property.contains("persist"))
148 {
149 persist = property["persist"].get<bool>();
150 }
151 // Property name from JSON must exactly match supported
152 // index names to functions in property namespace
Matthew Barth216229c2020-09-24 13:47:33 -0500153 auto propFunc =
154 propFuncs->second.find(property["name"].get<std::string>());
155 if (propFunc == propFuncs->second.end())
Matthew Barth651f03a2020-08-27 16:15:11 -0500156 {
Matthew Barth216229c2020-09-24 13:47:33 -0500157 // Construct list of available configurable properties
Matthew Barth651f03a2020-08-27 16:15:11 -0500158 auto props = std::accumulate(
Matthew Barth216229c2020-09-24 13:47:33 -0500159 std::next(propFuncs->second.begin()),
160 propFuncs->second.end(), propFuncs->second.begin()->first,
161 [](auto list, auto prop) {
Matthew Barth651f03a2020-08-27 16:15:11 -0500162 return std::move(list) + ", " + prop.first;
163 });
Matthew Barth216229c2020-09-24 13:47:33 -0500164 log<level::ERR>("Configured property not available",
Matthew Barth651f03a2020-08-27 16:15:11 -0500165 entry("JSON=%s", property.dump().c_str()),
166 entry("AVAILABLE_PROPS=%s", props.c_str()));
167 throw std::runtime_error(
168 "Configured property function not available");
169 }
Matthew Barth216229c2020-09-24 13:47:33 -0500170 auto zHandler = propFunc->second(property, persist);
171 // Only add non-null zone handler functions
172 if (zHandler)
173 {
174 _zoneHandlers.emplace_back(zHandler);
175 }
Matthew Barth651f03a2020-08-27 16:15:11 -0500176 }
Matthew Barth651f03a2020-08-27 16:15:11 -0500177 }
178}
179
180/**
Matthew Barth216229c2020-09-24 13:47:33 -0500181 * Properties of interfaces supported by the zone configuration that return
182 * a ZoneHandler function that sets the zone's property value(s).
Matthew Barth651f03a2020-08-27 16:15:11 -0500183 */
184namespace zone::property
185{
Matthew Barth216229c2020-09-24 13:47:33 -0500186// Get a zone handler function for the configured values of the "Supported"
187// property
188ZoneHandler supported(const json& jsonObj, bool persist)
Matthew Barth651f03a2020-08-27 16:15:11 -0500189{
190 std::vector<std::string> values;
Matthew Barth216229c2020-09-24 13:47:33 -0500191 if (!jsonObj.contains("values"))
Matthew Barth651f03a2020-08-27 16:15:11 -0500192 {
Matthew Barth216229c2020-09-24 13:47:33 -0500193 log<level::ERR>(
194 "No 'values' found for \"Supported\" property, using an empty list",
195 entry("JSON=%s", jsonObj.dump().c_str()));
196 }
197 else
198 {
199 for (const auto& value : jsonObj["values"])
200 {
201 if (!value.contains("value"))
202 {
203 log<level::ERR>("No 'value' found for \"Supported\" property "
204 "entry, skipping",
205 entry("JSON=%s", value.dump().c_str()));
206 }
207 else
208 {
209 values.emplace_back(value["value"].get<std::string>());
210 }
211 }
Matthew Barth651f03a2020-08-27 16:15:11 -0500212 }
213
Matthew Barth216229c2020-09-24 13:47:33 -0500214 return make_zoneHandler(handler::setZoneProperty<std::vector<std::string>>(
215 Zone::thermModeIntf, Zone::supportedProp, &control::Zone::supported,
216 std::move(values), persist));
Matthew Barth651f03a2020-08-27 16:15:11 -0500217}
218
Matthew Barth216229c2020-09-24 13:47:33 -0500219// Get a zone handler function for a configured value of the "Current"
220// property
221ZoneHandler current(const json& jsonObj, bool persist)
Matthew Barth651f03a2020-08-27 16:15:11 -0500222{
Matthew Barth216229c2020-09-24 13:47:33 -0500223 // Use default value for "Current" property if no "value" entry given
224 if (!jsonObj.contains("value"))
225 {
226 log<level::ERR>("No 'value' found for \"Current\" property, "
227 "using default",
228 entry("JSON=%s", jsonObj.dump().c_str()));
229 return {};
230 }
231
232 return make_zoneHandler(handler::setZoneProperty<std::string>(
233 Zone::thermModeIntf, Zone::currentProp, &control::Zone::current,
234 jsonObj["value"].get<std::string>(), persist));
Matthew Barth651f03a2020-08-27 16:15:11 -0500235}
236} // namespace zone::property
237
Matthew Barth4f0d3b72020-08-27 14:32:15 -0500238} // namespace phosphor::fan::control::json