blob: 3959978e3893c7e3b1b532811cb55a8977965b80 [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 {
Bob King87ff9d72020-03-31 14:02:55 +0800111 action = parseI2CWriteByte(element["i2c_write_byte"]);
112 ++propertyCount;
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500113 }
114 else if (element.contains("i2c_write_bytes"))
115 {
Bob Kingbafcb862020-03-31 16:39:00 +0800116 action = parseI2CWriteBytes(element["i2c_write_bytes"]);
117 ++propertyCount;
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500118 }
119 else if (element.contains("if"))
120 {
121 // TODO: Not implemented yet
122 // action = parseIf(element["if"]);
123 // ++propertyCount;
124 }
125 else if (element.contains("not"))
126 {
127 // TODO: Not implemented yet
128 // action = parseNot(element["not"]);
129 // ++propertyCount;
130 }
131 else if (element.contains("or"))
132 {
133 // TODO: Not implemented yet
134 // action = parseOr(element["or"]);
135 // ++propertyCount;
136 }
137 else if (element.contains("pmbus_read_sensor"))
138 {
139 // TODO: Not implemented yet
140 // action = parsePMBusReadSensor(element["pmbus_read_sensor"]);
141 // ++propertyCount;
142 }
143 else if (element.contains("pmbus_write_vout_command"))
144 {
145 action =
146 parsePMBusWriteVoutCommand(element["pmbus_write_vout_command"]);
147 ++propertyCount;
148 }
149 else if (element.contains("run_rule"))
150 {
151 // TODO: Not implemented yet
152 // action = parseRunRule(element["run_rule"]);
153 // ++propertyCount;
154 }
155 else if (element.contains("set_device"))
156 {
157 // TODO: Not implemented yet
158 // action = parseSetDevice(element["set_device"]);
159 // ++propertyCount;
160 }
161 else
162 {
163 throw std::invalid_argument{"Required action type property missing"};
164 }
165
166 // Verify no invalid properties exist
167 verifyPropertyCount(element, propertyCount);
168
169 return action;
170}
171
172std::vector<std::unique_ptr<Action>> parseActionArray(const json& element)
173{
174 verifyIsArray(element);
175 std::vector<std::unique_ptr<Action>> actions;
176 for (auto& actionElement : element)
177 {
178 actions.emplace_back(parseAction(actionElement));
179 }
180 return actions;
181}
182
183std::vector<std::unique_ptr<Chassis>> parseChassisArray(const json& element)
184{
185 verifyIsArray(element);
186 std::vector<std::unique_ptr<Chassis>> chassis;
187 // TODO: Not implemented yet
188 // for (auto& chassisElement : element)
189 // {
190 // chassis.emplace_back(parseChassis(chassisElement));
191 // }
192 return chassis;
193}
194
Bob Kingbafcb862020-03-31 16:39:00 +0800195std::vector<uint8_t> parseHexByteArray(const json& element)
196{
197 verifyIsArray(element);
198 std::vector<uint8_t> values;
199 for (auto& valueElement : element)
200 {
201 values.emplace_back(parseHexByte(valueElement));
202 }
203 return values;
204}
205
Bob Kingf617f892020-03-30 19:03:35 +0800206std::unique_ptr<I2CWriteBitAction> parseI2CWriteBit(const json& element)
207{
208 verifyIsObject(element);
209 unsigned int propertyCount{0};
210
211 // Required register property
212 const json& regElement = getRequiredProperty(element, "register");
Bob Kingbafcb862020-03-31 16:39:00 +0800213 uint8_t reg = parseHexByte(regElement);
Bob Kingf617f892020-03-30 19:03:35 +0800214 ++propertyCount;
215
216 // Required position property
217 const json& positionElement = getRequiredProperty(element, "position");
218 uint8_t position = parseBitPosition(positionElement);
219 ++propertyCount;
220
221 // Required value property
222 const json& valueElement = getRequiredProperty(element, "value");
223 uint8_t value = parseBitValue(valueElement);
224 ++propertyCount;
225
226 // Verify no invalid properties exist
227 verifyPropertyCount(element, propertyCount);
228
229 return std::make_unique<I2CWriteBitAction>(reg, position, value);
230}
231
Bob King87ff9d72020-03-31 14:02:55 +0800232std::unique_ptr<I2CWriteByteAction> parseI2CWriteByte(const json& element)
233{
234 verifyIsObject(element);
235 unsigned int propertyCount{0};
236
237 // Required register property
238 const json& regElement = getRequiredProperty(element, "register");
Bob Kingbafcb862020-03-31 16:39:00 +0800239 uint8_t reg = parseHexByte(regElement);
Bob King87ff9d72020-03-31 14:02:55 +0800240 ++propertyCount;
241
242 // Required value property
243 const json& valueElement = getRequiredProperty(element, "value");
Bob Kingbafcb862020-03-31 16:39:00 +0800244 uint8_t value = parseHexByte(valueElement);
Bob King87ff9d72020-03-31 14:02:55 +0800245 ++propertyCount;
246
247 // Optional mask property
248 uint8_t mask = 0xff;
249 auto maskIt = element.find("mask");
250 if (maskIt != element.end())
251 {
Bob Kingbafcb862020-03-31 16:39:00 +0800252 mask = parseHexByte(*maskIt);
Bob King87ff9d72020-03-31 14:02:55 +0800253 ++propertyCount;
254 }
255
256 // Verify no invalid properties exist
257 verifyPropertyCount(element, propertyCount);
258
259 return std::make_unique<I2CWriteByteAction>(reg, value, mask);
260}
261
Bob Kingbafcb862020-03-31 16:39:00 +0800262std::unique_ptr<I2CWriteBytesAction> parseI2CWriteBytes(const json& element)
263{
264 verifyIsObject(element);
265 unsigned int propertyCount{0};
266
267 // Required register property
268 const json& regElement = getRequiredProperty(element, "register");
269 uint8_t reg = parseHexByte(regElement);
270 ++propertyCount;
271
272 // Required values property
273 const json& valueElement = getRequiredProperty(element, "values");
274 std::vector<uint8_t> values = parseHexByteArray(valueElement);
275 ++propertyCount;
276
277 // Optional masks property
278 std::vector<uint8_t> masks{};
279 auto masksIt = element.find("masks");
280 if (masksIt != element.end())
281 {
282 masks = parseHexByteArray(*masksIt);
283 ++propertyCount;
284 }
285
286 // Verify masks array (if specified) was same size as values array
287 if ((!masks.empty()) && (masks.size() != values.size()))
288 {
289 throw std::invalid_argument{"Invalid number of elements in masks"};
290 }
291
292 // Verify no invalid properties exist
293 verifyPropertyCount(element, propertyCount);
294
295 if (masks.empty())
296 {
297 return std::make_unique<I2CWriteBytesAction>(reg, values);
298 }
299 return std::make_unique<I2CWriteBytesAction>(reg, values, masks);
300}
301
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500302std::unique_ptr<PMBusWriteVoutCommandAction>
303 parsePMBusWriteVoutCommand(const json& element)
304{
305 verifyIsObject(element);
306 unsigned int propertyCount{0};
307
308 // Optional volts property
309 std::optional<double> volts{};
310 auto voltsIt = element.find("volts");
311 if (voltsIt != element.end())
312 {
313 volts = parseDouble(*voltsIt);
314 ++propertyCount;
315 }
316
317 // Required format property
318 const json& formatElement = getRequiredProperty(element, "format");
319 std::string formatString = parseString(formatElement);
320 if (formatString != "linear")
321 {
322 throw std::invalid_argument{"Invalid format value: " + formatString};
323 }
324 pmbus_utils::VoutDataFormat format = pmbus_utils::VoutDataFormat::linear;
325 ++propertyCount;
326
327 // Optional exponent property
328 std::optional<int8_t> exponent{};
329 auto exponentIt = element.find("exponent");
330 if (exponentIt != element.end())
331 {
332 exponent = parseInt8(*exponentIt);
333 ++propertyCount;
334 }
335
336 // Optional is_verified property
337 bool isVerified = false;
338 auto isVerifiedIt = element.find("is_verified");
339 if (isVerifiedIt != element.end())
340 {
341 isVerified = parseBoolean(*isVerifiedIt);
342 ++propertyCount;
343 }
344
345 // Verify no invalid properties exist
346 verifyPropertyCount(element, propertyCount);
347
348 return std::make_unique<PMBusWriteVoutCommandAction>(volts, format,
349 exponent, isVerified);
350}
351
352std::tuple<std::vector<std::unique_ptr<Rule>>,
353 std::vector<std::unique_ptr<Chassis>>>
354 parseRoot(const json& element)
355{
356 verifyIsObject(element);
357 unsigned int propertyCount{0};
358
359 // Optional comments property; value not stored
360 if (element.contains("comments"))
361 {
362 ++propertyCount;
363 }
364
365 // Optional rules property
366 std::vector<std::unique_ptr<Rule>> rules{};
367 auto rulesIt = element.find("rules");
368 if (rulesIt != element.end())
369 {
370 rules = parseRuleArray(*rulesIt);
371 ++propertyCount;
372 }
373
374 // Required chassis property
375 const json& chassisElement = getRequiredProperty(element, "chassis");
376 std::vector<std::unique_ptr<Chassis>> chassis =
377 parseChassisArray(chassisElement);
378 ++propertyCount;
379
380 // Verify no invalid properties exist
381 verifyPropertyCount(element, propertyCount);
382
383 return std::make_tuple(std::move(rules), std::move(chassis));
384}
385
386std::unique_ptr<Rule> parseRule(const json& element)
387{
388 verifyIsObject(element);
389 unsigned int propertyCount{0};
390
391 // Optional comments property; value not stored
392 if (element.contains("comments"))
393 {
394 ++propertyCount;
395 }
396
397 // Required id property
398 const json& idElement = getRequiredProperty(element, "id");
399 std::string id = parseString(idElement);
400 ++propertyCount;
401
402 // Required actions property
403 const json& actionsElement = getRequiredProperty(element, "actions");
404 std::vector<std::unique_ptr<Action>> actions =
405 parseActionArray(actionsElement);
406 ++propertyCount;
407
408 // Verify no invalid properties exist
409 verifyPropertyCount(element, propertyCount);
410
411 return std::make_unique<Rule>(id, std::move(actions));
412}
413
414std::vector<std::unique_ptr<Rule>> parseRuleArray(const json& element)
415{
416 verifyIsArray(element);
417 std::vector<std::unique_ptr<Rule>> rules;
418 for (auto& ruleElement : element)
419 {
420 rules.emplace_back(parseRule(ruleElement));
421 }
422 return rules;
423}
424
425} // namespace internal
426
427} // namespace phosphor::power::regulators::config_file_parser