blob: 6527b5f405823716369a5a6942dbf3e318291fad [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 McCarneycb3f6a62021-04-30 10:54:30 -0500216 // Optional inventory_path property. Will be required in future.
217 std::string inventoryPath{"/xyz/openbmc_project/inventory/system/chassis"};
218 auto inventoryPathIt = element.find("inventory_path");
219 if (inventoryPathIt != element.end())
220 {
221 inventoryPath = parseInventoryPath(*inventoryPathIt);
222 ++propertyCount;
223 }
224
Bob King0e701132020-04-03 21:50:31 +0800225 // Optional devices property
226 std::vector<std::unique_ptr<Device>> devices{};
227 auto devicesIt = element.find("devices");
228 if (devicesIt != element.end())
229 {
230 devices = parseDeviceArray(*devicesIt);
231 ++propertyCount;
232 }
233
234 // Verify no invalid properties exist
235 verifyPropertyCount(element, propertyCount);
236
Shawn McCarneycb3f6a62021-04-30 10:54:30 -0500237 return std::make_unique<Chassis>(number, inventoryPath, std::move(devices));
Bob King0e701132020-04-03 21:50:31 +0800238}
239
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500240std::vector<std::unique_ptr<Chassis>> parseChassisArray(const json& element)
241{
242 verifyIsArray(element);
243 std::vector<std::unique_ptr<Chassis>> chassis;
Bob King0e701132020-04-03 21:50:31 +0800244 for (auto& chassisElement : element)
245 {
246 chassis.emplace_back(parseChassis(chassisElement));
247 }
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500248 return chassis;
249}
250
Bob Kingb267b7e2020-04-22 14:42:39 +0800251std::unique_ptr<ComparePresenceAction> parseComparePresence(const json& element)
252{
253 verifyIsObject(element);
254 unsigned int propertyCount{0};
255
256 // Required fru property
257 const json& fruElement = getRequiredProperty(element, "fru");
Bob Kinga76898f2020-10-13 15:08:33 +0800258 std::string fru = parseInventoryPath(fruElement);
Bob Kingb267b7e2020-04-22 14:42:39 +0800259 ++propertyCount;
260
261 // Required value property
262 const json& valueElement = getRequiredProperty(element, "value");
263 bool value = parseBoolean(valueElement);
264 ++propertyCount;
265
266 // Verify no invalid properties exist
267 verifyPropertyCount(element, propertyCount);
268
269 return std::make_unique<ComparePresenceAction>(fru, value);
270}
271
Bob Kingf2134322020-04-27 14:14:56 +0800272std::unique_ptr<CompareVPDAction> parseCompareVPD(const json& element)
273{
274 verifyIsObject(element);
275 unsigned int propertyCount{0};
276
277 // Required fru property
278 const json& fruElement = getRequiredProperty(element, "fru");
Bob Kinga76898f2020-10-13 15:08:33 +0800279 std::string fru = parseInventoryPath(fruElement);
Bob Kingf2134322020-04-27 14:14:56 +0800280 ++propertyCount;
281
282 // Required keyword property
283 const json& keywordElement = getRequiredProperty(element, "keyword");
284 std::string keyword = parseString(keywordElement);
285 ++propertyCount;
286
Matt Spinleraacc2aa2021-05-25 09:31:35 -0600287 // Either value or byte_values required property
288 auto valueIt = element.find("value");
289 std::vector<uint8_t> value{};
290 auto byteValuesIt = element.find("byte_values");
291 if ((valueIt != element.end()) && (byteValuesIt == element.end()))
292 {
293 std::string stringValue = parseString(*valueIt);
294 value.insert(value.begin(), stringValue.begin(), stringValue.end());
295 ++propertyCount;
296 }
297 else if ((valueIt == element.end()) && (byteValuesIt != element.end()))
298 {
299 value = parseHexByteArray(*byteValuesIt);
300 ++propertyCount;
301 }
302 else
303 {
304 throw std::invalid_argument{
305 "Invalid property: Must contain either value or byte_values"};
306 }
Bob Kingf2134322020-04-27 14:14:56 +0800307
308 // Verify no invalid properties exist
309 verifyPropertyCount(element, propertyCount);
310
311 return std::make_unique<CompareVPDAction>(fru, keyword, value);
312}
313
Bob King33e7eaa2020-04-01 18:09:34 +0800314std::unique_ptr<Configuration> parseConfiguration(const json& element)
315{
316 verifyIsObject(element);
317 unsigned int propertyCount{0};
318
319 // Optional comments property; value not stored
320 if (element.contains("comments"))
321 {
322 ++propertyCount;
323 }
324
325 // Optional volts property
326 std::optional<double> volts{};
327 auto voltsIt = element.find("volts");
328 if (voltsIt != element.end())
329 {
330 volts = parseDouble(*voltsIt);
331 ++propertyCount;
332 }
333
334 // Required rule_id or actions property
335 std::vector<std::unique_ptr<Action>> actions{};
336 actions = parseRuleIDOrActionsProperty(element);
337 ++propertyCount;
338
339 // Verify no invalid properties exist
340 verifyPropertyCount(element, propertyCount);
341
342 return std::make_unique<Configuration>(volts, std::move(actions));
343}
344
Bob King9c36c5f2020-04-06 11:34:09 +0800345std::unique_ptr<Device> parseDevice(const json& element)
346{
347 verifyIsObject(element);
348 unsigned int propertyCount{0};
349
350 // Optional comments property; value not stored
351 if (element.contains("comments"))
352 {
353 ++propertyCount;
354 }
355
356 // Required id property
357 const json& idElement = getRequiredProperty(element, "id");
358 std::string id = parseString(idElement);
359 ++propertyCount;
360
361 // Required is_regulator property
362 const json& isRegulatorElement =
363 getRequiredProperty(element, "is_regulator");
364 bool isRegulator = parseBoolean(isRegulatorElement);
365 ++propertyCount;
366
367 // Required fru property
368 const json& fruElement = getRequiredProperty(element, "fru");
Bob Kinga76898f2020-10-13 15:08:33 +0800369 std::string fru = parseInventoryPath(fruElement);
Bob King9c36c5f2020-04-06 11:34:09 +0800370 ++propertyCount;
371
372 // Required i2c_interface property
373 const json& i2cInterfaceElement =
374 getRequiredProperty(element, "i2c_interface");
375 std::unique_ptr<i2c::I2CInterface> i2cInterface =
376 parseI2CInterface(i2cInterfaceElement);
377 ++propertyCount;
378
379 // Optional presence_detection property
Bob King9c36c5f2020-04-06 11:34:09 +0800380 std::unique_ptr<PresenceDetection> presenceDetection{};
Bob King2aafb1c2020-04-16 15:24:32 +0800381 auto presenceDetectionIt = element.find("presence_detection");
382 if (presenceDetectionIt != element.end())
383 {
384 presenceDetection = parsePresenceDetection(*presenceDetectionIt);
385 ++propertyCount;
386 }
Bob King9c36c5f2020-04-06 11:34:09 +0800387
388 // Optional configuration property
Bob King9c36c5f2020-04-06 11:34:09 +0800389 std::unique_ptr<Configuration> configuration{};
Bob King33e7eaa2020-04-01 18:09:34 +0800390 auto configurationIt = element.find("configuration");
391 if (configurationIt != element.end())
392 {
393 configuration = parseConfiguration(*configurationIt);
394 ++propertyCount;
395 }
Bob King9c36c5f2020-04-06 11:34:09 +0800396
397 // Optional rails property
398 std::vector<std::unique_ptr<Rail>> rails{};
399 auto railsIt = element.find("rails");
400 if (railsIt != element.end())
401 {
402 if (!isRegulator)
403 {
404 throw std::invalid_argument{
405 "Invalid rails property when is_regulator is false"};
406 }
407 rails = parseRailArray(*railsIt);
408 ++propertyCount;
409 }
410
411 // Verify no invalid properties exist
412 verifyPropertyCount(element, propertyCount);
413
414 return std::make_unique<Device>(id, isRegulator, fru,
415 std::move(i2cInterface),
416 std::move(presenceDetection),
417 std::move(configuration), std::move(rails));
418}
419
Bob King0e701132020-04-03 21:50:31 +0800420std::vector<std::unique_ptr<Device>> parseDeviceArray(const json& element)
421{
422 verifyIsArray(element);
423 std::vector<std::unique_ptr<Device>> devices;
Bob King9c36c5f2020-04-06 11:34:09 +0800424 for (auto& deviceElement : element)
425 {
426 devices.emplace_back(parseDevice(deviceElement));
427 }
Bob King0e701132020-04-03 21:50:31 +0800428 return devices;
429}
430
Bob Kingbafcb862020-03-31 16:39:00 +0800431std::vector<uint8_t> parseHexByteArray(const json& element)
432{
433 verifyIsArray(element);
434 std::vector<uint8_t> values;
435 for (auto& valueElement : element)
436 {
437 values.emplace_back(parseHexByte(valueElement));
438 }
439 return values;
440}
441
Shawn McCarney91f87a52021-09-07 09:59:57 -0500442std::unique_ptr<I2CCaptureBytesAction> parseI2CCaptureBytes(const json& element)
443{
444 verifyIsObject(element);
445 unsigned int propertyCount{0};
446
447 // Required register property
448 const json& regElement = getRequiredProperty(element, "register");
449 uint8_t reg = parseHexByte(regElement);
450 ++propertyCount;
451
452 // Required count property
453 const json& countElement = getRequiredProperty(element, "count");
454 uint8_t count = parseUint8(countElement);
455 if (count < 1)
456 {
457 throw std::invalid_argument{"Invalid byte count: Must be > 0"};
458 }
459 ++propertyCount;
460
461 // Verify no invalid properties exist
462 verifyPropertyCount(element, propertyCount);
463
464 return std::make_unique<I2CCaptureBytesAction>(reg, count);
465}
466
Bob Kingf09bfe02020-04-13 17:21:15 +0800467std::unique_ptr<I2CCompareBitAction> parseI2CCompareBit(const json& element)
468{
469 verifyIsObject(element);
470 unsigned int propertyCount{0};
471
472 // Required register property
473 const json& regElement = getRequiredProperty(element, "register");
474 uint8_t reg = parseHexByte(regElement);
475 ++propertyCount;
476
477 // Required position property
478 const json& positionElement = getRequiredProperty(element, "position");
479 uint8_t position = parseBitPosition(positionElement);
480 ++propertyCount;
481
482 // Required value property
483 const json& valueElement = getRequiredProperty(element, "value");
484 uint8_t value = parseBitValue(valueElement);
485 ++propertyCount;
486
487 // Verify no invalid properties exist
488 verifyPropertyCount(element, propertyCount);
489
490 return std::make_unique<I2CCompareBitAction>(reg, position, value);
491}
492
493std::unique_ptr<I2CCompareByteAction> parseI2CCompareByte(const json& element)
494{
495 verifyIsObject(element);
496 unsigned int propertyCount{0};
497
498 // Required register property
499 const json& regElement = getRequiredProperty(element, "register");
500 uint8_t reg = parseHexByte(regElement);
501 ++propertyCount;
502
503 // Required value property
504 const json& valueElement = getRequiredProperty(element, "value");
505 uint8_t value = parseHexByte(valueElement);
506 ++propertyCount;
507
508 // Optional mask property
509 uint8_t mask = 0xff;
510 auto maskIt = element.find("mask");
511 if (maskIt != element.end())
512 {
513 mask = parseHexByte(*maskIt);
514 ++propertyCount;
515 }
516
517 // Verify no invalid properties exist
518 verifyPropertyCount(element, propertyCount);
519
520 return std::make_unique<I2CCompareByteAction>(reg, value, mask);
521}
522
523std::unique_ptr<I2CCompareBytesAction> parseI2CCompareBytes(const json& element)
524{
525 verifyIsObject(element);
526 unsigned int propertyCount{0};
527
528 // Required register property
529 const json& regElement = getRequiredProperty(element, "register");
530 uint8_t reg = parseHexByte(regElement);
531 ++propertyCount;
532
533 // Required values property
534 const json& valueElement = getRequiredProperty(element, "values");
535 std::vector<uint8_t> values = parseHexByteArray(valueElement);
536 ++propertyCount;
537
538 // Optional masks property
539 std::vector<uint8_t> masks{};
540 auto masksIt = element.find("masks");
541 if (masksIt != element.end())
542 {
543 masks = parseHexByteArray(*masksIt);
544 ++propertyCount;
545 }
546
547 // Verify masks array (if specified) was same size as values array
548 if ((!masks.empty()) && (masks.size() != values.size()))
549 {
550 throw std::invalid_argument{"Invalid number of elements in masks"};
551 }
552
553 // Verify no invalid properties exist
554 verifyPropertyCount(element, propertyCount);
555
556 if (masks.empty())
557 {
558 return std::make_unique<I2CCompareBytesAction>(reg, values);
559 }
560 return std::make_unique<I2CCompareBytesAction>(reg, values, masks);
561}
562
Bob King9c36c5f2020-04-06 11:34:09 +0800563std::unique_ptr<i2c::I2CInterface> parseI2CInterface(const json& element)
564{
565 verifyIsObject(element);
566 unsigned int propertyCount{0};
567
568 // Required bus property
569 const json& busElement = getRequiredProperty(element, "bus");
570 uint8_t bus = parseUint8(busElement);
571 ++propertyCount;
572
573 // Required address property
574 const json& addressElement = getRequiredProperty(element, "address");
575 uint8_t address = parseHexByte(addressElement);
576 ++propertyCount;
577
578 verifyPropertyCount(element, propertyCount);
579 return i2c::create(bus, address, i2c::I2CInterface::InitialState::CLOSED);
580}
581
Bob Kingf617f892020-03-30 19:03:35 +0800582std::unique_ptr<I2CWriteBitAction> parseI2CWriteBit(const json& element)
583{
584 verifyIsObject(element);
585 unsigned int propertyCount{0};
586
587 // Required register property
588 const json& regElement = getRequiredProperty(element, "register");
Bob Kingbafcb862020-03-31 16:39:00 +0800589 uint8_t reg = parseHexByte(regElement);
Bob Kingf617f892020-03-30 19:03:35 +0800590 ++propertyCount;
591
592 // Required position property
593 const json& positionElement = getRequiredProperty(element, "position");
594 uint8_t position = parseBitPosition(positionElement);
595 ++propertyCount;
596
597 // Required value property
598 const json& valueElement = getRequiredProperty(element, "value");
599 uint8_t value = parseBitValue(valueElement);
600 ++propertyCount;
601
602 // Verify no invalid properties exist
603 verifyPropertyCount(element, propertyCount);
604
605 return std::make_unique<I2CWriteBitAction>(reg, position, value);
606}
607
Bob King87ff9d72020-03-31 14:02:55 +0800608std::unique_ptr<I2CWriteByteAction> parseI2CWriteByte(const json& element)
609{
610 verifyIsObject(element);
611 unsigned int propertyCount{0};
612
613 // Required register property
614 const json& regElement = getRequiredProperty(element, "register");
Bob Kingbafcb862020-03-31 16:39:00 +0800615 uint8_t reg = parseHexByte(regElement);
Bob King87ff9d72020-03-31 14:02:55 +0800616 ++propertyCount;
617
618 // Required value property
619 const json& valueElement = getRequiredProperty(element, "value");
Bob Kingbafcb862020-03-31 16:39:00 +0800620 uint8_t value = parseHexByte(valueElement);
Bob King87ff9d72020-03-31 14:02:55 +0800621 ++propertyCount;
622
623 // Optional mask property
624 uint8_t mask = 0xff;
625 auto maskIt = element.find("mask");
626 if (maskIt != element.end())
627 {
Bob Kingbafcb862020-03-31 16:39:00 +0800628 mask = parseHexByte(*maskIt);
Bob King87ff9d72020-03-31 14:02:55 +0800629 ++propertyCount;
630 }
631
632 // Verify no invalid properties exist
633 verifyPropertyCount(element, propertyCount);
634
635 return std::make_unique<I2CWriteByteAction>(reg, value, mask);
636}
637
Bob Kingbafcb862020-03-31 16:39:00 +0800638std::unique_ptr<I2CWriteBytesAction> parseI2CWriteBytes(const json& element)
639{
640 verifyIsObject(element);
641 unsigned int propertyCount{0};
642
643 // Required register property
644 const json& regElement = getRequiredProperty(element, "register");
645 uint8_t reg = parseHexByte(regElement);
646 ++propertyCount;
647
648 // Required values property
649 const json& valueElement = getRequiredProperty(element, "values");
650 std::vector<uint8_t> values = parseHexByteArray(valueElement);
651 ++propertyCount;
652
653 // Optional masks property
654 std::vector<uint8_t> masks{};
655 auto masksIt = element.find("masks");
656 if (masksIt != element.end())
657 {
658 masks = parseHexByteArray(*masksIt);
659 ++propertyCount;
660 }
661
662 // Verify masks array (if specified) was same size as values array
663 if ((!masks.empty()) && (masks.size() != values.size()))
664 {
665 throw std::invalid_argument{"Invalid number of elements in masks"};
666 }
667
668 // Verify no invalid properties exist
669 verifyPropertyCount(element, propertyCount);
670
671 if (masks.empty())
672 {
673 return std::make_unique<I2CWriteBytesAction>(reg, values);
674 }
675 return std::make_unique<I2CWriteBytesAction>(reg, values, masks);
676}
677
Bob King93a89d72020-04-15 15:11:11 +0800678std::unique_ptr<IfAction> parseIf(const json& element)
679{
680 verifyIsObject(element);
681 unsigned int propertyCount{0};
682
683 // Required condition property
684 const json& conditionElement = getRequiredProperty(element, "condition");
685 std::unique_ptr<Action> conditionAction = parseAction(conditionElement);
686 ++propertyCount;
687
688 // Required then property
689 const json& thenElement = getRequiredProperty(element, "then");
690 std::vector<std::unique_ptr<Action>> thenActions =
691 parseActionArray(thenElement);
692 ++propertyCount;
693
694 // Optional else property
695 std::vector<std::unique_ptr<Action>> elseActions{};
696 auto elseIt = element.find("else");
697 if (elseIt != element.end())
698 {
699 elseActions = parseActionArray(*elseIt);
700 ++propertyCount;
701 }
702
703 // Verify no invalid properties exist
704 verifyPropertyCount(element, propertyCount);
705
706 return std::make_unique<IfAction>(std::move(conditionAction),
707 std::move(thenActions),
708 std::move(elseActions));
709}
710
Bob Kinga76898f2020-10-13 15:08:33 +0800711std::string parseInventoryPath(const json& element)
712{
713 std::string inventoryPath = parseString(element);
714 std::string absPath = "/xyz/openbmc_project/inventory";
715 if (inventoryPath.front() != '/')
716 {
717 absPath += '/';
718 }
719 absPath += inventoryPath;
720 return absPath;
721}
722
Shawn McCarney11157852021-09-07 14:04:36 -0500723std::unique_ptr<LogPhaseFaultAction> parseLogPhaseFault(const json& element)
724{
725 verifyIsObject(element);
726 unsigned int propertyCount{0};
727
728 // Required type property
729 const json& typeElement = getRequiredProperty(element, "type");
730 PhaseFaultType type = parsePhaseFaultType(typeElement);
731 ++propertyCount;
732
733 // Verify no invalid properties exist
734 verifyPropertyCount(element, propertyCount);
735
736 return std::make_unique<LogPhaseFaultAction>(type);
737}
738
Bob Kingf1b58dc2020-04-14 14:53:10 +0800739std::unique_ptr<NotAction> parseNot(const json& element)
740{
741 // Required action to execute
742 std::unique_ptr<Action> action = parseAction(element);
743
744 return std::make_unique<NotAction>(std::move(action));
745}
746
Bob King0b51a9b2020-04-15 13:24:18 +0800747std::unique_ptr<OrAction> parseOr(const json& element)
748{
749 verifyIsArray(element);
750
751 // Verify if array size less than 2
752 if (element.size() < 2)
753 {
754 throw std::invalid_argument{"Array must contain two or more actions"};
755 }
756 // Array of two or more actions
757 std::vector<std::unique_ptr<Action>> actions = parseActionArray(element);
758
759 return std::make_unique<OrAction>(std::move(actions));
760}
761
Shawn McCarneyb70370b2021-09-07 12:07:40 -0500762PhaseFaultType parsePhaseFaultType(const json& element)
763{
764 std::string value = parseString(element);
765 PhaseFaultType type{};
766
767 if (value == "n")
768 {
769 type = PhaseFaultType::n;
770 }
771 else if (value == "n+1")
772 {
773 type = PhaseFaultType::n_plus_1;
774 }
775 else
776 {
777 throw std::invalid_argument{"Element is not a phase fault type"};
778 }
779
780 return type;
781}
782
Bob King84614882020-04-30 13:13:48 +0800783std::unique_ptr<PMBusReadSensorAction> parsePMBusReadSensor(const json& element)
784{
785 verifyIsObject(element);
786 unsigned int propertyCount{0};
787
788 // Required type property
789 const json& typeElement = getRequiredProperty(element, "type");
Shawn McCarney2f9e14f2021-04-29 02:45:18 -0500790 SensorType type = parseSensorType(typeElement);
Bob King84614882020-04-30 13:13:48 +0800791 ++propertyCount;
792
793 // Required command property
794 const json& commandElement = getRequiredProperty(element, "command");
795 uint8_t command = parseHexByte(commandElement);
796 ++propertyCount;
797
798 // Required format property
799 const json& formatElement = getRequiredProperty(element, "format");
800 pmbus_utils::SensorDataFormat format = parseSensorDataFormat(formatElement);
801 ++propertyCount;
802
803 // Optional exponent property
804 std::optional<int8_t> exponent{};
805 auto exponentIt = element.find("exponent");
806 if (exponentIt != element.end())
807 {
808 exponent = parseInt8(*exponentIt);
809 ++propertyCount;
810 }
811
812 // Verify no invalid properties exist
813 verifyPropertyCount(element, propertyCount);
814
815 return std::make_unique<PMBusReadSensorAction>(type, command, format,
816 exponent);
817}
818
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500819std::unique_ptr<PMBusWriteVoutCommandAction>
820 parsePMBusWriteVoutCommand(const json& element)
821{
822 verifyIsObject(element);
823 unsigned int propertyCount{0};
824
825 // Optional volts property
826 std::optional<double> volts{};
827 auto voltsIt = element.find("volts");
828 if (voltsIt != element.end())
829 {
830 volts = parseDouble(*voltsIt);
831 ++propertyCount;
832 }
833
834 // Required format property
835 const json& formatElement = getRequiredProperty(element, "format");
836 std::string formatString = parseString(formatElement);
837 if (formatString != "linear")
838 {
839 throw std::invalid_argument{"Invalid format value: " + formatString};
840 }
841 pmbus_utils::VoutDataFormat format = pmbus_utils::VoutDataFormat::linear;
842 ++propertyCount;
843
844 // Optional exponent property
845 std::optional<int8_t> exponent{};
846 auto exponentIt = element.find("exponent");
847 if (exponentIt != element.end())
848 {
849 exponent = parseInt8(*exponentIt);
850 ++propertyCount;
851 }
852
853 // Optional is_verified property
854 bool isVerified = false;
855 auto isVerifiedIt = element.find("is_verified");
856 if (isVerifiedIt != element.end())
857 {
858 isVerified = parseBoolean(*isVerifiedIt);
859 ++propertyCount;
860 }
861
862 // Verify no invalid properties exist
863 verifyPropertyCount(element, propertyCount);
864
865 return std::make_unique<PMBusWriteVoutCommandAction>(volts, format,
866 exponent, isVerified);
867}
868
Bob King2aafb1c2020-04-16 15:24:32 +0800869std::unique_ptr<PresenceDetection> parsePresenceDetection(const json& element)
870{
871 verifyIsObject(element);
872 unsigned int propertyCount{0};
873
874 // Optional comments property; value not stored
875 if (element.contains("comments"))
876 {
877 ++propertyCount;
878 }
879
880 // Required rule_id or actions property
881 std::vector<std::unique_ptr<Action>> actions{};
882 actions = parseRuleIDOrActionsProperty(element);
883 ++propertyCount;
884
885 // Verify no invalid properties exist
886 verifyPropertyCount(element, propertyCount);
887
888 return std::make_unique<PresenceDetection>(std::move(actions));
889}
890
Bob Kinga2f2a0d2020-04-09 13:32:14 +0800891std::unique_ptr<Rail> parseRail(const json& element)
892{
893 verifyIsObject(element);
894 unsigned int propertyCount{0};
895
896 // Optional comments property; value not stored
897 if (element.contains("comments"))
898 {
899 ++propertyCount;
900 }
901
902 // Required id property
903 const json& idElement = getRequiredProperty(element, "id");
904 std::string id = parseString(idElement);
905 ++propertyCount;
906
907 // Optional configuration property
908 std::unique_ptr<Configuration> configuration{};
909 auto configurationIt = element.find("configuration");
910 if (configurationIt != element.end())
911 {
912 configuration = parseConfiguration(*configurationIt);
913 ++propertyCount;
914 }
915
916 // Optional sensor_monitoring property
917 std::unique_ptr<SensorMonitoring> sensorMonitoring{};
918 auto sensorMonitoringIt = element.find("sensor_monitoring");
919 if (sensorMonitoringIt != element.end())
920 {
921 sensorMonitoring = parseSensorMonitoring(*sensorMonitoringIt);
922 ++propertyCount;
923 }
924
925 // Verify no invalid properties exist
926 verifyPropertyCount(element, propertyCount);
927
928 return std::make_unique<Rail>(id, std::move(configuration),
929 std::move(sensorMonitoring));
930}
931
Bob King9c36c5f2020-04-06 11:34:09 +0800932std::vector<std::unique_ptr<Rail>> parseRailArray(const json& element)
933{
934 verifyIsArray(element);
935 std::vector<std::unique_ptr<Rail>> rails;
Bob Kinga2f2a0d2020-04-09 13:32:14 +0800936 for (auto& railElement : element)
937 {
938 rails.emplace_back(parseRail(railElement));
939 }
Bob King9c36c5f2020-04-06 11:34:09 +0800940 return rails;
941}
942
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500943std::tuple<std::vector<std::unique_ptr<Rule>>,
944 std::vector<std::unique_ptr<Chassis>>>
945 parseRoot(const json& element)
946{
947 verifyIsObject(element);
948 unsigned int propertyCount{0};
949
950 // Optional comments property; value not stored
951 if (element.contains("comments"))
952 {
953 ++propertyCount;
954 }
955
956 // Optional rules property
957 std::vector<std::unique_ptr<Rule>> rules{};
958 auto rulesIt = element.find("rules");
959 if (rulesIt != element.end())
960 {
961 rules = parseRuleArray(*rulesIt);
962 ++propertyCount;
963 }
964
965 // Required chassis property
966 const json& chassisElement = getRequiredProperty(element, "chassis");
967 std::vector<std::unique_ptr<Chassis>> chassis =
968 parseChassisArray(chassisElement);
969 ++propertyCount;
970
971 // Verify no invalid properties exist
972 verifyPropertyCount(element, propertyCount);
973
974 return std::make_tuple(std::move(rules), std::move(chassis));
975}
976
977std::unique_ptr<Rule> parseRule(const json& element)
978{
979 verifyIsObject(element);
980 unsigned int propertyCount{0};
981
982 // Optional comments property; value not stored
983 if (element.contains("comments"))
984 {
985 ++propertyCount;
986 }
987
988 // Required id property
989 const json& idElement = getRequiredProperty(element, "id");
990 std::string id = parseString(idElement);
991 ++propertyCount;
992
993 // Required actions property
994 const json& actionsElement = getRequiredProperty(element, "actions");
995 std::vector<std::unique_ptr<Action>> actions =
996 parseActionArray(actionsElement);
997 ++propertyCount;
998
999 // Verify no invalid properties exist
1000 verifyPropertyCount(element, propertyCount);
1001
1002 return std::make_unique<Rule>(id, std::move(actions));
1003}
1004
1005std::vector<std::unique_ptr<Rule>> parseRuleArray(const json& element)
1006{
1007 verifyIsArray(element);
1008 std::vector<std::unique_ptr<Rule>> rules;
1009 for (auto& ruleElement : element)
1010 {
1011 rules.emplace_back(parseRule(ruleElement));
1012 }
1013 return rules;
1014}
1015
Bob King33e7eaa2020-04-01 18:09:34 +08001016std::vector<std::unique_ptr<Action>>
1017 parseRuleIDOrActionsProperty(const json& element)
1018{
1019 verifyIsObject(element);
1020 // Required rule_id or actions property
1021 std::vector<std::unique_ptr<Action>> actions{};
1022 auto ruleIDIt = element.find("rule_id");
1023 auto actionsIt = element.find("actions");
1024 if ((actionsIt == element.end()) && (ruleIDIt != element.end()))
1025 {
1026 std::string ruleID = parseString(*ruleIDIt);
1027 actions.emplace_back(std::make_unique<RunRuleAction>(ruleID));
1028 }
1029 else if ((actionsIt != element.end()) && (ruleIDIt == element.end()))
1030 {
1031 actions = parseActionArray(*actionsIt);
1032 }
1033 else
1034 {
1035 throw std::invalid_argument{"Invalid property combination: Must "
1036 "contain either rule_id or actions"};
1037 }
1038
1039 return actions;
1040}
1041
Bob King315b0b62020-04-03 21:47:58 +08001042std::unique_ptr<RunRuleAction> parseRunRule(const json& element)
1043{
1044 // String ruleID
1045 std::string ruleID = parseString(element);
1046
1047 return std::make_unique<RunRuleAction>(ruleID);
1048}
1049
Bob King84614882020-04-30 13:13:48 +08001050pmbus_utils::SensorDataFormat parseSensorDataFormat(const json& element)
1051{
1052 if (!element.is_string())
1053 {
1054 throw std::invalid_argument{"Element is not a string"};
1055 }
1056 std::string value = element.get<std::string>();
1057 pmbus_utils::SensorDataFormat format{};
1058
1059 if (value == "linear_11")
1060 {
1061 format = pmbus_utils::SensorDataFormat::linear_11;
1062 }
1063 else if (value == "linear_16")
1064 {
1065 format = pmbus_utils::SensorDataFormat::linear_16;
1066 }
1067 else
1068 {
1069 throw std::invalid_argument{"Element is not a sensor data format"};
1070 }
1071
1072 return format;
1073}
1074
Bob Kinga2f2a0d2020-04-09 13:32:14 +08001075std::unique_ptr<SensorMonitoring> parseSensorMonitoring(const json& element)
1076{
1077 verifyIsObject(element);
1078 unsigned int propertyCount{0};
1079
1080 // Optional comments property; value not stored
1081 if (element.contains("comments"))
1082 {
1083 ++propertyCount;
1084 }
1085
1086 // Required rule_id or actions property
1087 std::vector<std::unique_ptr<Action>> actions{};
1088 actions = parseRuleIDOrActionsProperty(element);
1089 ++propertyCount;
1090
1091 // Verify no invalid properties exist
1092 verifyPropertyCount(element, propertyCount);
1093
1094 return std::make_unique<SensorMonitoring>(std::move(actions));
1095}
1096
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001097SensorType parseSensorType(const json& element)
Bob King84614882020-04-30 13:13:48 +08001098{
Shawn McCarneyb70370b2021-09-07 12:07:40 -05001099 std::string value = parseString(element);
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001100 SensorType type{};
Bob King84614882020-04-30 13:13:48 +08001101
1102 if (value == "iout")
1103 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001104 type = SensorType::iout;
Bob King84614882020-04-30 13:13:48 +08001105 }
1106 else if (value == "iout_peak")
1107 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001108 type = SensorType::iout_peak;
Bob King84614882020-04-30 13:13:48 +08001109 }
1110 else if (value == "iout_valley")
1111 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001112 type = SensorType::iout_valley;
Bob King84614882020-04-30 13:13:48 +08001113 }
1114 else if (value == "pout")
1115 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001116 type = SensorType::pout;
Bob King84614882020-04-30 13:13:48 +08001117 }
1118 else if (value == "temperature")
1119 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001120 type = SensorType::temperature;
Bob King84614882020-04-30 13:13:48 +08001121 }
1122 else if (value == "temperature_peak")
1123 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001124 type = SensorType::temperature_peak;
Bob King84614882020-04-30 13:13:48 +08001125 }
1126 else if (value == "vout")
1127 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001128 type = SensorType::vout;
Bob King84614882020-04-30 13:13:48 +08001129 }
1130 else if (value == "vout_peak")
1131 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001132 type = SensorType::vout_peak;
Bob King84614882020-04-30 13:13:48 +08001133 }
1134 else if (value == "vout_valley")
1135 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001136 type = SensorType::vout_valley;
Bob King84614882020-04-30 13:13:48 +08001137 }
1138 else
1139 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001140 throw std::invalid_argument{"Element is not a sensor type"};
Bob King84614882020-04-30 13:13:48 +08001141 }
1142
1143 return type;
1144}
1145
Bob King18a68502020-04-17 14:19:56 +08001146std::unique_ptr<SetDeviceAction> parseSetDevice(const json& element)
1147{
1148 // String deviceID
1149 std::string deviceID = parseString(element);
1150
1151 return std::make_unique<SetDeviceAction>(deviceID);
1152}
1153
Bob King84614882020-04-30 13:13:48 +08001154pmbus_utils::VoutDataFormat parseVoutDataFormat(const json& element)
1155{
1156 if (!element.is_string())
1157 {
1158 throw std::invalid_argument{"Element is not a string"};
1159 }
1160 std::string value = element.get<std::string>();
1161 pmbus_utils::VoutDataFormat format{};
1162
1163 if (value == "linear")
1164 {
1165 format = pmbus_utils::VoutDataFormat::linear;
1166 }
1167 else if (value == "vid")
1168 {
1169 format = pmbus_utils::VoutDataFormat::vid;
1170 }
1171 else if (value == "direct")
1172 {
1173 format = pmbus_utils::VoutDataFormat::direct;
1174 }
1175 else if (value == "ieee")
1176 {
1177 format = pmbus_utils::VoutDataFormat::ieee;
1178 }
1179 else
1180 {
1181 throw std::invalid_argument{"Element is not a vout data format"};
1182 }
1183
1184 return format;
1185}
1186
Shawn McCarney0e8c68a2020-03-27 01:44:48 -05001187} // namespace internal
1188
1189} // namespace phosphor::power::regulators::config_file_parser