blob: 5330f590298245daacd8677254f233ba577576ec [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 }
123 else if (element.contains("not"))
124 {
Bob Kingf1b58dc2020-04-14 14:53:10 +0800125 action = parseNot(element["not"]);
126 ++propertyCount;
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500127 }
128 else if (element.contains("or"))
129 {
Bob King0b51a9b2020-04-15 13:24:18 +0800130 action = parseOr(element["or"]);
131 ++propertyCount;
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500132 }
133 else if (element.contains("pmbus_read_sensor"))
134 {
Bob King84614882020-04-30 13:13:48 +0800135 action = parsePMBusReadSensor(element["pmbus_read_sensor"]);
136 ++propertyCount;
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500137 }
138 else if (element.contains("pmbus_write_vout_command"))
139 {
140 action =
141 parsePMBusWriteVoutCommand(element["pmbus_write_vout_command"]);
142 ++propertyCount;
143 }
144 else if (element.contains("run_rule"))
145 {
Bob King315b0b62020-04-03 21:47:58 +0800146 action = parseRunRule(element["run_rule"]);
147 ++propertyCount;
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500148 }
149 else if (element.contains("set_device"))
150 {
Bob King18a68502020-04-17 14:19:56 +0800151 action = parseSetDevice(element["set_device"]);
152 ++propertyCount;
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500153 }
154 else
155 {
156 throw std::invalid_argument{"Required action type property missing"};
157 }
158
159 // Verify no invalid properties exist
160 verifyPropertyCount(element, propertyCount);
161
162 return action;
163}
164
165std::vector<std::unique_ptr<Action>> parseActionArray(const json& element)
166{
167 verifyIsArray(element);
168 std::vector<std::unique_ptr<Action>> actions;
169 for (auto& actionElement : element)
170 {
171 actions.emplace_back(parseAction(actionElement));
172 }
173 return actions;
174}
175
Bob King3a787542020-04-14 13:45:01 +0800176std::unique_ptr<AndAction> parseAnd(const json& element)
177{
178 verifyIsArray(element);
179
180 // Verify if array size less than 2
181 if (element.size() < 2)
182 {
183 throw std::invalid_argument{"Array must contain two or more actions"};
184 }
185 // Array of two or more actions
186 std::vector<std::unique_ptr<Action>> actions = parseActionArray(element);
187
188 return std::make_unique<AndAction>(std::move(actions));
189}
190
Bob King0e701132020-04-03 21:50:31 +0800191std::unique_ptr<Chassis> parseChassis(const json& element)
192{
193 verifyIsObject(element);
194 unsigned int propertyCount{0};
195
196 // Optional comments property; value not stored
197 if (element.contains("comments"))
198 {
199 ++propertyCount;
200 }
201
202 // Required number property
203 const json& numberElement = getRequiredProperty(element, "number");
204 unsigned int number = parseUnsignedInteger(numberElement);
205 if (number < 1)
206 {
207 throw std::invalid_argument{"Invalid chassis number: Must be > 0"};
208 }
209 ++propertyCount;
210
Shawn McCarneycb3f6a62021-04-30 10:54:30 -0500211 // Optional inventory_path property. Will be required in future.
212 std::string inventoryPath{"/xyz/openbmc_project/inventory/system/chassis"};
213 auto inventoryPathIt = element.find("inventory_path");
214 if (inventoryPathIt != element.end())
215 {
216 inventoryPath = parseInventoryPath(*inventoryPathIt);
217 ++propertyCount;
218 }
219
Bob King0e701132020-04-03 21:50:31 +0800220 // Optional devices property
221 std::vector<std::unique_ptr<Device>> devices{};
222 auto devicesIt = element.find("devices");
223 if (devicesIt != element.end())
224 {
225 devices = parseDeviceArray(*devicesIt);
226 ++propertyCount;
227 }
228
229 // Verify no invalid properties exist
230 verifyPropertyCount(element, propertyCount);
231
Shawn McCarneycb3f6a62021-04-30 10:54:30 -0500232 return std::make_unique<Chassis>(number, inventoryPath, std::move(devices));
Bob King0e701132020-04-03 21:50:31 +0800233}
234
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500235std::vector<std::unique_ptr<Chassis>> parseChassisArray(const json& element)
236{
237 verifyIsArray(element);
238 std::vector<std::unique_ptr<Chassis>> chassis;
Bob King0e701132020-04-03 21:50:31 +0800239 for (auto& chassisElement : element)
240 {
241 chassis.emplace_back(parseChassis(chassisElement));
242 }
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500243 return chassis;
244}
245
Bob Kingb267b7e2020-04-22 14:42:39 +0800246std::unique_ptr<ComparePresenceAction> parseComparePresence(const json& element)
247{
248 verifyIsObject(element);
249 unsigned int propertyCount{0};
250
251 // Required fru property
252 const json& fruElement = getRequiredProperty(element, "fru");
Bob Kinga76898f2020-10-13 15:08:33 +0800253 std::string fru = parseInventoryPath(fruElement);
Bob Kingb267b7e2020-04-22 14:42:39 +0800254 ++propertyCount;
255
256 // Required value property
257 const json& valueElement = getRequiredProperty(element, "value");
258 bool value = parseBoolean(valueElement);
259 ++propertyCount;
260
261 // Verify no invalid properties exist
262 verifyPropertyCount(element, propertyCount);
263
264 return std::make_unique<ComparePresenceAction>(fru, value);
265}
266
Bob Kingf2134322020-04-27 14:14:56 +0800267std::unique_ptr<CompareVPDAction> parseCompareVPD(const json& element)
268{
269 verifyIsObject(element);
270 unsigned int propertyCount{0};
271
272 // Required fru property
273 const json& fruElement = getRequiredProperty(element, "fru");
Bob Kinga76898f2020-10-13 15:08:33 +0800274 std::string fru = parseInventoryPath(fruElement);
Bob Kingf2134322020-04-27 14:14:56 +0800275 ++propertyCount;
276
277 // Required keyword property
278 const json& keywordElement = getRequiredProperty(element, "keyword");
279 std::string keyword = parseString(keywordElement);
280 ++propertyCount;
281
Matt Spinleraacc2aa2021-05-25 09:31:35 -0600282 // Either value or byte_values required property
283 auto valueIt = element.find("value");
284 std::vector<uint8_t> value{};
285 auto byteValuesIt = element.find("byte_values");
286 if ((valueIt != element.end()) && (byteValuesIt == element.end()))
287 {
288 std::string stringValue = parseString(*valueIt);
289 value.insert(value.begin(), stringValue.begin(), stringValue.end());
290 ++propertyCount;
291 }
292 else if ((valueIt == element.end()) && (byteValuesIt != element.end()))
293 {
294 value = parseHexByteArray(*byteValuesIt);
295 ++propertyCount;
296 }
297 else
298 {
299 throw std::invalid_argument{
300 "Invalid property: Must contain either value or byte_values"};
301 }
Bob Kingf2134322020-04-27 14:14:56 +0800302
303 // Verify no invalid properties exist
304 verifyPropertyCount(element, propertyCount);
305
306 return std::make_unique<CompareVPDAction>(fru, keyword, value);
307}
308
Bob King33e7eaa2020-04-01 18:09:34 +0800309std::unique_ptr<Configuration> parseConfiguration(const json& element)
310{
311 verifyIsObject(element);
312 unsigned int propertyCount{0};
313
314 // Optional comments property; value not stored
315 if (element.contains("comments"))
316 {
317 ++propertyCount;
318 }
319
320 // Optional volts property
321 std::optional<double> volts{};
322 auto voltsIt = element.find("volts");
323 if (voltsIt != element.end())
324 {
325 volts = parseDouble(*voltsIt);
326 ++propertyCount;
327 }
328
329 // Required rule_id or actions property
330 std::vector<std::unique_ptr<Action>> actions{};
331 actions = parseRuleIDOrActionsProperty(element);
332 ++propertyCount;
333
334 // Verify no invalid properties exist
335 verifyPropertyCount(element, propertyCount);
336
337 return std::make_unique<Configuration>(volts, std::move(actions));
338}
339
Bob King9c36c5f2020-04-06 11:34:09 +0800340std::unique_ptr<Device> parseDevice(const json& element)
341{
342 verifyIsObject(element);
343 unsigned int propertyCount{0};
344
345 // Optional comments property; value not stored
346 if (element.contains("comments"))
347 {
348 ++propertyCount;
349 }
350
351 // Required id property
352 const json& idElement = getRequiredProperty(element, "id");
353 std::string id = parseString(idElement);
354 ++propertyCount;
355
356 // Required is_regulator property
357 const json& isRegulatorElement =
358 getRequiredProperty(element, "is_regulator");
359 bool isRegulator = parseBoolean(isRegulatorElement);
360 ++propertyCount;
361
362 // Required fru property
363 const json& fruElement = getRequiredProperty(element, "fru");
Bob Kinga76898f2020-10-13 15:08:33 +0800364 std::string fru = parseInventoryPath(fruElement);
Bob King9c36c5f2020-04-06 11:34:09 +0800365 ++propertyCount;
366
367 // Required i2c_interface property
368 const json& i2cInterfaceElement =
369 getRequiredProperty(element, "i2c_interface");
370 std::unique_ptr<i2c::I2CInterface> i2cInterface =
371 parseI2CInterface(i2cInterfaceElement);
372 ++propertyCount;
373
374 // Optional presence_detection property
Bob King9c36c5f2020-04-06 11:34:09 +0800375 std::unique_ptr<PresenceDetection> presenceDetection{};
Bob King2aafb1c2020-04-16 15:24:32 +0800376 auto presenceDetectionIt = element.find("presence_detection");
377 if (presenceDetectionIt != element.end())
378 {
379 presenceDetection = parsePresenceDetection(*presenceDetectionIt);
380 ++propertyCount;
381 }
Bob King9c36c5f2020-04-06 11:34:09 +0800382
383 // Optional configuration property
Bob King9c36c5f2020-04-06 11:34:09 +0800384 std::unique_ptr<Configuration> configuration{};
Bob King33e7eaa2020-04-01 18:09:34 +0800385 auto configurationIt = element.find("configuration");
386 if (configurationIt != element.end())
387 {
388 configuration = parseConfiguration(*configurationIt);
389 ++propertyCount;
390 }
Bob King9c36c5f2020-04-06 11:34:09 +0800391
392 // Optional rails property
393 std::vector<std::unique_ptr<Rail>> rails{};
394 auto railsIt = element.find("rails");
395 if (railsIt != element.end())
396 {
397 if (!isRegulator)
398 {
399 throw std::invalid_argument{
400 "Invalid rails property when is_regulator is false"};
401 }
402 rails = parseRailArray(*railsIt);
403 ++propertyCount;
404 }
405
406 // Verify no invalid properties exist
407 verifyPropertyCount(element, propertyCount);
408
409 return std::make_unique<Device>(id, isRegulator, fru,
410 std::move(i2cInterface),
411 std::move(presenceDetection),
412 std::move(configuration), std::move(rails));
413}
414
Bob King0e701132020-04-03 21:50:31 +0800415std::vector<std::unique_ptr<Device>> parseDeviceArray(const json& element)
416{
417 verifyIsArray(element);
418 std::vector<std::unique_ptr<Device>> devices;
Bob King9c36c5f2020-04-06 11:34:09 +0800419 for (auto& deviceElement : element)
420 {
421 devices.emplace_back(parseDevice(deviceElement));
422 }
Bob King0e701132020-04-03 21:50:31 +0800423 return devices;
424}
425
Bob Kingbafcb862020-03-31 16:39:00 +0800426std::vector<uint8_t> parseHexByteArray(const json& element)
427{
428 verifyIsArray(element);
429 std::vector<uint8_t> values;
430 for (auto& valueElement : element)
431 {
432 values.emplace_back(parseHexByte(valueElement));
433 }
434 return values;
435}
436
Shawn McCarney91f87a52021-09-07 09:59:57 -0500437std::unique_ptr<I2CCaptureBytesAction> parseI2CCaptureBytes(const json& element)
438{
439 verifyIsObject(element);
440 unsigned int propertyCount{0};
441
442 // Required register property
443 const json& regElement = getRequiredProperty(element, "register");
444 uint8_t reg = parseHexByte(regElement);
445 ++propertyCount;
446
447 // Required count property
448 const json& countElement = getRequiredProperty(element, "count");
449 uint8_t count = parseUint8(countElement);
450 if (count < 1)
451 {
452 throw std::invalid_argument{"Invalid byte count: Must be > 0"};
453 }
454 ++propertyCount;
455
456 // Verify no invalid properties exist
457 verifyPropertyCount(element, propertyCount);
458
459 return std::make_unique<I2CCaptureBytesAction>(reg, count);
460}
461
Bob Kingf09bfe02020-04-13 17:21:15 +0800462std::unique_ptr<I2CCompareBitAction> parseI2CCompareBit(const json& element)
463{
464 verifyIsObject(element);
465 unsigned int propertyCount{0};
466
467 // Required register property
468 const json& regElement = getRequiredProperty(element, "register");
469 uint8_t reg = parseHexByte(regElement);
470 ++propertyCount;
471
472 // Required position property
473 const json& positionElement = getRequiredProperty(element, "position");
474 uint8_t position = parseBitPosition(positionElement);
475 ++propertyCount;
476
477 // Required value property
478 const json& valueElement = getRequiredProperty(element, "value");
479 uint8_t value = parseBitValue(valueElement);
480 ++propertyCount;
481
482 // Verify no invalid properties exist
483 verifyPropertyCount(element, propertyCount);
484
485 return std::make_unique<I2CCompareBitAction>(reg, position, value);
486}
487
488std::unique_ptr<I2CCompareByteAction> parseI2CCompareByte(const json& element)
489{
490 verifyIsObject(element);
491 unsigned int propertyCount{0};
492
493 // Required register property
494 const json& regElement = getRequiredProperty(element, "register");
495 uint8_t reg = parseHexByte(regElement);
496 ++propertyCount;
497
498 // Required value property
499 const json& valueElement = getRequiredProperty(element, "value");
500 uint8_t value = parseHexByte(valueElement);
501 ++propertyCount;
502
503 // Optional mask property
504 uint8_t mask = 0xff;
505 auto maskIt = element.find("mask");
506 if (maskIt != element.end())
507 {
508 mask = parseHexByte(*maskIt);
509 ++propertyCount;
510 }
511
512 // Verify no invalid properties exist
513 verifyPropertyCount(element, propertyCount);
514
515 return std::make_unique<I2CCompareByteAction>(reg, value, mask);
516}
517
518std::unique_ptr<I2CCompareBytesAction> parseI2CCompareBytes(const json& element)
519{
520 verifyIsObject(element);
521 unsigned int propertyCount{0};
522
523 // Required register property
524 const json& regElement = getRequiredProperty(element, "register");
525 uint8_t reg = parseHexByte(regElement);
526 ++propertyCount;
527
528 // Required values property
529 const json& valueElement = getRequiredProperty(element, "values");
530 std::vector<uint8_t> values = parseHexByteArray(valueElement);
531 ++propertyCount;
532
533 // Optional masks property
534 std::vector<uint8_t> masks{};
535 auto masksIt = element.find("masks");
536 if (masksIt != element.end())
537 {
538 masks = parseHexByteArray(*masksIt);
539 ++propertyCount;
540 }
541
542 // Verify masks array (if specified) was same size as values array
543 if ((!masks.empty()) && (masks.size() != values.size()))
544 {
545 throw std::invalid_argument{"Invalid number of elements in masks"};
546 }
547
548 // Verify no invalid properties exist
549 verifyPropertyCount(element, propertyCount);
550
551 if (masks.empty())
552 {
553 return std::make_unique<I2CCompareBytesAction>(reg, values);
554 }
555 return std::make_unique<I2CCompareBytesAction>(reg, values, masks);
556}
557
Bob King9c36c5f2020-04-06 11:34:09 +0800558std::unique_ptr<i2c::I2CInterface> parseI2CInterface(const json& element)
559{
560 verifyIsObject(element);
561 unsigned int propertyCount{0};
562
563 // Required bus property
564 const json& busElement = getRequiredProperty(element, "bus");
565 uint8_t bus = parseUint8(busElement);
566 ++propertyCount;
567
568 // Required address property
569 const json& addressElement = getRequiredProperty(element, "address");
570 uint8_t address = parseHexByte(addressElement);
571 ++propertyCount;
572
573 verifyPropertyCount(element, propertyCount);
574 return i2c::create(bus, address, i2c::I2CInterface::InitialState::CLOSED);
575}
576
Bob Kingf617f892020-03-30 19:03:35 +0800577std::unique_ptr<I2CWriteBitAction> parseI2CWriteBit(const json& element)
578{
579 verifyIsObject(element);
580 unsigned int propertyCount{0};
581
582 // Required register property
583 const json& regElement = getRequiredProperty(element, "register");
Bob Kingbafcb862020-03-31 16:39:00 +0800584 uint8_t reg = parseHexByte(regElement);
Bob Kingf617f892020-03-30 19:03:35 +0800585 ++propertyCount;
586
587 // Required position property
588 const json& positionElement = getRequiredProperty(element, "position");
589 uint8_t position = parseBitPosition(positionElement);
590 ++propertyCount;
591
592 // Required value property
593 const json& valueElement = getRequiredProperty(element, "value");
594 uint8_t value = parseBitValue(valueElement);
595 ++propertyCount;
596
597 // Verify no invalid properties exist
598 verifyPropertyCount(element, propertyCount);
599
600 return std::make_unique<I2CWriteBitAction>(reg, position, value);
601}
602
Bob King87ff9d72020-03-31 14:02:55 +0800603std::unique_ptr<I2CWriteByteAction> parseI2CWriteByte(const json& element)
604{
605 verifyIsObject(element);
606 unsigned int propertyCount{0};
607
608 // Required register property
609 const json& regElement = getRequiredProperty(element, "register");
Bob Kingbafcb862020-03-31 16:39:00 +0800610 uint8_t reg = parseHexByte(regElement);
Bob King87ff9d72020-03-31 14:02:55 +0800611 ++propertyCount;
612
613 // Required value property
614 const json& valueElement = getRequiredProperty(element, "value");
Bob Kingbafcb862020-03-31 16:39:00 +0800615 uint8_t value = parseHexByte(valueElement);
Bob King87ff9d72020-03-31 14:02:55 +0800616 ++propertyCount;
617
618 // Optional mask property
619 uint8_t mask = 0xff;
620 auto maskIt = element.find("mask");
621 if (maskIt != element.end())
622 {
Bob Kingbafcb862020-03-31 16:39:00 +0800623 mask = parseHexByte(*maskIt);
Bob King87ff9d72020-03-31 14:02:55 +0800624 ++propertyCount;
625 }
626
627 // Verify no invalid properties exist
628 verifyPropertyCount(element, propertyCount);
629
630 return std::make_unique<I2CWriteByteAction>(reg, value, mask);
631}
632
Bob Kingbafcb862020-03-31 16:39:00 +0800633std::unique_ptr<I2CWriteBytesAction> parseI2CWriteBytes(const json& element)
634{
635 verifyIsObject(element);
636 unsigned int propertyCount{0};
637
638 // Required register property
639 const json& regElement = getRequiredProperty(element, "register");
640 uint8_t reg = parseHexByte(regElement);
641 ++propertyCount;
642
643 // Required values property
644 const json& valueElement = getRequiredProperty(element, "values");
645 std::vector<uint8_t> values = parseHexByteArray(valueElement);
646 ++propertyCount;
647
648 // Optional masks property
649 std::vector<uint8_t> masks{};
650 auto masksIt = element.find("masks");
651 if (masksIt != element.end())
652 {
653 masks = parseHexByteArray(*masksIt);
654 ++propertyCount;
655 }
656
657 // Verify masks array (if specified) was same size as values array
658 if ((!masks.empty()) && (masks.size() != values.size()))
659 {
660 throw std::invalid_argument{"Invalid number of elements in masks"};
661 }
662
663 // Verify no invalid properties exist
664 verifyPropertyCount(element, propertyCount);
665
666 if (masks.empty())
667 {
668 return std::make_unique<I2CWriteBytesAction>(reg, values);
669 }
670 return std::make_unique<I2CWriteBytesAction>(reg, values, masks);
671}
672
Bob King93a89d72020-04-15 15:11:11 +0800673std::unique_ptr<IfAction> parseIf(const json& element)
674{
675 verifyIsObject(element);
676 unsigned int propertyCount{0};
677
678 // Required condition property
679 const json& conditionElement = getRequiredProperty(element, "condition");
680 std::unique_ptr<Action> conditionAction = parseAction(conditionElement);
681 ++propertyCount;
682
683 // Required then property
684 const json& thenElement = getRequiredProperty(element, "then");
685 std::vector<std::unique_ptr<Action>> thenActions =
686 parseActionArray(thenElement);
687 ++propertyCount;
688
689 // Optional else property
690 std::vector<std::unique_ptr<Action>> elseActions{};
691 auto elseIt = element.find("else");
692 if (elseIt != element.end())
693 {
694 elseActions = parseActionArray(*elseIt);
695 ++propertyCount;
696 }
697
698 // Verify no invalid properties exist
699 verifyPropertyCount(element, propertyCount);
700
701 return std::make_unique<IfAction>(std::move(conditionAction),
702 std::move(thenActions),
703 std::move(elseActions));
704}
705
Bob Kinga76898f2020-10-13 15:08:33 +0800706std::string parseInventoryPath(const json& element)
707{
708 std::string inventoryPath = parseString(element);
709 std::string absPath = "/xyz/openbmc_project/inventory";
710 if (inventoryPath.front() != '/')
711 {
712 absPath += '/';
713 }
714 absPath += inventoryPath;
715 return absPath;
716}
717
Bob Kingf1b58dc2020-04-14 14:53:10 +0800718std::unique_ptr<NotAction> parseNot(const json& element)
719{
720 // Required action to execute
721 std::unique_ptr<Action> action = parseAction(element);
722
723 return std::make_unique<NotAction>(std::move(action));
724}
725
Bob King0b51a9b2020-04-15 13:24:18 +0800726std::unique_ptr<OrAction> parseOr(const json& element)
727{
728 verifyIsArray(element);
729
730 // Verify if array size less than 2
731 if (element.size() < 2)
732 {
733 throw std::invalid_argument{"Array must contain two or more actions"};
734 }
735 // Array of two or more actions
736 std::vector<std::unique_ptr<Action>> actions = parseActionArray(element);
737
738 return std::make_unique<OrAction>(std::move(actions));
739}
740
Shawn McCarneyb70370b2021-09-07 12:07:40 -0500741PhaseFaultType parsePhaseFaultType(const json& element)
742{
743 std::string value = parseString(element);
744 PhaseFaultType type{};
745
746 if (value == "n")
747 {
748 type = PhaseFaultType::n;
749 }
750 else if (value == "n+1")
751 {
752 type = PhaseFaultType::n_plus_1;
753 }
754 else
755 {
756 throw std::invalid_argument{"Element is not a phase fault type"};
757 }
758
759 return type;
760}
761
Bob King84614882020-04-30 13:13:48 +0800762std::unique_ptr<PMBusReadSensorAction> parsePMBusReadSensor(const json& element)
763{
764 verifyIsObject(element);
765 unsigned int propertyCount{0};
766
767 // Required type property
768 const json& typeElement = getRequiredProperty(element, "type");
Shawn McCarney2f9e14f2021-04-29 02:45:18 -0500769 SensorType type = parseSensorType(typeElement);
Bob King84614882020-04-30 13:13:48 +0800770 ++propertyCount;
771
772 // Required command property
773 const json& commandElement = getRequiredProperty(element, "command");
774 uint8_t command = parseHexByte(commandElement);
775 ++propertyCount;
776
777 // Required format property
778 const json& formatElement = getRequiredProperty(element, "format");
779 pmbus_utils::SensorDataFormat format = parseSensorDataFormat(formatElement);
780 ++propertyCount;
781
782 // Optional exponent property
783 std::optional<int8_t> exponent{};
784 auto exponentIt = element.find("exponent");
785 if (exponentIt != element.end())
786 {
787 exponent = parseInt8(*exponentIt);
788 ++propertyCount;
789 }
790
791 // Verify no invalid properties exist
792 verifyPropertyCount(element, propertyCount);
793
794 return std::make_unique<PMBusReadSensorAction>(type, command, format,
795 exponent);
796}
797
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500798std::unique_ptr<PMBusWriteVoutCommandAction>
799 parsePMBusWriteVoutCommand(const json& element)
800{
801 verifyIsObject(element);
802 unsigned int propertyCount{0};
803
804 // Optional volts property
805 std::optional<double> volts{};
806 auto voltsIt = element.find("volts");
807 if (voltsIt != element.end())
808 {
809 volts = parseDouble(*voltsIt);
810 ++propertyCount;
811 }
812
813 // Required format property
814 const json& formatElement = getRequiredProperty(element, "format");
815 std::string formatString = parseString(formatElement);
816 if (formatString != "linear")
817 {
818 throw std::invalid_argument{"Invalid format value: " + formatString};
819 }
820 pmbus_utils::VoutDataFormat format = pmbus_utils::VoutDataFormat::linear;
821 ++propertyCount;
822
823 // Optional exponent property
824 std::optional<int8_t> exponent{};
825 auto exponentIt = element.find("exponent");
826 if (exponentIt != element.end())
827 {
828 exponent = parseInt8(*exponentIt);
829 ++propertyCount;
830 }
831
832 // Optional is_verified property
833 bool isVerified = false;
834 auto isVerifiedIt = element.find("is_verified");
835 if (isVerifiedIt != element.end())
836 {
837 isVerified = parseBoolean(*isVerifiedIt);
838 ++propertyCount;
839 }
840
841 // Verify no invalid properties exist
842 verifyPropertyCount(element, propertyCount);
843
844 return std::make_unique<PMBusWriteVoutCommandAction>(volts, format,
845 exponent, isVerified);
846}
847
Bob King2aafb1c2020-04-16 15:24:32 +0800848std::unique_ptr<PresenceDetection> parsePresenceDetection(const json& element)
849{
850 verifyIsObject(element);
851 unsigned int propertyCount{0};
852
853 // Optional comments property; value not stored
854 if (element.contains("comments"))
855 {
856 ++propertyCount;
857 }
858
859 // Required rule_id or actions property
860 std::vector<std::unique_ptr<Action>> actions{};
861 actions = parseRuleIDOrActionsProperty(element);
862 ++propertyCount;
863
864 // Verify no invalid properties exist
865 verifyPropertyCount(element, propertyCount);
866
867 return std::make_unique<PresenceDetection>(std::move(actions));
868}
869
Bob Kinga2f2a0d2020-04-09 13:32:14 +0800870std::unique_ptr<Rail> parseRail(const json& element)
871{
872 verifyIsObject(element);
873 unsigned int propertyCount{0};
874
875 // Optional comments property; value not stored
876 if (element.contains("comments"))
877 {
878 ++propertyCount;
879 }
880
881 // Required id property
882 const json& idElement = getRequiredProperty(element, "id");
883 std::string id = parseString(idElement);
884 ++propertyCount;
885
886 // Optional configuration property
887 std::unique_ptr<Configuration> configuration{};
888 auto configurationIt = element.find("configuration");
889 if (configurationIt != element.end())
890 {
891 configuration = parseConfiguration(*configurationIt);
892 ++propertyCount;
893 }
894
895 // Optional sensor_monitoring property
896 std::unique_ptr<SensorMonitoring> sensorMonitoring{};
897 auto sensorMonitoringIt = element.find("sensor_monitoring");
898 if (sensorMonitoringIt != element.end())
899 {
900 sensorMonitoring = parseSensorMonitoring(*sensorMonitoringIt);
901 ++propertyCount;
902 }
903
904 // Verify no invalid properties exist
905 verifyPropertyCount(element, propertyCount);
906
907 return std::make_unique<Rail>(id, std::move(configuration),
908 std::move(sensorMonitoring));
909}
910
Bob King9c36c5f2020-04-06 11:34:09 +0800911std::vector<std::unique_ptr<Rail>> parseRailArray(const json& element)
912{
913 verifyIsArray(element);
914 std::vector<std::unique_ptr<Rail>> rails;
Bob Kinga2f2a0d2020-04-09 13:32:14 +0800915 for (auto& railElement : element)
916 {
917 rails.emplace_back(parseRail(railElement));
918 }
Bob King9c36c5f2020-04-06 11:34:09 +0800919 return rails;
920}
921
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500922std::tuple<std::vector<std::unique_ptr<Rule>>,
923 std::vector<std::unique_ptr<Chassis>>>
924 parseRoot(const json& element)
925{
926 verifyIsObject(element);
927 unsigned int propertyCount{0};
928
929 // Optional comments property; value not stored
930 if (element.contains("comments"))
931 {
932 ++propertyCount;
933 }
934
935 // Optional rules property
936 std::vector<std::unique_ptr<Rule>> rules{};
937 auto rulesIt = element.find("rules");
938 if (rulesIt != element.end())
939 {
940 rules = parseRuleArray(*rulesIt);
941 ++propertyCount;
942 }
943
944 // Required chassis property
945 const json& chassisElement = getRequiredProperty(element, "chassis");
946 std::vector<std::unique_ptr<Chassis>> chassis =
947 parseChassisArray(chassisElement);
948 ++propertyCount;
949
950 // Verify no invalid properties exist
951 verifyPropertyCount(element, propertyCount);
952
953 return std::make_tuple(std::move(rules), std::move(chassis));
954}
955
956std::unique_ptr<Rule> parseRule(const json& element)
957{
958 verifyIsObject(element);
959 unsigned int propertyCount{0};
960
961 // Optional comments property; value not stored
962 if (element.contains("comments"))
963 {
964 ++propertyCount;
965 }
966
967 // Required id property
968 const json& idElement = getRequiredProperty(element, "id");
969 std::string id = parseString(idElement);
970 ++propertyCount;
971
972 // Required actions property
973 const json& actionsElement = getRequiredProperty(element, "actions");
974 std::vector<std::unique_ptr<Action>> actions =
975 parseActionArray(actionsElement);
976 ++propertyCount;
977
978 // Verify no invalid properties exist
979 verifyPropertyCount(element, propertyCount);
980
981 return std::make_unique<Rule>(id, std::move(actions));
982}
983
984std::vector<std::unique_ptr<Rule>> parseRuleArray(const json& element)
985{
986 verifyIsArray(element);
987 std::vector<std::unique_ptr<Rule>> rules;
988 for (auto& ruleElement : element)
989 {
990 rules.emplace_back(parseRule(ruleElement));
991 }
992 return rules;
993}
994
Bob King33e7eaa2020-04-01 18:09:34 +0800995std::vector<std::unique_ptr<Action>>
996 parseRuleIDOrActionsProperty(const json& element)
997{
998 verifyIsObject(element);
999 // Required rule_id or actions property
1000 std::vector<std::unique_ptr<Action>> actions{};
1001 auto ruleIDIt = element.find("rule_id");
1002 auto actionsIt = element.find("actions");
1003 if ((actionsIt == element.end()) && (ruleIDIt != element.end()))
1004 {
1005 std::string ruleID = parseString(*ruleIDIt);
1006 actions.emplace_back(std::make_unique<RunRuleAction>(ruleID));
1007 }
1008 else if ((actionsIt != element.end()) && (ruleIDIt == element.end()))
1009 {
1010 actions = parseActionArray(*actionsIt);
1011 }
1012 else
1013 {
1014 throw std::invalid_argument{"Invalid property combination: Must "
1015 "contain either rule_id or actions"};
1016 }
1017
1018 return actions;
1019}
1020
Bob King315b0b62020-04-03 21:47:58 +08001021std::unique_ptr<RunRuleAction> parseRunRule(const json& element)
1022{
1023 // String ruleID
1024 std::string ruleID = parseString(element);
1025
1026 return std::make_unique<RunRuleAction>(ruleID);
1027}
1028
Bob King84614882020-04-30 13:13:48 +08001029pmbus_utils::SensorDataFormat parseSensorDataFormat(const json& element)
1030{
1031 if (!element.is_string())
1032 {
1033 throw std::invalid_argument{"Element is not a string"};
1034 }
1035 std::string value = element.get<std::string>();
1036 pmbus_utils::SensorDataFormat format{};
1037
1038 if (value == "linear_11")
1039 {
1040 format = pmbus_utils::SensorDataFormat::linear_11;
1041 }
1042 else if (value == "linear_16")
1043 {
1044 format = pmbus_utils::SensorDataFormat::linear_16;
1045 }
1046 else
1047 {
1048 throw std::invalid_argument{"Element is not a sensor data format"};
1049 }
1050
1051 return format;
1052}
1053
Bob Kinga2f2a0d2020-04-09 13:32:14 +08001054std::unique_ptr<SensorMonitoring> parseSensorMonitoring(const json& element)
1055{
1056 verifyIsObject(element);
1057 unsigned int propertyCount{0};
1058
1059 // Optional comments property; value not stored
1060 if (element.contains("comments"))
1061 {
1062 ++propertyCount;
1063 }
1064
1065 // Required rule_id or actions property
1066 std::vector<std::unique_ptr<Action>> actions{};
1067 actions = parseRuleIDOrActionsProperty(element);
1068 ++propertyCount;
1069
1070 // Verify no invalid properties exist
1071 verifyPropertyCount(element, propertyCount);
1072
1073 return std::make_unique<SensorMonitoring>(std::move(actions));
1074}
1075
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001076SensorType parseSensorType(const json& element)
Bob King84614882020-04-30 13:13:48 +08001077{
Shawn McCarneyb70370b2021-09-07 12:07:40 -05001078 std::string value = parseString(element);
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001079 SensorType type{};
Bob King84614882020-04-30 13:13:48 +08001080
1081 if (value == "iout")
1082 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001083 type = SensorType::iout;
Bob King84614882020-04-30 13:13:48 +08001084 }
1085 else if (value == "iout_peak")
1086 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001087 type = SensorType::iout_peak;
Bob King84614882020-04-30 13:13:48 +08001088 }
1089 else if (value == "iout_valley")
1090 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001091 type = SensorType::iout_valley;
Bob King84614882020-04-30 13:13:48 +08001092 }
1093 else if (value == "pout")
1094 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001095 type = SensorType::pout;
Bob King84614882020-04-30 13:13:48 +08001096 }
1097 else if (value == "temperature")
1098 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001099 type = SensorType::temperature;
Bob King84614882020-04-30 13:13:48 +08001100 }
1101 else if (value == "temperature_peak")
1102 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001103 type = SensorType::temperature_peak;
Bob King84614882020-04-30 13:13:48 +08001104 }
1105 else if (value == "vout")
1106 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001107 type = SensorType::vout;
Bob King84614882020-04-30 13:13:48 +08001108 }
1109 else if (value == "vout_peak")
1110 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001111 type = SensorType::vout_peak;
Bob King84614882020-04-30 13:13:48 +08001112 }
1113 else if (value == "vout_valley")
1114 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001115 type = SensorType::vout_valley;
Bob King84614882020-04-30 13:13:48 +08001116 }
1117 else
1118 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001119 throw std::invalid_argument{"Element is not a sensor type"};
Bob King84614882020-04-30 13:13:48 +08001120 }
1121
1122 return type;
1123}
1124
Bob King18a68502020-04-17 14:19:56 +08001125std::unique_ptr<SetDeviceAction> parseSetDevice(const json& element)
1126{
1127 // String deviceID
1128 std::string deviceID = parseString(element);
1129
1130 return std::make_unique<SetDeviceAction>(deviceID);
1131}
1132
Bob King84614882020-04-30 13:13:48 +08001133pmbus_utils::VoutDataFormat parseVoutDataFormat(const json& element)
1134{
1135 if (!element.is_string())
1136 {
1137 throw std::invalid_argument{"Element is not a string"};
1138 }
1139 std::string value = element.get<std::string>();
1140 pmbus_utils::VoutDataFormat format{};
1141
1142 if (value == "linear")
1143 {
1144 format = pmbus_utils::VoutDataFormat::linear;
1145 }
1146 else if (value == "vid")
1147 {
1148 format = pmbus_utils::VoutDataFormat::vid;
1149 }
1150 else if (value == "direct")
1151 {
1152 format = pmbus_utils::VoutDataFormat::direct;
1153 }
1154 else if (value == "ieee")
1155 {
1156 format = pmbus_utils::VoutDataFormat::ieee;
1157 }
1158 else
1159 {
1160 throw std::invalid_argument{"Element is not a vout data format"};
1161 }
1162
1163 return format;
1164}
1165
Shawn McCarney0e8c68a2020-03-27 01:44:48 -05001166} // namespace internal
1167
1168} // namespace phosphor::power::regulators::config_file_parser