blob: 4bb8bd881b7c9eabf92bb3e5bb61e93a84c15165 [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 {
Shawn McCarneya2a830b2021-10-30 14:24:31 -0500290 std::string stringValue = parseString(*valueIt, true);
Matt Spinleraacc2aa2021-05-25 09:31:35 -0600291 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
Shawn McCarney5d23d9d2021-11-08 23:31:29 -0600589 // Verify no invalid properties exist
Bob King9c36c5f2020-04-06 11:34:09 +0800590 verifyPropertyCount(element, propertyCount);
Shawn McCarney5d23d9d2021-11-08 23:31:29 -0600591
592 // Create I2CInterface object; retry failed I2C operations a max of 3 times.
593 int maxRetries{3};
594 return i2c::create(bus, address, i2c::I2CInterface::InitialState::CLOSED,
595 maxRetries);
Bob King9c36c5f2020-04-06 11:34:09 +0800596}
597
Bob Kingf617f892020-03-30 19:03:35 +0800598std::unique_ptr<I2CWriteBitAction> parseI2CWriteBit(const json& element)
599{
600 verifyIsObject(element);
601 unsigned int propertyCount{0};
602
603 // Required register property
604 const json& regElement = getRequiredProperty(element, "register");
Bob Kingbafcb862020-03-31 16:39:00 +0800605 uint8_t reg = parseHexByte(regElement);
Bob Kingf617f892020-03-30 19:03:35 +0800606 ++propertyCount;
607
608 // Required position property
609 const json& positionElement = getRequiredProperty(element, "position");
610 uint8_t position = parseBitPosition(positionElement);
611 ++propertyCount;
612
613 // Required value property
614 const json& valueElement = getRequiredProperty(element, "value");
615 uint8_t value = parseBitValue(valueElement);
616 ++propertyCount;
617
618 // Verify no invalid properties exist
619 verifyPropertyCount(element, propertyCount);
620
621 return std::make_unique<I2CWriteBitAction>(reg, position, value);
622}
623
Bob King87ff9d72020-03-31 14:02:55 +0800624std::unique_ptr<I2CWriteByteAction> parseI2CWriteByte(const json& element)
625{
626 verifyIsObject(element);
627 unsigned int propertyCount{0};
628
629 // Required register property
630 const json& regElement = getRequiredProperty(element, "register");
Bob Kingbafcb862020-03-31 16:39:00 +0800631 uint8_t reg = parseHexByte(regElement);
Bob King87ff9d72020-03-31 14:02:55 +0800632 ++propertyCount;
633
634 // Required value property
635 const json& valueElement = getRequiredProperty(element, "value");
Bob Kingbafcb862020-03-31 16:39:00 +0800636 uint8_t value = parseHexByte(valueElement);
Bob King87ff9d72020-03-31 14:02:55 +0800637 ++propertyCount;
638
639 // Optional mask property
640 uint8_t mask = 0xff;
641 auto maskIt = element.find("mask");
642 if (maskIt != element.end())
643 {
Bob Kingbafcb862020-03-31 16:39:00 +0800644 mask = parseHexByte(*maskIt);
Bob King87ff9d72020-03-31 14:02:55 +0800645 ++propertyCount;
646 }
647
648 // Verify no invalid properties exist
649 verifyPropertyCount(element, propertyCount);
650
651 return std::make_unique<I2CWriteByteAction>(reg, value, mask);
652}
653
Bob Kingbafcb862020-03-31 16:39:00 +0800654std::unique_ptr<I2CWriteBytesAction> parseI2CWriteBytes(const json& element)
655{
656 verifyIsObject(element);
657 unsigned int propertyCount{0};
658
659 // Required register property
660 const json& regElement = getRequiredProperty(element, "register");
661 uint8_t reg = parseHexByte(regElement);
662 ++propertyCount;
663
664 // Required values property
665 const json& valueElement = getRequiredProperty(element, "values");
666 std::vector<uint8_t> values = parseHexByteArray(valueElement);
667 ++propertyCount;
668
669 // Optional masks property
670 std::vector<uint8_t> masks{};
671 auto masksIt = element.find("masks");
672 if (masksIt != element.end())
673 {
674 masks = parseHexByteArray(*masksIt);
675 ++propertyCount;
676 }
677
678 // Verify masks array (if specified) was same size as values array
679 if ((!masks.empty()) && (masks.size() != values.size()))
680 {
681 throw std::invalid_argument{"Invalid number of elements in masks"};
682 }
683
684 // Verify no invalid properties exist
685 verifyPropertyCount(element, propertyCount);
686
687 if (masks.empty())
688 {
689 return std::make_unique<I2CWriteBytesAction>(reg, values);
690 }
691 return std::make_unique<I2CWriteBytesAction>(reg, values, masks);
692}
693
Bob King93a89d72020-04-15 15:11:11 +0800694std::unique_ptr<IfAction> parseIf(const json& element)
695{
696 verifyIsObject(element);
697 unsigned int propertyCount{0};
698
699 // Required condition property
700 const json& conditionElement = getRequiredProperty(element, "condition");
701 std::unique_ptr<Action> conditionAction = parseAction(conditionElement);
702 ++propertyCount;
703
704 // Required then property
705 const json& thenElement = getRequiredProperty(element, "then");
706 std::vector<std::unique_ptr<Action>> thenActions =
707 parseActionArray(thenElement);
708 ++propertyCount;
709
710 // Optional else property
711 std::vector<std::unique_ptr<Action>> elseActions{};
712 auto elseIt = element.find("else");
713 if (elseIt != element.end())
714 {
715 elseActions = parseActionArray(*elseIt);
716 ++propertyCount;
717 }
718
719 // Verify no invalid properties exist
720 verifyPropertyCount(element, propertyCount);
721
722 return std::make_unique<IfAction>(std::move(conditionAction),
723 std::move(thenActions),
724 std::move(elseActions));
725}
726
Bob Kinga76898f2020-10-13 15:08:33 +0800727std::string parseInventoryPath(const json& element)
728{
729 std::string inventoryPath = parseString(element);
730 std::string absPath = "/xyz/openbmc_project/inventory";
731 if (inventoryPath.front() != '/')
732 {
733 absPath += '/';
734 }
735 absPath += inventoryPath;
736 return absPath;
737}
738
Shawn McCarney11157852021-09-07 14:04:36 -0500739std::unique_ptr<LogPhaseFaultAction> parseLogPhaseFault(const json& element)
740{
741 verifyIsObject(element);
742 unsigned int propertyCount{0};
743
744 // Required type property
745 const json& typeElement = getRequiredProperty(element, "type");
746 PhaseFaultType type = parsePhaseFaultType(typeElement);
747 ++propertyCount;
748
749 // Verify no invalid properties exist
750 verifyPropertyCount(element, propertyCount);
751
752 return std::make_unique<LogPhaseFaultAction>(type);
753}
754
Bob Kingf1b58dc2020-04-14 14:53:10 +0800755std::unique_ptr<NotAction> parseNot(const json& element)
756{
757 // Required action to execute
758 std::unique_ptr<Action> action = parseAction(element);
759
760 return std::make_unique<NotAction>(std::move(action));
761}
762
Bob King0b51a9b2020-04-15 13:24:18 +0800763std::unique_ptr<OrAction> parseOr(const json& element)
764{
765 verifyIsArray(element);
766
767 // Verify if array size less than 2
768 if (element.size() < 2)
769 {
770 throw std::invalid_argument{"Array must contain two or more actions"};
771 }
772 // Array of two or more actions
773 std::vector<std::unique_ptr<Action>> actions = parseActionArray(element);
774
775 return std::make_unique<OrAction>(std::move(actions));
776}
777
Shawn McCarney39eb08a2021-09-07 16:34:49 -0500778std::unique_ptr<PhaseFaultDetection>
779 parsePhaseFaultDetection(const json& element)
780{
781 verifyIsObject(element);
782 unsigned int propertyCount{0};
783
784 // Optional comments property; value not stored
785 if (element.contains("comments"))
786 {
787 ++propertyCount;
788 }
789
790 // Optional device_id property
791 std::string deviceID{};
792 auto deviceIDIt = element.find("device_id");
793 if (deviceIDIt != element.end())
794 {
795 deviceID = parseString(*deviceIDIt);
796 ++propertyCount;
797 }
798
799 // Required rule_id or actions property
800 std::vector<std::unique_ptr<Action>> actions{};
801 actions = parseRuleIDOrActionsProperty(element);
802 ++propertyCount;
803
804 // Verify no invalid properties exist
805 verifyPropertyCount(element, propertyCount);
806
807 return std::make_unique<PhaseFaultDetection>(std::move(actions), deviceID);
808}
809
Shawn McCarneyb70370b2021-09-07 12:07:40 -0500810PhaseFaultType parsePhaseFaultType(const json& element)
811{
812 std::string value = parseString(element);
813 PhaseFaultType type{};
814
815 if (value == "n")
816 {
817 type = PhaseFaultType::n;
818 }
819 else if (value == "n+1")
820 {
821 type = PhaseFaultType::n_plus_1;
822 }
823 else
824 {
825 throw std::invalid_argument{"Element is not a phase fault type"};
826 }
827
828 return type;
829}
830
Bob King84614882020-04-30 13:13:48 +0800831std::unique_ptr<PMBusReadSensorAction> parsePMBusReadSensor(const json& element)
832{
833 verifyIsObject(element);
834 unsigned int propertyCount{0};
835
836 // Required type property
837 const json& typeElement = getRequiredProperty(element, "type");
Shawn McCarney2f9e14f2021-04-29 02:45:18 -0500838 SensorType type = parseSensorType(typeElement);
Bob King84614882020-04-30 13:13:48 +0800839 ++propertyCount;
840
841 // Required command property
842 const json& commandElement = getRequiredProperty(element, "command");
843 uint8_t command = parseHexByte(commandElement);
844 ++propertyCount;
845
846 // Required format property
847 const json& formatElement = getRequiredProperty(element, "format");
848 pmbus_utils::SensorDataFormat format = parseSensorDataFormat(formatElement);
849 ++propertyCount;
850
851 // Optional exponent property
852 std::optional<int8_t> exponent{};
853 auto exponentIt = element.find("exponent");
854 if (exponentIt != element.end())
855 {
856 exponent = parseInt8(*exponentIt);
857 ++propertyCount;
858 }
859
860 // Verify no invalid properties exist
861 verifyPropertyCount(element, propertyCount);
862
863 return std::make_unique<PMBusReadSensorAction>(type, command, format,
864 exponent);
865}
866
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500867std::unique_ptr<PMBusWriteVoutCommandAction>
868 parsePMBusWriteVoutCommand(const json& element)
869{
870 verifyIsObject(element);
871 unsigned int propertyCount{0};
872
873 // Optional volts property
874 std::optional<double> volts{};
875 auto voltsIt = element.find("volts");
876 if (voltsIt != element.end())
877 {
878 volts = parseDouble(*voltsIt);
879 ++propertyCount;
880 }
881
882 // Required format property
883 const json& formatElement = getRequiredProperty(element, "format");
884 std::string formatString = parseString(formatElement);
885 if (formatString != "linear")
886 {
887 throw std::invalid_argument{"Invalid format value: " + formatString};
888 }
889 pmbus_utils::VoutDataFormat format = pmbus_utils::VoutDataFormat::linear;
890 ++propertyCount;
891
892 // Optional exponent property
893 std::optional<int8_t> exponent{};
894 auto exponentIt = element.find("exponent");
895 if (exponentIt != element.end())
896 {
897 exponent = parseInt8(*exponentIt);
898 ++propertyCount;
899 }
900
901 // Optional is_verified property
902 bool isVerified = false;
903 auto isVerifiedIt = element.find("is_verified");
904 if (isVerifiedIt != element.end())
905 {
906 isVerified = parseBoolean(*isVerifiedIt);
907 ++propertyCount;
908 }
909
910 // Verify no invalid properties exist
911 verifyPropertyCount(element, propertyCount);
912
913 return std::make_unique<PMBusWriteVoutCommandAction>(volts, format,
914 exponent, isVerified);
915}
916
Bob King2aafb1c2020-04-16 15:24:32 +0800917std::unique_ptr<PresenceDetection> parsePresenceDetection(const json& element)
918{
919 verifyIsObject(element);
920 unsigned int propertyCount{0};
921
922 // Optional comments property; value not stored
923 if (element.contains("comments"))
924 {
925 ++propertyCount;
926 }
927
928 // Required rule_id or actions property
929 std::vector<std::unique_ptr<Action>> actions{};
930 actions = parseRuleIDOrActionsProperty(element);
931 ++propertyCount;
932
933 // Verify no invalid properties exist
934 verifyPropertyCount(element, propertyCount);
935
936 return std::make_unique<PresenceDetection>(std::move(actions));
937}
938
Bob Kinga2f2a0d2020-04-09 13:32:14 +0800939std::unique_ptr<Rail> parseRail(const json& element)
940{
941 verifyIsObject(element);
942 unsigned int propertyCount{0};
943
944 // Optional comments property; value not stored
945 if (element.contains("comments"))
946 {
947 ++propertyCount;
948 }
949
950 // Required id property
951 const json& idElement = getRequiredProperty(element, "id");
952 std::string id = parseString(idElement);
953 ++propertyCount;
954
955 // Optional configuration property
956 std::unique_ptr<Configuration> configuration{};
957 auto configurationIt = element.find("configuration");
958 if (configurationIt != element.end())
959 {
960 configuration = parseConfiguration(*configurationIt);
961 ++propertyCount;
962 }
963
964 // Optional sensor_monitoring property
965 std::unique_ptr<SensorMonitoring> sensorMonitoring{};
966 auto sensorMonitoringIt = element.find("sensor_monitoring");
967 if (sensorMonitoringIt != element.end())
968 {
969 sensorMonitoring = parseSensorMonitoring(*sensorMonitoringIt);
970 ++propertyCount;
971 }
972
973 // Verify no invalid properties exist
974 verifyPropertyCount(element, propertyCount);
975
976 return std::make_unique<Rail>(id, std::move(configuration),
977 std::move(sensorMonitoring));
978}
979
Bob King9c36c5f2020-04-06 11:34:09 +0800980std::vector<std::unique_ptr<Rail>> parseRailArray(const json& element)
981{
982 verifyIsArray(element);
983 std::vector<std::unique_ptr<Rail>> rails;
Bob Kinga2f2a0d2020-04-09 13:32:14 +0800984 for (auto& railElement : element)
985 {
986 rails.emplace_back(parseRail(railElement));
987 }
Bob King9c36c5f2020-04-06 11:34:09 +0800988 return rails;
989}
990
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500991std::tuple<std::vector<std::unique_ptr<Rule>>,
992 std::vector<std::unique_ptr<Chassis>>>
993 parseRoot(const json& element)
994{
995 verifyIsObject(element);
996 unsigned int propertyCount{0};
997
998 // Optional comments property; value not stored
999 if (element.contains("comments"))
1000 {
1001 ++propertyCount;
1002 }
1003
1004 // Optional rules property
1005 std::vector<std::unique_ptr<Rule>> rules{};
1006 auto rulesIt = element.find("rules");
1007 if (rulesIt != element.end())
1008 {
1009 rules = parseRuleArray(*rulesIt);
1010 ++propertyCount;
1011 }
1012
1013 // Required chassis property
1014 const json& chassisElement = getRequiredProperty(element, "chassis");
1015 std::vector<std::unique_ptr<Chassis>> chassis =
1016 parseChassisArray(chassisElement);
1017 ++propertyCount;
1018
1019 // Verify no invalid properties exist
1020 verifyPropertyCount(element, propertyCount);
1021
1022 return std::make_tuple(std::move(rules), std::move(chassis));
1023}
1024
1025std::unique_ptr<Rule> parseRule(const json& element)
1026{
1027 verifyIsObject(element);
1028 unsigned int propertyCount{0};
1029
1030 // Optional comments property; value not stored
1031 if (element.contains("comments"))
1032 {
1033 ++propertyCount;
1034 }
1035
1036 // Required id property
1037 const json& idElement = getRequiredProperty(element, "id");
1038 std::string id = parseString(idElement);
1039 ++propertyCount;
1040
1041 // Required actions property
1042 const json& actionsElement = getRequiredProperty(element, "actions");
1043 std::vector<std::unique_ptr<Action>> actions =
1044 parseActionArray(actionsElement);
1045 ++propertyCount;
1046
1047 // Verify no invalid properties exist
1048 verifyPropertyCount(element, propertyCount);
1049
1050 return std::make_unique<Rule>(id, std::move(actions));
1051}
1052
1053std::vector<std::unique_ptr<Rule>> parseRuleArray(const json& element)
1054{
1055 verifyIsArray(element);
1056 std::vector<std::unique_ptr<Rule>> rules;
1057 for (auto& ruleElement : element)
1058 {
1059 rules.emplace_back(parseRule(ruleElement));
1060 }
1061 return rules;
1062}
1063
Bob King33e7eaa2020-04-01 18:09:34 +08001064std::vector<std::unique_ptr<Action>>
1065 parseRuleIDOrActionsProperty(const json& element)
1066{
1067 verifyIsObject(element);
1068 // Required rule_id or actions property
1069 std::vector<std::unique_ptr<Action>> actions{};
1070 auto ruleIDIt = element.find("rule_id");
1071 auto actionsIt = element.find("actions");
1072 if ((actionsIt == element.end()) && (ruleIDIt != element.end()))
1073 {
1074 std::string ruleID = parseString(*ruleIDIt);
1075 actions.emplace_back(std::make_unique<RunRuleAction>(ruleID));
1076 }
1077 else if ((actionsIt != element.end()) && (ruleIDIt == element.end()))
1078 {
1079 actions = parseActionArray(*actionsIt);
1080 }
1081 else
1082 {
1083 throw std::invalid_argument{"Invalid property combination: Must "
1084 "contain either rule_id or actions"};
1085 }
1086
1087 return actions;
1088}
1089
Bob King315b0b62020-04-03 21:47:58 +08001090std::unique_ptr<RunRuleAction> parseRunRule(const json& element)
1091{
1092 // String ruleID
1093 std::string ruleID = parseString(element);
1094
1095 return std::make_unique<RunRuleAction>(ruleID);
1096}
1097
Bob King84614882020-04-30 13:13:48 +08001098pmbus_utils::SensorDataFormat parseSensorDataFormat(const json& element)
1099{
1100 if (!element.is_string())
1101 {
1102 throw std::invalid_argument{"Element is not a string"};
1103 }
1104 std::string value = element.get<std::string>();
1105 pmbus_utils::SensorDataFormat format{};
1106
1107 if (value == "linear_11")
1108 {
1109 format = pmbus_utils::SensorDataFormat::linear_11;
1110 }
1111 else if (value == "linear_16")
1112 {
1113 format = pmbus_utils::SensorDataFormat::linear_16;
1114 }
1115 else
1116 {
1117 throw std::invalid_argument{"Element is not a sensor data format"};
1118 }
1119
1120 return format;
1121}
1122
Bob Kinga2f2a0d2020-04-09 13:32:14 +08001123std::unique_ptr<SensorMonitoring> parseSensorMonitoring(const json& element)
1124{
1125 verifyIsObject(element);
1126 unsigned int propertyCount{0};
1127
1128 // Optional comments property; value not stored
1129 if (element.contains("comments"))
1130 {
1131 ++propertyCount;
1132 }
1133
1134 // Required rule_id or actions property
1135 std::vector<std::unique_ptr<Action>> actions{};
1136 actions = parseRuleIDOrActionsProperty(element);
1137 ++propertyCount;
1138
1139 // Verify no invalid properties exist
1140 verifyPropertyCount(element, propertyCount);
1141
1142 return std::make_unique<SensorMonitoring>(std::move(actions));
1143}
1144
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001145SensorType parseSensorType(const json& element)
Bob King84614882020-04-30 13:13:48 +08001146{
Shawn McCarneyb70370b2021-09-07 12:07:40 -05001147 std::string value = parseString(element);
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001148 SensorType type{};
Bob King84614882020-04-30 13:13:48 +08001149
1150 if (value == "iout")
1151 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001152 type = SensorType::iout;
Bob King84614882020-04-30 13:13:48 +08001153 }
1154 else if (value == "iout_peak")
1155 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001156 type = SensorType::iout_peak;
Bob King84614882020-04-30 13:13:48 +08001157 }
1158 else if (value == "iout_valley")
1159 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001160 type = SensorType::iout_valley;
Bob King84614882020-04-30 13:13:48 +08001161 }
1162 else if (value == "pout")
1163 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001164 type = SensorType::pout;
Bob King84614882020-04-30 13:13:48 +08001165 }
1166 else if (value == "temperature")
1167 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001168 type = SensorType::temperature;
Bob King84614882020-04-30 13:13:48 +08001169 }
1170 else if (value == "temperature_peak")
1171 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001172 type = SensorType::temperature_peak;
Bob King84614882020-04-30 13:13:48 +08001173 }
1174 else if (value == "vout")
1175 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001176 type = SensorType::vout;
Bob King84614882020-04-30 13:13:48 +08001177 }
1178 else if (value == "vout_peak")
1179 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001180 type = SensorType::vout_peak;
Bob King84614882020-04-30 13:13:48 +08001181 }
1182 else if (value == "vout_valley")
1183 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001184 type = SensorType::vout_valley;
Bob King84614882020-04-30 13:13:48 +08001185 }
1186 else
1187 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001188 throw std::invalid_argument{"Element is not a sensor type"};
Bob King84614882020-04-30 13:13:48 +08001189 }
1190
1191 return type;
1192}
1193
Bob King18a68502020-04-17 14:19:56 +08001194std::unique_ptr<SetDeviceAction> parseSetDevice(const json& element)
1195{
1196 // String deviceID
1197 std::string deviceID = parseString(element);
1198
1199 return std::make_unique<SetDeviceAction>(deviceID);
1200}
1201
Bob King84614882020-04-30 13:13:48 +08001202pmbus_utils::VoutDataFormat parseVoutDataFormat(const json& element)
1203{
1204 if (!element.is_string())
1205 {
1206 throw std::invalid_argument{"Element is not a string"};
1207 }
1208 std::string value = element.get<std::string>();
1209 pmbus_utils::VoutDataFormat format{};
1210
1211 if (value == "linear")
1212 {
1213 format = pmbus_utils::VoutDataFormat::linear;
1214 }
1215 else if (value == "vid")
1216 {
1217 format = pmbus_utils::VoutDataFormat::vid;
1218 }
1219 else if (value == "direct")
1220 {
1221 format = pmbus_utils::VoutDataFormat::direct;
1222 }
1223 else if (value == "ieee")
1224 {
1225 format = pmbus_utils::VoutDataFormat::ieee;
1226 }
1227 else
1228 {
1229 throw std::invalid_argument{"Element is not a vout data format"};
1230 }
1231
1232 return format;
1233}
1234
Shawn McCarney0e8c68a2020-03-27 01:44:48 -05001235} // namespace internal
1236
1237} // namespace phosphor::power::regulators::config_file_parser