blob: cdf758e9c32bcb60eb588ec97f0a5da307953c0a [file] [log] [blame]
Shawn McCarney0e8c68a2020-03-27 01:44:48 -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
17#include "config_file_parser.hpp"
18
19#include "config_file_parser_error.hpp"
Bob Kingf617f892020-03-30 19:03:35 +080020#include "i2c_interface.hpp"
Shawn McCarney0e8c68a2020-03-27 01:44:48 -050021#include "pmbus_utils.hpp"
22
23#include <exception>
24#include <fstream>
25#include <optional>
26#include <utility>
27
28using json = nlohmann::json;
29
30namespace phosphor::power::regulators::config_file_parser
31{
32
33std::tuple<std::vector<std::unique_ptr<Rule>>,
34 std::vector<std::unique_ptr<Chassis>>>
35 parse(const std::filesystem::path& pathName)
36{
37 try
38 {
39 // Use standard JSON parser to create tree of JSON elements
40 std::ifstream file{pathName};
41 json rootElement = json::parse(file);
42
43 // Parse tree of JSON elements and return corresponding C++ objects
44 return internal::parseRoot(rootElement);
45 }
46 catch (const std::exception& e)
47 {
48 throw ConfigFileParserError{pathName, e.what()};
49 }
50}
51
52namespace internal
53{
54
55std::unique_ptr<Action> parseAction(const json& element)
56{
57 verifyIsObject(element);
58 unsigned int propertyCount{0};
59
60 // Optional comments property; value not stored
61 if (element.contains("comments"))
62 {
63 ++propertyCount;
64 }
65
66 // Required action type property; there must be exactly one specified
67 std::unique_ptr<Action> action{};
68 if (element.contains("and"))
69 {
70 // TODO: Not implemented yet
71 // action = parseAnd(element["and"]);
72 // ++propertyCount;
73 }
74 else if (element.contains("compare_presence"))
75 {
76 // TODO: Not implemented yet
77 // action = parseComparePresence(element["compare_presence"]);
78 // ++propertyCount;
79 }
80 else if (element.contains("compare_vpd"))
81 {
82 // TODO: Not implemented yet
83 // action = parseCompareVPD(element["compare_vpd"]);
84 // ++propertyCount;
85 }
86 else if (element.contains("i2c_compare_bit"))
87 {
88 // TODO: Not implemented yet
89 // action = parseI2CCompareBit(element["i2c_compare_bit"]);
90 // ++propertyCount;
91 }
92 else if (element.contains("i2c_compare_byte"))
93 {
94 // TODO: Not implemented yet
95 // action = parseI2CCompareByte(element["i2c_compare_byte"]);
96 // ++propertyCount;
97 }
98 else if (element.contains("i2c_compare_bytes"))
99 {
100 // TODO: Not implemented yet
101 // action = parseI2CCompareBytes(element["i2c_compare_bytes"]);
102 // ++propertyCount;
103 }
104 else if (element.contains("i2c_write_bit"))
105 {
Bob Kingf617f892020-03-30 19:03:35 +0800106 action = parseI2CWriteBit(element["i2c_write_bit"]);
107 ++propertyCount;
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500108 }
109 else if (element.contains("i2c_write_byte"))
110 {
111 // TODO: Not implemented yet
112 // action = parseI2CWriteByte(element["i2c_write_byte"]);
113 // ++propertyCount;
114 }
115 else if (element.contains("i2c_write_bytes"))
116 {
117 // TODO: Not implemented yet
118 // action = parseI2CWriteBytes(element["i2c_write_bytes"]);
119 // ++propertyCount;
120 }
121 else if (element.contains("if"))
122 {
123 // TODO: Not implemented yet
124 // action = parseIf(element["if"]);
125 // ++propertyCount;
126 }
127 else if (element.contains("not"))
128 {
129 // TODO: Not implemented yet
130 // action = parseNot(element["not"]);
131 // ++propertyCount;
132 }
133 else if (element.contains("or"))
134 {
135 // TODO: Not implemented yet
136 // action = parseOr(element["or"]);
137 // ++propertyCount;
138 }
139 else if (element.contains("pmbus_read_sensor"))
140 {
141 // TODO: Not implemented yet
142 // action = parsePMBusReadSensor(element["pmbus_read_sensor"]);
143 // ++propertyCount;
144 }
145 else if (element.contains("pmbus_write_vout_command"))
146 {
147 action =
148 parsePMBusWriteVoutCommand(element["pmbus_write_vout_command"]);
149 ++propertyCount;
150 }
151 else if (element.contains("run_rule"))
152 {
153 // TODO: Not implemented yet
154 // action = parseRunRule(element["run_rule"]);
155 // ++propertyCount;
156 }
157 else if (element.contains("set_device"))
158 {
159 // TODO: Not implemented yet
160 // action = parseSetDevice(element["set_device"]);
161 // ++propertyCount;
162 }
163 else
164 {
165 throw std::invalid_argument{"Required action type property missing"};
166 }
167
168 // Verify no invalid properties exist
169 verifyPropertyCount(element, propertyCount);
170
171 return action;
172}
173
174std::vector<std::unique_ptr<Action>> parseActionArray(const json& element)
175{
176 verifyIsArray(element);
177 std::vector<std::unique_ptr<Action>> actions;
178 for (auto& actionElement : element)
179 {
180 actions.emplace_back(parseAction(actionElement));
181 }
182 return actions;
183}
184
185std::vector<std::unique_ptr<Chassis>> parseChassisArray(const json& element)
186{
187 verifyIsArray(element);
188 std::vector<std::unique_ptr<Chassis>> chassis;
189 // TODO: Not implemented yet
190 // for (auto& chassisElement : element)
191 // {
192 // chassis.emplace_back(parseChassis(chassisElement));
193 // }
194 return chassis;
195}
196
Bob Kingf617f892020-03-30 19:03:35 +0800197std::unique_ptr<I2CWriteBitAction> parseI2CWriteBit(const json& element)
198{
199 verifyIsObject(element);
200 unsigned int propertyCount{0};
201
202 // Required register property
203 const json& regElement = getRequiredProperty(element, "register");
204 uint8_t reg = parseStringToUint8(regElement);
205 ++propertyCount;
206
207 // Required position property
208 const json& positionElement = getRequiredProperty(element, "position");
209 uint8_t position = parseBitPosition(positionElement);
210 ++propertyCount;
211
212 // Required value property
213 const json& valueElement = getRequiredProperty(element, "value");
214 uint8_t value = parseBitValue(valueElement);
215 ++propertyCount;
216
217 // Verify no invalid properties exist
218 verifyPropertyCount(element, propertyCount);
219
220 return std::make_unique<I2CWriteBitAction>(reg, position, value);
221}
222
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500223std::unique_ptr<PMBusWriteVoutCommandAction>
224 parsePMBusWriteVoutCommand(const json& element)
225{
226 verifyIsObject(element);
227 unsigned int propertyCount{0};
228
229 // Optional volts property
230 std::optional<double> volts{};
231 auto voltsIt = element.find("volts");
232 if (voltsIt != element.end())
233 {
234 volts = parseDouble(*voltsIt);
235 ++propertyCount;
236 }
237
238 // Required format property
239 const json& formatElement = getRequiredProperty(element, "format");
240 std::string formatString = parseString(formatElement);
241 if (formatString != "linear")
242 {
243 throw std::invalid_argument{"Invalid format value: " + formatString};
244 }
245 pmbus_utils::VoutDataFormat format = pmbus_utils::VoutDataFormat::linear;
246 ++propertyCount;
247
248 // Optional exponent property
249 std::optional<int8_t> exponent{};
250 auto exponentIt = element.find("exponent");
251 if (exponentIt != element.end())
252 {
253 exponent = parseInt8(*exponentIt);
254 ++propertyCount;
255 }
256
257 // Optional is_verified property
258 bool isVerified = false;
259 auto isVerifiedIt = element.find("is_verified");
260 if (isVerifiedIt != element.end())
261 {
262 isVerified = parseBoolean(*isVerifiedIt);
263 ++propertyCount;
264 }
265
266 // Verify no invalid properties exist
267 verifyPropertyCount(element, propertyCount);
268
269 return std::make_unique<PMBusWriteVoutCommandAction>(volts, format,
270 exponent, isVerified);
271}
272
273std::tuple<std::vector<std::unique_ptr<Rule>>,
274 std::vector<std::unique_ptr<Chassis>>>
275 parseRoot(const json& element)
276{
277 verifyIsObject(element);
278 unsigned int propertyCount{0};
279
280 // Optional comments property; value not stored
281 if (element.contains("comments"))
282 {
283 ++propertyCount;
284 }
285
286 // Optional rules property
287 std::vector<std::unique_ptr<Rule>> rules{};
288 auto rulesIt = element.find("rules");
289 if (rulesIt != element.end())
290 {
291 rules = parseRuleArray(*rulesIt);
292 ++propertyCount;
293 }
294
295 // Required chassis property
296 const json& chassisElement = getRequiredProperty(element, "chassis");
297 std::vector<std::unique_ptr<Chassis>> chassis =
298 parseChassisArray(chassisElement);
299 ++propertyCount;
300
301 // Verify no invalid properties exist
302 verifyPropertyCount(element, propertyCount);
303
304 return std::make_tuple(std::move(rules), std::move(chassis));
305}
306
307std::unique_ptr<Rule> parseRule(const json& element)
308{
309 verifyIsObject(element);
310 unsigned int propertyCount{0};
311
312 // Optional comments property; value not stored
313 if (element.contains("comments"))
314 {
315 ++propertyCount;
316 }
317
318 // Required id property
319 const json& idElement = getRequiredProperty(element, "id");
320 std::string id = parseString(idElement);
321 ++propertyCount;
322
323 // Required actions property
324 const json& actionsElement = getRequiredProperty(element, "actions");
325 std::vector<std::unique_ptr<Action>> actions =
326 parseActionArray(actionsElement);
327 ++propertyCount;
328
329 // Verify no invalid properties exist
330 verifyPropertyCount(element, propertyCount);
331
332 return std::make_unique<Rule>(id, std::move(actions));
333}
334
335std::vector<std::unique_ptr<Rule>> parseRuleArray(const json& element)
336{
337 verifyIsArray(element);
338 std::vector<std::unique_ptr<Rule>> rules;
339 for (auto& ruleElement : element)
340 {
341 rules.emplace_back(parseRule(ruleElement));
342 }
343 return rules;
344}
345
346} // namespace internal
347
348} // namespace phosphor::power::regulators::config_file_parser