blob: 84f9c824c0195d6ba94b8f1b9951524f07ccfa78 [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
18#include <nlohmann/json.hpp>
19#include <phosphor-logging/log.hpp>
20#include <sdbusplus/bus.hpp>
21
Matthew Barth651f03a2020-08-27 16:15:11 -050022#include <any>
23#include <iterator>
24#include <map>
25#include <numeric>
26#include <tuple>
27#include <utility>
28
Matthew Barth4f0d3b72020-08-27 14:32:15 -050029namespace phosphor::fan::control::json
30{
31
32using json = nlohmann::json;
33using namespace phosphor::logging;
34
Matthew Barth651f03a2020-08-27 16:15:11 -050035const std::map<std::string, propertyHandler> Zone::_props = {
36 {"Supported", zone::property::supported},
37 {"Current", zone::property::current}};
38
Matthew Barth4f0d3b72020-08-27 14:32:15 -050039Zone::Zone(sdbusplus::bus::bus& bus, const json& jsonObj) :
40 ConfigBase(jsonObj), _incDelay(0)
41{
42 if (jsonObj.contains("profiles"))
43 {
44 for (const auto& profile : jsonObj["profiles"])
45 {
46 _profiles.emplace_back(profile.get<std::string>());
47 }
48 }
49 // Speed increase delay is optional, defaults to 0
50 if (jsonObj.contains("increase_delay"))
51 {
52 _incDelay = jsonObj["increase_delay"].get<uint64_t>();
53 }
54 setFullSpeed(jsonObj);
55 setDefaultFloor(jsonObj);
56 setDecInterval(jsonObj);
Matthew Barth651f03a2020-08-27 16:15:11 -050057 // Setting properties on interfaces to be served are optional
58 if (jsonObj.contains("interfaces"))
59 {
60 setInterfaces(jsonObj);
61 }
Matthew Barth4f0d3b72020-08-27 14:32:15 -050062}
63
64void Zone::setFullSpeed(const json& jsonObj)
65{
66 if (!jsonObj.contains("full_speed"))
67 {
68 log<level::ERR>("Missing required zone's full speed",
69 entry("JSON=%s", jsonObj.dump().c_str()));
70 throw std::runtime_error("Missing required zone's full speed");
71 }
72 _fullSpeed = jsonObj["full_speed"].get<uint64_t>();
73}
74
75void Zone::setDefaultFloor(const json& jsonObj)
76{
77 if (!jsonObj.contains("default_floor"))
78 {
79 log<level::ERR>("Missing required zone's default floor speed",
80 entry("JSON=%s", jsonObj.dump().c_str()));
81 throw std::runtime_error("Missing required zone's default floor speed");
82 }
83 _defaultFloor = jsonObj["default_floor"].get<uint64_t>();
84}
85
86void Zone::setDecInterval(const json& jsonObj)
87{
88 if (!jsonObj.contains("decrease_interval"))
89 {
90 log<level::ERR>("Missing required zone's decrease interval",
91 entry("JSON=%s", jsonObj.dump().c_str()));
92 throw std::runtime_error("Missing required zone's decrease interval");
93 }
94 _decInterval = jsonObj["decrease_interval"].get<uint64_t>();
95}
96
Matthew Barth651f03a2020-08-27 16:15:11 -050097void Zone::setInterfaces(const json& jsonObj)
98{
99 for (const auto& interface : jsonObj["interfaces"])
100 {
101 if (!interface.contains("name") || !interface.contains("properties"))
102 {
103 log<level::ERR>("Missing required zone interface attributes",
104 entry("JSON=%s", interface.dump().c_str()));
105 throw std::runtime_error(
106 "Missing required zone interface attributes");
107 }
108 std::map<std::string, std::tuple<std::any, bool>> props;
109 for (const auto& property : interface["properties"])
110 {
111 if (!property.contains("name"))
112 {
113 log<level::ERR>(
114 "Missing required interface property attributes",
115 entry("JSON=%s", property.dump().c_str()));
116 throw std::runtime_error(
117 "Missing required interface property attributes");
118 }
119 // Attribute "persist" is optional, defaults to `false`
120 auto persist = false;
121 if (property.contains("persist"))
122 {
123 persist = property["persist"].get<bool>();
124 }
125 // Property name from JSON must exactly match supported
126 // index names to functions in property namespace
127 auto prop = property["name"].get<std::string>();
128 auto propFunc = _props.find(prop);
129 if (propFunc != _props.end())
130 {
131 auto value = propFunc->second(property);
132 props.emplace(prop, std::make_tuple(value, persist));
133 }
134 else
135 {
136 // Construct list of available properties
137 auto props = std::accumulate(
138 std::next(_props.begin()), _props.end(),
139 _props.begin()->first, [](auto list, auto prop) {
140 return std::move(list) + ", " + prop.first;
141 });
142 log<level::ERR>("Configured property function not available",
143 entry("JSON=%s", property.dump().c_str()),
144 entry("AVAILABLE_PROPS=%s", props.c_str()));
145 throw std::runtime_error(
146 "Configured property function not available");
147 }
148 }
149 _interfaces.emplace(interface["name"].get<std::string>(), props);
150 }
151}
152
153/**
154 * Properties of interfaces supported by the zone configuration
155 */
156namespace zone::property
157{
158// Get an any object for the configured value of the "Supported" property
159std::any supported(const json& jsonObj)
160{
161 std::vector<std::string> values;
162 for (const auto& value : jsonObj["values"])
163 {
164 values.emplace_back(value["value"].get<std::string>());
165 }
166
167 return std::make_any<std::vector<std::string>>(values);
168}
169
170// Get an any object for the configured value of the "Current" property
171std::any current(const json& jsonObj)
172{
173 auto value = jsonObj["value"].get<std::string>();
174 return std::make_any<std::string>(value);
175}
176} // namespace zone::property
177
Matthew Barth4f0d3b72020-08-27 14:32:15 -0500178} // namespace phosphor::fan::control::json