blob: db0cd7a00b2aa73aa3583a0af25806d0968daa44 [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 {
Bob King3a787542020-04-14 13:45:01 +080070 action = parseAnd(element["and"]);
71 ++propertyCount;
Shawn McCarney0e8c68a2020-03-27 01:44:48 -050072 }
73 else if (element.contains("compare_presence"))
74 {
Bob Kingb267b7e2020-04-22 14:42:39 +080075 action = parseComparePresence(element["compare_presence"]);
76 ++propertyCount;
Shawn McCarney0e8c68a2020-03-27 01:44:48 -050077 }
78 else if (element.contains("compare_vpd"))
79 {
Bob Kingf2134322020-04-27 14:14:56 +080080 action = parseCompareVPD(element["compare_vpd"]);
81 ++propertyCount;
Shawn McCarney0e8c68a2020-03-27 01:44:48 -050082 }
Shawn McCarney91f87a52021-09-07 09:59:57 -050083 else if (element.contains("i2c_capture_bytes"))
84 {
85 action = parseI2CCaptureBytes(element["i2c_capture_bytes"]);
86 ++propertyCount;
87 }
Shawn McCarney0e8c68a2020-03-27 01:44:48 -050088 else if (element.contains("i2c_compare_bit"))
89 {
Bob Kingf09bfe02020-04-13 17:21:15 +080090 action = parseI2CCompareBit(element["i2c_compare_bit"]);
91 ++propertyCount;
Shawn McCarney0e8c68a2020-03-27 01:44:48 -050092 }
93 else if (element.contains("i2c_compare_byte"))
94 {
Bob Kingf09bfe02020-04-13 17:21:15 +080095 action = parseI2CCompareByte(element["i2c_compare_byte"]);
96 ++propertyCount;
Shawn McCarney0e8c68a2020-03-27 01:44:48 -050097 }
98 else if (element.contains("i2c_compare_bytes"))
99 {
Bob Kingf09bfe02020-04-13 17:21:15 +0800100 action = parseI2CCompareBytes(element["i2c_compare_bytes"]);
101 ++propertyCount;
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500102 }
103 else if (element.contains("i2c_write_bit"))
104 {
Bob Kingf617f892020-03-30 19:03:35 +0800105 action = parseI2CWriteBit(element["i2c_write_bit"]);
106 ++propertyCount;
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500107 }
108 else if (element.contains("i2c_write_byte"))
109 {
Bob King87ff9d72020-03-31 14:02:55 +0800110 action = parseI2CWriteByte(element["i2c_write_byte"]);
111 ++propertyCount;
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500112 }
113 else if (element.contains("i2c_write_bytes"))
114 {
Bob Kingbafcb862020-03-31 16:39:00 +0800115 action = parseI2CWriteBytes(element["i2c_write_bytes"]);
116 ++propertyCount;
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500117 }
118 else if (element.contains("if"))
119 {
Bob King93a89d72020-04-15 15:11:11 +0800120 action = parseIf(element["if"]);
121 ++propertyCount;
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500122 }
Shawn McCarney11157852021-09-07 14:04:36 -0500123 else if (element.contains("log_phase_fault"))
124 {
125 action = parseLogPhaseFault(element["log_phase_fault"]);
126 ++propertyCount;
127 }
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500128 else if (element.contains("not"))
129 {
Bob Kingf1b58dc2020-04-14 14:53:10 +0800130 action = parseNot(element["not"]);
131 ++propertyCount;
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500132 }
133 else if (element.contains("or"))
134 {
Bob King0b51a9b2020-04-15 13:24:18 +0800135 action = parseOr(element["or"]);
136 ++propertyCount;
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500137 }
138 else if (element.contains("pmbus_read_sensor"))
139 {
Bob King84614882020-04-30 13:13:48 +0800140 action = parsePMBusReadSensor(element["pmbus_read_sensor"]);
141 ++propertyCount;
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500142 }
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 {
Bob King315b0b62020-04-03 21:47:58 +0800151 action = parseRunRule(element["run_rule"]);
152 ++propertyCount;
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500153 }
154 else if (element.contains("set_device"))
155 {
Bob King18a68502020-04-17 14:19:56 +0800156 action = parseSetDevice(element["set_device"]);
157 ++propertyCount;
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500158 }
159 else
160 {
161 throw std::invalid_argument{"Required action type property missing"};
162 }
163
164 // Verify no invalid properties exist
165 verifyPropertyCount(element, propertyCount);
166
167 return action;
168}
169
170std::vector<std::unique_ptr<Action>> parseActionArray(const json& element)
171{
172 verifyIsArray(element);
173 std::vector<std::unique_ptr<Action>> actions;
174 for (auto& actionElement : element)
175 {
176 actions.emplace_back(parseAction(actionElement));
177 }
178 return actions;
179}
180
Bob King3a787542020-04-14 13:45:01 +0800181std::unique_ptr<AndAction> parseAnd(const json& element)
182{
183 verifyIsArray(element);
184
185 // Verify if array size less than 2
186 if (element.size() < 2)
187 {
188 throw std::invalid_argument{"Array must contain two or more actions"};
189 }
190 // Array of two or more actions
191 std::vector<std::unique_ptr<Action>> actions = parseActionArray(element);
192
193 return std::make_unique<AndAction>(std::move(actions));
194}
195
Bob King0e701132020-04-03 21:50:31 +0800196std::unique_ptr<Chassis> parseChassis(const json& element)
197{
198 verifyIsObject(element);
199 unsigned int propertyCount{0};
200
201 // Optional comments property; value not stored
202 if (element.contains("comments"))
203 {
204 ++propertyCount;
205 }
206
207 // Required number property
208 const json& numberElement = getRequiredProperty(element, "number");
209 unsigned int number = parseUnsignedInteger(numberElement);
210 if (number < 1)
211 {
212 throw std::invalid_argument{"Invalid chassis number: Must be > 0"};
213 }
214 ++propertyCount;
215
Shawn McCarney4c88a4c2021-09-21 15:29:24 -0500216 // Required inventory_path property
217 const json& inventoryPathElement =
218 getRequiredProperty(element, "inventory_path");
219 std::string inventoryPath = parseInventoryPath(inventoryPathElement);
220 ++propertyCount;
Shawn McCarneycb3f6a62021-04-30 10:54:30 -0500221
Bob King0e701132020-04-03 21:50:31 +0800222 // Optional devices property
223 std::vector<std::unique_ptr<Device>> devices{};
224 auto devicesIt = element.find("devices");
225 if (devicesIt != element.end())
226 {
227 devices = parseDeviceArray(*devicesIt);
228 ++propertyCount;
229 }
230
231 // Verify no invalid properties exist
232 verifyPropertyCount(element, propertyCount);
233
Shawn McCarneycb3f6a62021-04-30 10:54:30 -0500234 return std::make_unique<Chassis>(number, inventoryPath, std::move(devices));
Bob King0e701132020-04-03 21:50:31 +0800235}
236
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500237std::vector<std::unique_ptr<Chassis>> parseChassisArray(const json& element)
238{
239 verifyIsArray(element);
240 std::vector<std::unique_ptr<Chassis>> chassis;
Bob King0e701132020-04-03 21:50:31 +0800241 for (auto& chassisElement : element)
242 {
243 chassis.emplace_back(parseChassis(chassisElement));
244 }
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500245 return chassis;
246}
247
Bob Kingb267b7e2020-04-22 14:42:39 +0800248std::unique_ptr<ComparePresenceAction> parseComparePresence(const json& element)
249{
250 verifyIsObject(element);
251 unsigned int propertyCount{0};
252
253 // Required fru property
254 const json& fruElement = getRequiredProperty(element, "fru");
Bob Kinga76898f2020-10-13 15:08:33 +0800255 std::string fru = parseInventoryPath(fruElement);
Bob Kingb267b7e2020-04-22 14:42:39 +0800256 ++propertyCount;
257
258 // Required value property
259 const json& valueElement = getRequiredProperty(element, "value");
260 bool value = parseBoolean(valueElement);
261 ++propertyCount;
262
263 // Verify no invalid properties exist
264 verifyPropertyCount(element, propertyCount);
265
266 return std::make_unique<ComparePresenceAction>(fru, value);
267}
268
Bob Kingf2134322020-04-27 14:14:56 +0800269std::unique_ptr<CompareVPDAction> parseCompareVPD(const json& element)
270{
271 verifyIsObject(element);
272 unsigned int propertyCount{0};
273
274 // Required fru property
275 const json& fruElement = getRequiredProperty(element, "fru");
Bob Kinga76898f2020-10-13 15:08:33 +0800276 std::string fru = parseInventoryPath(fruElement);
Bob Kingf2134322020-04-27 14:14:56 +0800277 ++propertyCount;
278
279 // Required keyword property
280 const json& keywordElement = getRequiredProperty(element, "keyword");
281 std::string keyword = parseString(keywordElement);
282 ++propertyCount;
283
Matt Spinleraacc2aa2021-05-25 09:31:35 -0600284 // Either value or byte_values required property
285 auto valueIt = element.find("value");
286 std::vector<uint8_t> value{};
287 auto byteValuesIt = element.find("byte_values");
288 if ((valueIt != element.end()) && (byteValuesIt == element.end()))
289 {
290 std::string stringValue = parseString(*valueIt);
291 value.insert(value.begin(), stringValue.begin(), stringValue.end());
292 ++propertyCount;
293 }
294 else if ((valueIt == element.end()) && (byteValuesIt != element.end()))
295 {
296 value = parseHexByteArray(*byteValuesIt);
297 ++propertyCount;
298 }
299 else
300 {
301 throw std::invalid_argument{
302 "Invalid property: Must contain either value or byte_values"};
303 }
Bob Kingf2134322020-04-27 14:14:56 +0800304
305 // Verify no invalid properties exist
306 verifyPropertyCount(element, propertyCount);
307
308 return std::make_unique<CompareVPDAction>(fru, keyword, value);
309}
310
Bob King33e7eaa2020-04-01 18:09:34 +0800311std::unique_ptr<Configuration> parseConfiguration(const json& element)
312{
313 verifyIsObject(element);
314 unsigned int propertyCount{0};
315
316 // Optional comments property; value not stored
317 if (element.contains("comments"))
318 {
319 ++propertyCount;
320 }
321
322 // Optional volts property
323 std::optional<double> volts{};
324 auto voltsIt = element.find("volts");
325 if (voltsIt != element.end())
326 {
327 volts = parseDouble(*voltsIt);
328 ++propertyCount;
329 }
330
331 // Required rule_id or actions property
332 std::vector<std::unique_ptr<Action>> actions{};
333 actions = parseRuleIDOrActionsProperty(element);
334 ++propertyCount;
335
336 // Verify no invalid properties exist
337 verifyPropertyCount(element, propertyCount);
338
339 return std::make_unique<Configuration>(volts, std::move(actions));
340}
341
Bob King9c36c5f2020-04-06 11:34:09 +0800342std::unique_ptr<Device> parseDevice(const json& element)
343{
344 verifyIsObject(element);
345 unsigned int propertyCount{0};
346
347 // Optional comments property; value not stored
348 if (element.contains("comments"))
349 {
350 ++propertyCount;
351 }
352
353 // Required id property
354 const json& idElement = getRequiredProperty(element, "id");
355 std::string id = parseString(idElement);
356 ++propertyCount;
357
358 // Required is_regulator property
359 const json& isRegulatorElement =
360 getRequiredProperty(element, "is_regulator");
361 bool isRegulator = parseBoolean(isRegulatorElement);
362 ++propertyCount;
363
364 // Required fru property
365 const json& fruElement = getRequiredProperty(element, "fru");
Bob Kinga76898f2020-10-13 15:08:33 +0800366 std::string fru = parseInventoryPath(fruElement);
Bob King9c36c5f2020-04-06 11:34:09 +0800367 ++propertyCount;
368
369 // Required i2c_interface property
370 const json& i2cInterfaceElement =
371 getRequiredProperty(element, "i2c_interface");
372 std::unique_ptr<i2c::I2CInterface> i2cInterface =
373 parseI2CInterface(i2cInterfaceElement);
374 ++propertyCount;
375
376 // Optional presence_detection property
Bob King9c36c5f2020-04-06 11:34:09 +0800377 std::unique_ptr<PresenceDetection> presenceDetection{};
Bob King2aafb1c2020-04-16 15:24:32 +0800378 auto presenceDetectionIt = element.find("presence_detection");
379 if (presenceDetectionIt != element.end())
380 {
381 presenceDetection = parsePresenceDetection(*presenceDetectionIt);
382 ++propertyCount;
383 }
Bob King9c36c5f2020-04-06 11:34:09 +0800384
385 // Optional configuration property
Bob King9c36c5f2020-04-06 11:34:09 +0800386 std::unique_ptr<Configuration> configuration{};
Bob King33e7eaa2020-04-01 18:09:34 +0800387 auto configurationIt = element.find("configuration");
388 if (configurationIt != element.end())
389 {
390 configuration = parseConfiguration(*configurationIt);
391 ++propertyCount;
392 }
Bob King9c36c5f2020-04-06 11:34:09 +0800393
Shawn McCarney32252592021-09-08 15:29:36 -0500394 // Optional phase_fault_detection property
395 std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
396 auto phaseFaultDetectionIt = element.find("phase_fault_detection");
397 if (phaseFaultDetectionIt != element.end())
398 {
399 if (!isRegulator)
400 {
401 throw std::invalid_argument{"Invalid phase_fault_detection "
402 "property when is_regulator is false"};
403 }
404 phaseFaultDetection = parsePhaseFaultDetection(*phaseFaultDetectionIt);
405 ++propertyCount;
406 }
407
Bob King9c36c5f2020-04-06 11:34:09 +0800408 // Optional rails property
409 std::vector<std::unique_ptr<Rail>> rails{};
410 auto railsIt = element.find("rails");
411 if (railsIt != element.end())
412 {
413 if (!isRegulator)
414 {
415 throw std::invalid_argument{
416 "Invalid rails property when is_regulator is false"};
417 }
418 rails = parseRailArray(*railsIt);
419 ++propertyCount;
420 }
421
422 // Verify no invalid properties exist
423 verifyPropertyCount(element, propertyCount);
424
Shawn McCarney32252592021-09-08 15:29:36 -0500425 return std::make_unique<Device>(
426 id, isRegulator, fru, std::move(i2cInterface),
427 std::move(presenceDetection), std::move(configuration),
428 std::move(phaseFaultDetection), std::move(rails));
Bob King9c36c5f2020-04-06 11:34:09 +0800429}
430
Bob King0e701132020-04-03 21:50:31 +0800431std::vector<std::unique_ptr<Device>> parseDeviceArray(const json& element)
432{
433 verifyIsArray(element);
434 std::vector<std::unique_ptr<Device>> devices;
Bob King9c36c5f2020-04-06 11:34:09 +0800435 for (auto& deviceElement : element)
436 {
437 devices.emplace_back(parseDevice(deviceElement));
438 }
Bob King0e701132020-04-03 21:50:31 +0800439 return devices;
440}
441
Bob Kingbafcb862020-03-31 16:39:00 +0800442std::vector<uint8_t> parseHexByteArray(const json& element)
443{
444 verifyIsArray(element);
445 std::vector<uint8_t> values;
446 for (auto& valueElement : element)
447 {
448 values.emplace_back(parseHexByte(valueElement));
449 }
450 return values;
451}
452
Shawn McCarney91f87a52021-09-07 09:59:57 -0500453std::unique_ptr<I2CCaptureBytesAction> parseI2CCaptureBytes(const json& element)
454{
455 verifyIsObject(element);
456 unsigned int propertyCount{0};
457
458 // Required register property
459 const json& regElement = getRequiredProperty(element, "register");
460 uint8_t reg = parseHexByte(regElement);
461 ++propertyCount;
462
463 // Required count property
464 const json& countElement = getRequiredProperty(element, "count");
465 uint8_t count = parseUint8(countElement);
466 if (count < 1)
467 {
468 throw std::invalid_argument{"Invalid byte count: Must be > 0"};
469 }
470 ++propertyCount;
471
472 // Verify no invalid properties exist
473 verifyPropertyCount(element, propertyCount);
474
475 return std::make_unique<I2CCaptureBytesAction>(reg, count);
476}
477
Bob Kingf09bfe02020-04-13 17:21:15 +0800478std::unique_ptr<I2CCompareBitAction> parseI2CCompareBit(const json& element)
479{
480 verifyIsObject(element);
481 unsigned int propertyCount{0};
482
483 // Required register property
484 const json& regElement = getRequiredProperty(element, "register");
485 uint8_t reg = parseHexByte(regElement);
486 ++propertyCount;
487
488 // Required position property
489 const json& positionElement = getRequiredProperty(element, "position");
490 uint8_t position = parseBitPosition(positionElement);
491 ++propertyCount;
492
493 // Required value property
494 const json& valueElement = getRequiredProperty(element, "value");
495 uint8_t value = parseBitValue(valueElement);
496 ++propertyCount;
497
498 // Verify no invalid properties exist
499 verifyPropertyCount(element, propertyCount);
500
501 return std::make_unique<I2CCompareBitAction>(reg, position, value);
502}
503
504std::unique_ptr<I2CCompareByteAction> parseI2CCompareByte(const json& element)
505{
506 verifyIsObject(element);
507 unsigned int propertyCount{0};
508
509 // Required register property
510 const json& regElement = getRequiredProperty(element, "register");
511 uint8_t reg = parseHexByte(regElement);
512 ++propertyCount;
513
514 // Required value property
515 const json& valueElement = getRequiredProperty(element, "value");
516 uint8_t value = parseHexByte(valueElement);
517 ++propertyCount;
518
519 // Optional mask property
520 uint8_t mask = 0xff;
521 auto maskIt = element.find("mask");
522 if (maskIt != element.end())
523 {
524 mask = parseHexByte(*maskIt);
525 ++propertyCount;
526 }
527
528 // Verify no invalid properties exist
529 verifyPropertyCount(element, propertyCount);
530
531 return std::make_unique<I2CCompareByteAction>(reg, value, mask);
532}
533
534std::unique_ptr<I2CCompareBytesAction> parseI2CCompareBytes(const json& element)
535{
536 verifyIsObject(element);
537 unsigned int propertyCount{0};
538
539 // Required register property
540 const json& regElement = getRequiredProperty(element, "register");
541 uint8_t reg = parseHexByte(regElement);
542 ++propertyCount;
543
544 // Required values property
545 const json& valueElement = getRequiredProperty(element, "values");
546 std::vector<uint8_t> values = parseHexByteArray(valueElement);
547 ++propertyCount;
548
549 // Optional masks property
550 std::vector<uint8_t> masks{};
551 auto masksIt = element.find("masks");
552 if (masksIt != element.end())
553 {
554 masks = parseHexByteArray(*masksIt);
555 ++propertyCount;
556 }
557
558 // Verify masks array (if specified) was same size as values array
559 if ((!masks.empty()) && (masks.size() != values.size()))
560 {
561 throw std::invalid_argument{"Invalid number of elements in masks"};
562 }
563
564 // Verify no invalid properties exist
565 verifyPropertyCount(element, propertyCount);
566
567 if (masks.empty())
568 {
569 return std::make_unique<I2CCompareBytesAction>(reg, values);
570 }
571 return std::make_unique<I2CCompareBytesAction>(reg, values, masks);
572}
573
Bob King9c36c5f2020-04-06 11:34:09 +0800574std::unique_ptr<i2c::I2CInterface> parseI2CInterface(const json& element)
575{
576 verifyIsObject(element);
577 unsigned int propertyCount{0};
578
579 // Required bus property
580 const json& busElement = getRequiredProperty(element, "bus");
581 uint8_t bus = parseUint8(busElement);
582 ++propertyCount;
583
584 // Required address property
585 const json& addressElement = getRequiredProperty(element, "address");
586 uint8_t address = parseHexByte(addressElement);
587 ++propertyCount;
588
589 verifyPropertyCount(element, propertyCount);
590 return i2c::create(bus, address, i2c::I2CInterface::InitialState::CLOSED);
591}
592
Bob Kingf617f892020-03-30 19:03:35 +0800593std::unique_ptr<I2CWriteBitAction> parseI2CWriteBit(const json& element)
594{
595 verifyIsObject(element);
596 unsigned int propertyCount{0};
597
598 // Required register property
599 const json& regElement = getRequiredProperty(element, "register");
Bob Kingbafcb862020-03-31 16:39:00 +0800600 uint8_t reg = parseHexByte(regElement);
Bob Kingf617f892020-03-30 19:03:35 +0800601 ++propertyCount;
602
603 // Required position property
604 const json& positionElement = getRequiredProperty(element, "position");
605 uint8_t position = parseBitPosition(positionElement);
606 ++propertyCount;
607
608 // Required value property
609 const json& valueElement = getRequiredProperty(element, "value");
610 uint8_t value = parseBitValue(valueElement);
611 ++propertyCount;
612
613 // Verify no invalid properties exist
614 verifyPropertyCount(element, propertyCount);
615
616 return std::make_unique<I2CWriteBitAction>(reg, position, value);
617}
618
Bob King87ff9d72020-03-31 14:02:55 +0800619std::unique_ptr<I2CWriteByteAction> parseI2CWriteByte(const json& element)
620{
621 verifyIsObject(element);
622 unsigned int propertyCount{0};
623
624 // Required register property
625 const json& regElement = getRequiredProperty(element, "register");
Bob Kingbafcb862020-03-31 16:39:00 +0800626 uint8_t reg = parseHexByte(regElement);
Bob King87ff9d72020-03-31 14:02:55 +0800627 ++propertyCount;
628
629 // Required value property
630 const json& valueElement = getRequiredProperty(element, "value");
Bob Kingbafcb862020-03-31 16:39:00 +0800631 uint8_t value = parseHexByte(valueElement);
Bob King87ff9d72020-03-31 14:02:55 +0800632 ++propertyCount;
633
634 // Optional mask property
635 uint8_t mask = 0xff;
636 auto maskIt = element.find("mask");
637 if (maskIt != element.end())
638 {
Bob Kingbafcb862020-03-31 16:39:00 +0800639 mask = parseHexByte(*maskIt);
Bob King87ff9d72020-03-31 14:02:55 +0800640 ++propertyCount;
641 }
642
643 // Verify no invalid properties exist
644 verifyPropertyCount(element, propertyCount);
645
646 return std::make_unique<I2CWriteByteAction>(reg, value, mask);
647}
648
Bob Kingbafcb862020-03-31 16:39:00 +0800649std::unique_ptr<I2CWriteBytesAction> parseI2CWriteBytes(const json& element)
650{
651 verifyIsObject(element);
652 unsigned int propertyCount{0};
653
654 // Required register property
655 const json& regElement = getRequiredProperty(element, "register");
656 uint8_t reg = parseHexByte(regElement);
657 ++propertyCount;
658
659 // Required values property
660 const json& valueElement = getRequiredProperty(element, "values");
661 std::vector<uint8_t> values = parseHexByteArray(valueElement);
662 ++propertyCount;
663
664 // Optional masks property
665 std::vector<uint8_t> masks{};
666 auto masksIt = element.find("masks");
667 if (masksIt != element.end())
668 {
669 masks = parseHexByteArray(*masksIt);
670 ++propertyCount;
671 }
672
673 // Verify masks array (if specified) was same size as values array
674 if ((!masks.empty()) && (masks.size() != values.size()))
675 {
676 throw std::invalid_argument{"Invalid number of elements in masks"};
677 }
678
679 // Verify no invalid properties exist
680 verifyPropertyCount(element, propertyCount);
681
682 if (masks.empty())
683 {
684 return std::make_unique<I2CWriteBytesAction>(reg, values);
685 }
686 return std::make_unique<I2CWriteBytesAction>(reg, values, masks);
687}
688
Bob King93a89d72020-04-15 15:11:11 +0800689std::unique_ptr<IfAction> parseIf(const json& element)
690{
691 verifyIsObject(element);
692 unsigned int propertyCount{0};
693
694 // Required condition property
695 const json& conditionElement = getRequiredProperty(element, "condition");
696 std::unique_ptr<Action> conditionAction = parseAction(conditionElement);
697 ++propertyCount;
698
699 // Required then property
700 const json& thenElement = getRequiredProperty(element, "then");
701 std::vector<std::unique_ptr<Action>> thenActions =
702 parseActionArray(thenElement);
703 ++propertyCount;
704
705 // Optional else property
706 std::vector<std::unique_ptr<Action>> elseActions{};
707 auto elseIt = element.find("else");
708 if (elseIt != element.end())
709 {
710 elseActions = parseActionArray(*elseIt);
711 ++propertyCount;
712 }
713
714 // Verify no invalid properties exist
715 verifyPropertyCount(element, propertyCount);
716
717 return std::make_unique<IfAction>(std::move(conditionAction),
718 std::move(thenActions),
719 std::move(elseActions));
720}
721
Bob Kinga76898f2020-10-13 15:08:33 +0800722std::string parseInventoryPath(const json& element)
723{
724 std::string inventoryPath = parseString(element);
725 std::string absPath = "/xyz/openbmc_project/inventory";
726 if (inventoryPath.front() != '/')
727 {
728 absPath += '/';
729 }
730 absPath += inventoryPath;
731 return absPath;
732}
733
Shawn McCarney11157852021-09-07 14:04:36 -0500734std::unique_ptr<LogPhaseFaultAction> parseLogPhaseFault(const json& element)
735{
736 verifyIsObject(element);
737 unsigned int propertyCount{0};
738
739 // Required type property
740 const json& typeElement = getRequiredProperty(element, "type");
741 PhaseFaultType type = parsePhaseFaultType(typeElement);
742 ++propertyCount;
743
744 // Verify no invalid properties exist
745 verifyPropertyCount(element, propertyCount);
746
747 return std::make_unique<LogPhaseFaultAction>(type);
748}
749
Bob Kingf1b58dc2020-04-14 14:53:10 +0800750std::unique_ptr<NotAction> parseNot(const json& element)
751{
752 // Required action to execute
753 std::unique_ptr<Action> action = parseAction(element);
754
755 return std::make_unique<NotAction>(std::move(action));
756}
757
Bob King0b51a9b2020-04-15 13:24:18 +0800758std::unique_ptr<OrAction> parseOr(const json& element)
759{
760 verifyIsArray(element);
761
762 // Verify if array size less than 2
763 if (element.size() < 2)
764 {
765 throw std::invalid_argument{"Array must contain two or more actions"};
766 }
767 // Array of two or more actions
768 std::vector<std::unique_ptr<Action>> actions = parseActionArray(element);
769
770 return std::make_unique<OrAction>(std::move(actions));
771}
772
Shawn McCarney39eb08a2021-09-07 16:34:49 -0500773std::unique_ptr<PhaseFaultDetection>
774 parsePhaseFaultDetection(const json& element)
775{
776 verifyIsObject(element);
777 unsigned int propertyCount{0};
778
779 // Optional comments property; value not stored
780 if (element.contains("comments"))
781 {
782 ++propertyCount;
783 }
784
785 // Optional device_id property
786 std::string deviceID{};
787 auto deviceIDIt = element.find("device_id");
788 if (deviceIDIt != element.end())
789 {
790 deviceID = parseString(*deviceIDIt);
791 ++propertyCount;
792 }
793
794 // Required rule_id or actions property
795 std::vector<std::unique_ptr<Action>> actions{};
796 actions = parseRuleIDOrActionsProperty(element);
797 ++propertyCount;
798
799 // Verify no invalid properties exist
800 verifyPropertyCount(element, propertyCount);
801
802 return std::make_unique<PhaseFaultDetection>(std::move(actions), deviceID);
803}
804
Shawn McCarneyb70370b2021-09-07 12:07:40 -0500805PhaseFaultType parsePhaseFaultType(const json& element)
806{
807 std::string value = parseString(element);
808 PhaseFaultType type{};
809
810 if (value == "n")
811 {
812 type = PhaseFaultType::n;
813 }
814 else if (value == "n+1")
815 {
816 type = PhaseFaultType::n_plus_1;
817 }
818 else
819 {
820 throw std::invalid_argument{"Element is not a phase fault type"};
821 }
822
823 return type;
824}
825
Bob King84614882020-04-30 13:13:48 +0800826std::unique_ptr<PMBusReadSensorAction> parsePMBusReadSensor(const json& element)
827{
828 verifyIsObject(element);
829 unsigned int propertyCount{0};
830
831 // Required type property
832 const json& typeElement = getRequiredProperty(element, "type");
Shawn McCarney2f9e14f2021-04-29 02:45:18 -0500833 SensorType type = parseSensorType(typeElement);
Bob King84614882020-04-30 13:13:48 +0800834 ++propertyCount;
835
836 // Required command property
837 const json& commandElement = getRequiredProperty(element, "command");
838 uint8_t command = parseHexByte(commandElement);
839 ++propertyCount;
840
841 // Required format property
842 const json& formatElement = getRequiredProperty(element, "format");
843 pmbus_utils::SensorDataFormat format = parseSensorDataFormat(formatElement);
844 ++propertyCount;
845
846 // Optional exponent property
847 std::optional<int8_t> exponent{};
848 auto exponentIt = element.find("exponent");
849 if (exponentIt != element.end())
850 {
851 exponent = parseInt8(*exponentIt);
852 ++propertyCount;
853 }
854
855 // Verify no invalid properties exist
856 verifyPropertyCount(element, propertyCount);
857
858 return std::make_unique<PMBusReadSensorAction>(type, command, format,
859 exponent);
860}
861
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500862std::unique_ptr<PMBusWriteVoutCommandAction>
863 parsePMBusWriteVoutCommand(const json& element)
864{
865 verifyIsObject(element);
866 unsigned int propertyCount{0};
867
868 // Optional volts property
869 std::optional<double> volts{};
870 auto voltsIt = element.find("volts");
871 if (voltsIt != element.end())
872 {
873 volts = parseDouble(*voltsIt);
874 ++propertyCount;
875 }
876
877 // Required format property
878 const json& formatElement = getRequiredProperty(element, "format");
879 std::string formatString = parseString(formatElement);
880 if (formatString != "linear")
881 {
882 throw std::invalid_argument{"Invalid format value: " + formatString};
883 }
884 pmbus_utils::VoutDataFormat format = pmbus_utils::VoutDataFormat::linear;
885 ++propertyCount;
886
887 // Optional exponent property
888 std::optional<int8_t> exponent{};
889 auto exponentIt = element.find("exponent");
890 if (exponentIt != element.end())
891 {
892 exponent = parseInt8(*exponentIt);
893 ++propertyCount;
894 }
895
896 // Optional is_verified property
897 bool isVerified = false;
898 auto isVerifiedIt = element.find("is_verified");
899 if (isVerifiedIt != element.end())
900 {
901 isVerified = parseBoolean(*isVerifiedIt);
902 ++propertyCount;
903 }
904
905 // Verify no invalid properties exist
906 verifyPropertyCount(element, propertyCount);
907
908 return std::make_unique<PMBusWriteVoutCommandAction>(volts, format,
909 exponent, isVerified);
910}
911
Bob King2aafb1c2020-04-16 15:24:32 +0800912std::unique_ptr<PresenceDetection> parsePresenceDetection(const json& element)
913{
914 verifyIsObject(element);
915 unsigned int propertyCount{0};
916
917 // Optional comments property; value not stored
918 if (element.contains("comments"))
919 {
920 ++propertyCount;
921 }
922
923 // Required rule_id or actions property
924 std::vector<std::unique_ptr<Action>> actions{};
925 actions = parseRuleIDOrActionsProperty(element);
926 ++propertyCount;
927
928 // Verify no invalid properties exist
929 verifyPropertyCount(element, propertyCount);
930
931 return std::make_unique<PresenceDetection>(std::move(actions));
932}
933
Bob Kinga2f2a0d2020-04-09 13:32:14 +0800934std::unique_ptr<Rail> parseRail(const json& element)
935{
936 verifyIsObject(element);
937 unsigned int propertyCount{0};
938
939 // Optional comments property; value not stored
940 if (element.contains("comments"))
941 {
942 ++propertyCount;
943 }
944
945 // Required id property
946 const json& idElement = getRequiredProperty(element, "id");
947 std::string id = parseString(idElement);
948 ++propertyCount;
949
950 // Optional configuration property
951 std::unique_ptr<Configuration> configuration{};
952 auto configurationIt = element.find("configuration");
953 if (configurationIt != element.end())
954 {
955 configuration = parseConfiguration(*configurationIt);
956 ++propertyCount;
957 }
958
959 // Optional sensor_monitoring property
960 std::unique_ptr<SensorMonitoring> sensorMonitoring{};
961 auto sensorMonitoringIt = element.find("sensor_monitoring");
962 if (sensorMonitoringIt != element.end())
963 {
964 sensorMonitoring = parseSensorMonitoring(*sensorMonitoringIt);
965 ++propertyCount;
966 }
967
968 // Verify no invalid properties exist
969 verifyPropertyCount(element, propertyCount);
970
971 return std::make_unique<Rail>(id, std::move(configuration),
972 std::move(sensorMonitoring));
973}
974
Bob King9c36c5f2020-04-06 11:34:09 +0800975std::vector<std::unique_ptr<Rail>> parseRailArray(const json& element)
976{
977 verifyIsArray(element);
978 std::vector<std::unique_ptr<Rail>> rails;
Bob Kinga2f2a0d2020-04-09 13:32:14 +0800979 for (auto& railElement : element)
980 {
981 rails.emplace_back(parseRail(railElement));
982 }
Bob King9c36c5f2020-04-06 11:34:09 +0800983 return rails;
984}
985
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500986std::tuple<std::vector<std::unique_ptr<Rule>>,
987 std::vector<std::unique_ptr<Chassis>>>
988 parseRoot(const json& element)
989{
990 verifyIsObject(element);
991 unsigned int propertyCount{0};
992
993 // Optional comments property; value not stored
994 if (element.contains("comments"))
995 {
996 ++propertyCount;
997 }
998
999 // Optional rules property
1000 std::vector<std::unique_ptr<Rule>> rules{};
1001 auto rulesIt = element.find("rules");
1002 if (rulesIt != element.end())
1003 {
1004 rules = parseRuleArray(*rulesIt);
1005 ++propertyCount;
1006 }
1007
1008 // Required chassis property
1009 const json& chassisElement = getRequiredProperty(element, "chassis");
1010 std::vector<std::unique_ptr<Chassis>> chassis =
1011 parseChassisArray(chassisElement);
1012 ++propertyCount;
1013
1014 // Verify no invalid properties exist
1015 verifyPropertyCount(element, propertyCount);
1016
1017 return std::make_tuple(std::move(rules), std::move(chassis));
1018}
1019
1020std::unique_ptr<Rule> parseRule(const json& element)
1021{
1022 verifyIsObject(element);
1023 unsigned int propertyCount{0};
1024
1025 // Optional comments property; value not stored
1026 if (element.contains("comments"))
1027 {
1028 ++propertyCount;
1029 }
1030
1031 // Required id property
1032 const json& idElement = getRequiredProperty(element, "id");
1033 std::string id = parseString(idElement);
1034 ++propertyCount;
1035
1036 // Required actions property
1037 const json& actionsElement = getRequiredProperty(element, "actions");
1038 std::vector<std::unique_ptr<Action>> actions =
1039 parseActionArray(actionsElement);
1040 ++propertyCount;
1041
1042 // Verify no invalid properties exist
1043 verifyPropertyCount(element, propertyCount);
1044
1045 return std::make_unique<Rule>(id, std::move(actions));
1046}
1047
1048std::vector<std::unique_ptr<Rule>> parseRuleArray(const json& element)
1049{
1050 verifyIsArray(element);
1051 std::vector<std::unique_ptr<Rule>> rules;
1052 for (auto& ruleElement : element)
1053 {
1054 rules.emplace_back(parseRule(ruleElement));
1055 }
1056 return rules;
1057}
1058
Bob King33e7eaa2020-04-01 18:09:34 +08001059std::vector<std::unique_ptr<Action>>
1060 parseRuleIDOrActionsProperty(const json& element)
1061{
1062 verifyIsObject(element);
1063 // Required rule_id or actions property
1064 std::vector<std::unique_ptr<Action>> actions{};
1065 auto ruleIDIt = element.find("rule_id");
1066 auto actionsIt = element.find("actions");
1067 if ((actionsIt == element.end()) && (ruleIDIt != element.end()))
1068 {
1069 std::string ruleID = parseString(*ruleIDIt);
1070 actions.emplace_back(std::make_unique<RunRuleAction>(ruleID));
1071 }
1072 else if ((actionsIt != element.end()) && (ruleIDIt == element.end()))
1073 {
1074 actions = parseActionArray(*actionsIt);
1075 }
1076 else
1077 {
1078 throw std::invalid_argument{"Invalid property combination: Must "
1079 "contain either rule_id or actions"};
1080 }
1081
1082 return actions;
1083}
1084
Bob King315b0b62020-04-03 21:47:58 +08001085std::unique_ptr<RunRuleAction> parseRunRule(const json& element)
1086{
1087 // String ruleID
1088 std::string ruleID = parseString(element);
1089
1090 return std::make_unique<RunRuleAction>(ruleID);
1091}
1092
Bob King84614882020-04-30 13:13:48 +08001093pmbus_utils::SensorDataFormat parseSensorDataFormat(const json& element)
1094{
1095 if (!element.is_string())
1096 {
1097 throw std::invalid_argument{"Element is not a string"};
1098 }
1099 std::string value = element.get<std::string>();
1100 pmbus_utils::SensorDataFormat format{};
1101
1102 if (value == "linear_11")
1103 {
1104 format = pmbus_utils::SensorDataFormat::linear_11;
1105 }
1106 else if (value == "linear_16")
1107 {
1108 format = pmbus_utils::SensorDataFormat::linear_16;
1109 }
1110 else
1111 {
1112 throw std::invalid_argument{"Element is not a sensor data format"};
1113 }
1114
1115 return format;
1116}
1117
Bob Kinga2f2a0d2020-04-09 13:32:14 +08001118std::unique_ptr<SensorMonitoring> parseSensorMonitoring(const json& element)
1119{
1120 verifyIsObject(element);
1121 unsigned int propertyCount{0};
1122
1123 // Optional comments property; value not stored
1124 if (element.contains("comments"))
1125 {
1126 ++propertyCount;
1127 }
1128
1129 // Required rule_id or actions property
1130 std::vector<std::unique_ptr<Action>> actions{};
1131 actions = parseRuleIDOrActionsProperty(element);
1132 ++propertyCount;
1133
1134 // Verify no invalid properties exist
1135 verifyPropertyCount(element, propertyCount);
1136
1137 return std::make_unique<SensorMonitoring>(std::move(actions));
1138}
1139
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001140SensorType parseSensorType(const json& element)
Bob King84614882020-04-30 13:13:48 +08001141{
Shawn McCarneyb70370b2021-09-07 12:07:40 -05001142 std::string value = parseString(element);
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001143 SensorType type{};
Bob King84614882020-04-30 13:13:48 +08001144
1145 if (value == "iout")
1146 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001147 type = SensorType::iout;
Bob King84614882020-04-30 13:13:48 +08001148 }
1149 else if (value == "iout_peak")
1150 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001151 type = SensorType::iout_peak;
Bob King84614882020-04-30 13:13:48 +08001152 }
1153 else if (value == "iout_valley")
1154 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001155 type = SensorType::iout_valley;
Bob King84614882020-04-30 13:13:48 +08001156 }
1157 else if (value == "pout")
1158 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001159 type = SensorType::pout;
Bob King84614882020-04-30 13:13:48 +08001160 }
1161 else if (value == "temperature")
1162 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001163 type = SensorType::temperature;
Bob King84614882020-04-30 13:13:48 +08001164 }
1165 else if (value == "temperature_peak")
1166 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001167 type = SensorType::temperature_peak;
Bob King84614882020-04-30 13:13:48 +08001168 }
1169 else if (value == "vout")
1170 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001171 type = SensorType::vout;
Bob King84614882020-04-30 13:13:48 +08001172 }
1173 else if (value == "vout_peak")
1174 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001175 type = SensorType::vout_peak;
Bob King84614882020-04-30 13:13:48 +08001176 }
1177 else if (value == "vout_valley")
1178 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001179 type = SensorType::vout_valley;
Bob King84614882020-04-30 13:13:48 +08001180 }
1181 else
1182 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001183 throw std::invalid_argument{"Element is not a sensor type"};
Bob King84614882020-04-30 13:13:48 +08001184 }
1185
1186 return type;
1187}
1188
Bob King18a68502020-04-17 14:19:56 +08001189std::unique_ptr<SetDeviceAction> parseSetDevice(const json& element)
1190{
1191 // String deviceID
1192 std::string deviceID = parseString(element);
1193
1194 return std::make_unique<SetDeviceAction>(deviceID);
1195}
1196
Bob King84614882020-04-30 13:13:48 +08001197pmbus_utils::VoutDataFormat parseVoutDataFormat(const json& element)
1198{
1199 if (!element.is_string())
1200 {
1201 throw std::invalid_argument{"Element is not a string"};
1202 }
1203 std::string value = element.get<std::string>();
1204 pmbus_utils::VoutDataFormat format{};
1205
1206 if (value == "linear")
1207 {
1208 format = pmbus_utils::VoutDataFormat::linear;
1209 }
1210 else if (value == "vid")
1211 {
1212 format = pmbus_utils::VoutDataFormat::vid;
1213 }
1214 else if (value == "direct")
1215 {
1216 format = pmbus_utils::VoutDataFormat::direct;
1217 }
1218 else if (value == "ieee")
1219 {
1220 format = pmbus_utils::VoutDataFormat::ieee;
1221 }
1222 else
1223 {
1224 throw std::invalid_argument{"Element is not a vout data format"};
1225 }
1226
1227 return format;
1228}
1229
Shawn McCarney0e8c68a2020-03-27 01:44:48 -05001230} // namespace internal
1231
1232} // namespace phosphor::power::regulators::config_file_parser