blob: 430d490a907b203a4ff9a7d91fcf486fdd4497f8 [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 McCarney39eb08a2021-09-07 16:34:49 -0500762std::unique_ptr<PhaseFaultDetection>
763 parsePhaseFaultDetection(const json& element)
764{
765 verifyIsObject(element);
766 unsigned int propertyCount{0};
767
768 // Optional comments property; value not stored
769 if (element.contains("comments"))
770 {
771 ++propertyCount;
772 }
773
774 // Optional device_id property
775 std::string deviceID{};
776 auto deviceIDIt = element.find("device_id");
777 if (deviceIDIt != element.end())
778 {
779 deviceID = parseString(*deviceIDIt);
780 ++propertyCount;
781 }
782
783 // Required rule_id or actions property
784 std::vector<std::unique_ptr<Action>> actions{};
785 actions = parseRuleIDOrActionsProperty(element);
786 ++propertyCount;
787
788 // Verify no invalid properties exist
789 verifyPropertyCount(element, propertyCount);
790
791 return std::make_unique<PhaseFaultDetection>(std::move(actions), deviceID);
792}
793
Shawn McCarneyb70370b2021-09-07 12:07:40 -0500794PhaseFaultType parsePhaseFaultType(const json& element)
795{
796 std::string value = parseString(element);
797 PhaseFaultType type{};
798
799 if (value == "n")
800 {
801 type = PhaseFaultType::n;
802 }
803 else if (value == "n+1")
804 {
805 type = PhaseFaultType::n_plus_1;
806 }
807 else
808 {
809 throw std::invalid_argument{"Element is not a phase fault type"};
810 }
811
812 return type;
813}
814
Bob King84614882020-04-30 13:13:48 +0800815std::unique_ptr<PMBusReadSensorAction> parsePMBusReadSensor(const json& element)
816{
817 verifyIsObject(element);
818 unsigned int propertyCount{0};
819
820 // Required type property
821 const json& typeElement = getRequiredProperty(element, "type");
Shawn McCarney2f9e14f2021-04-29 02:45:18 -0500822 SensorType type = parseSensorType(typeElement);
Bob King84614882020-04-30 13:13:48 +0800823 ++propertyCount;
824
825 // Required command property
826 const json& commandElement = getRequiredProperty(element, "command");
827 uint8_t command = parseHexByte(commandElement);
828 ++propertyCount;
829
830 // Required format property
831 const json& formatElement = getRequiredProperty(element, "format");
832 pmbus_utils::SensorDataFormat format = parseSensorDataFormat(formatElement);
833 ++propertyCount;
834
835 // Optional exponent property
836 std::optional<int8_t> exponent{};
837 auto exponentIt = element.find("exponent");
838 if (exponentIt != element.end())
839 {
840 exponent = parseInt8(*exponentIt);
841 ++propertyCount;
842 }
843
844 // Verify no invalid properties exist
845 verifyPropertyCount(element, propertyCount);
846
847 return std::make_unique<PMBusReadSensorAction>(type, command, format,
848 exponent);
849}
850
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500851std::unique_ptr<PMBusWriteVoutCommandAction>
852 parsePMBusWriteVoutCommand(const json& element)
853{
854 verifyIsObject(element);
855 unsigned int propertyCount{0};
856
857 // Optional volts property
858 std::optional<double> volts{};
859 auto voltsIt = element.find("volts");
860 if (voltsIt != element.end())
861 {
862 volts = parseDouble(*voltsIt);
863 ++propertyCount;
864 }
865
866 // Required format property
867 const json& formatElement = getRequiredProperty(element, "format");
868 std::string formatString = parseString(formatElement);
869 if (formatString != "linear")
870 {
871 throw std::invalid_argument{"Invalid format value: " + formatString};
872 }
873 pmbus_utils::VoutDataFormat format = pmbus_utils::VoutDataFormat::linear;
874 ++propertyCount;
875
876 // Optional exponent property
877 std::optional<int8_t> exponent{};
878 auto exponentIt = element.find("exponent");
879 if (exponentIt != element.end())
880 {
881 exponent = parseInt8(*exponentIt);
882 ++propertyCount;
883 }
884
885 // Optional is_verified property
886 bool isVerified = false;
887 auto isVerifiedIt = element.find("is_verified");
888 if (isVerifiedIt != element.end())
889 {
890 isVerified = parseBoolean(*isVerifiedIt);
891 ++propertyCount;
892 }
893
894 // Verify no invalid properties exist
895 verifyPropertyCount(element, propertyCount);
896
897 return std::make_unique<PMBusWriteVoutCommandAction>(volts, format,
898 exponent, isVerified);
899}
900
Bob King2aafb1c2020-04-16 15:24:32 +0800901std::unique_ptr<PresenceDetection> parsePresenceDetection(const json& element)
902{
903 verifyIsObject(element);
904 unsigned int propertyCount{0};
905
906 // Optional comments property; value not stored
907 if (element.contains("comments"))
908 {
909 ++propertyCount;
910 }
911
912 // Required rule_id or actions property
913 std::vector<std::unique_ptr<Action>> actions{};
914 actions = parseRuleIDOrActionsProperty(element);
915 ++propertyCount;
916
917 // Verify no invalid properties exist
918 verifyPropertyCount(element, propertyCount);
919
920 return std::make_unique<PresenceDetection>(std::move(actions));
921}
922
Bob Kinga2f2a0d2020-04-09 13:32:14 +0800923std::unique_ptr<Rail> parseRail(const json& element)
924{
925 verifyIsObject(element);
926 unsigned int propertyCount{0};
927
928 // Optional comments property; value not stored
929 if (element.contains("comments"))
930 {
931 ++propertyCount;
932 }
933
934 // Required id property
935 const json& idElement = getRequiredProperty(element, "id");
936 std::string id = parseString(idElement);
937 ++propertyCount;
938
939 // Optional configuration property
940 std::unique_ptr<Configuration> configuration{};
941 auto configurationIt = element.find("configuration");
942 if (configurationIt != element.end())
943 {
944 configuration = parseConfiguration(*configurationIt);
945 ++propertyCount;
946 }
947
948 // Optional sensor_monitoring property
949 std::unique_ptr<SensorMonitoring> sensorMonitoring{};
950 auto sensorMonitoringIt = element.find("sensor_monitoring");
951 if (sensorMonitoringIt != element.end())
952 {
953 sensorMonitoring = parseSensorMonitoring(*sensorMonitoringIt);
954 ++propertyCount;
955 }
956
957 // Verify no invalid properties exist
958 verifyPropertyCount(element, propertyCount);
959
960 return std::make_unique<Rail>(id, std::move(configuration),
961 std::move(sensorMonitoring));
962}
963
Bob King9c36c5f2020-04-06 11:34:09 +0800964std::vector<std::unique_ptr<Rail>> parseRailArray(const json& element)
965{
966 verifyIsArray(element);
967 std::vector<std::unique_ptr<Rail>> rails;
Bob Kinga2f2a0d2020-04-09 13:32:14 +0800968 for (auto& railElement : element)
969 {
970 rails.emplace_back(parseRail(railElement));
971 }
Bob King9c36c5f2020-04-06 11:34:09 +0800972 return rails;
973}
974
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500975std::tuple<std::vector<std::unique_ptr<Rule>>,
976 std::vector<std::unique_ptr<Chassis>>>
977 parseRoot(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 // Optional rules property
989 std::vector<std::unique_ptr<Rule>> rules{};
990 auto rulesIt = element.find("rules");
991 if (rulesIt != element.end())
992 {
993 rules = parseRuleArray(*rulesIt);
994 ++propertyCount;
995 }
996
997 // Required chassis property
998 const json& chassisElement = getRequiredProperty(element, "chassis");
999 std::vector<std::unique_ptr<Chassis>> chassis =
1000 parseChassisArray(chassisElement);
1001 ++propertyCount;
1002
1003 // Verify no invalid properties exist
1004 verifyPropertyCount(element, propertyCount);
1005
1006 return std::make_tuple(std::move(rules), std::move(chassis));
1007}
1008
1009std::unique_ptr<Rule> parseRule(const json& element)
1010{
1011 verifyIsObject(element);
1012 unsigned int propertyCount{0};
1013
1014 // Optional comments property; value not stored
1015 if (element.contains("comments"))
1016 {
1017 ++propertyCount;
1018 }
1019
1020 // Required id property
1021 const json& idElement = getRequiredProperty(element, "id");
1022 std::string id = parseString(idElement);
1023 ++propertyCount;
1024
1025 // Required actions property
1026 const json& actionsElement = getRequiredProperty(element, "actions");
1027 std::vector<std::unique_ptr<Action>> actions =
1028 parseActionArray(actionsElement);
1029 ++propertyCount;
1030
1031 // Verify no invalid properties exist
1032 verifyPropertyCount(element, propertyCount);
1033
1034 return std::make_unique<Rule>(id, std::move(actions));
1035}
1036
1037std::vector<std::unique_ptr<Rule>> parseRuleArray(const json& element)
1038{
1039 verifyIsArray(element);
1040 std::vector<std::unique_ptr<Rule>> rules;
1041 for (auto& ruleElement : element)
1042 {
1043 rules.emplace_back(parseRule(ruleElement));
1044 }
1045 return rules;
1046}
1047
Bob King33e7eaa2020-04-01 18:09:34 +08001048std::vector<std::unique_ptr<Action>>
1049 parseRuleIDOrActionsProperty(const json& element)
1050{
1051 verifyIsObject(element);
1052 // Required rule_id or actions property
1053 std::vector<std::unique_ptr<Action>> actions{};
1054 auto ruleIDIt = element.find("rule_id");
1055 auto actionsIt = element.find("actions");
1056 if ((actionsIt == element.end()) && (ruleIDIt != element.end()))
1057 {
1058 std::string ruleID = parseString(*ruleIDIt);
1059 actions.emplace_back(std::make_unique<RunRuleAction>(ruleID));
1060 }
1061 else if ((actionsIt != element.end()) && (ruleIDIt == element.end()))
1062 {
1063 actions = parseActionArray(*actionsIt);
1064 }
1065 else
1066 {
1067 throw std::invalid_argument{"Invalid property combination: Must "
1068 "contain either rule_id or actions"};
1069 }
1070
1071 return actions;
1072}
1073
Bob King315b0b62020-04-03 21:47:58 +08001074std::unique_ptr<RunRuleAction> parseRunRule(const json& element)
1075{
1076 // String ruleID
1077 std::string ruleID = parseString(element);
1078
1079 return std::make_unique<RunRuleAction>(ruleID);
1080}
1081
Bob King84614882020-04-30 13:13:48 +08001082pmbus_utils::SensorDataFormat parseSensorDataFormat(const json& element)
1083{
1084 if (!element.is_string())
1085 {
1086 throw std::invalid_argument{"Element is not a string"};
1087 }
1088 std::string value = element.get<std::string>();
1089 pmbus_utils::SensorDataFormat format{};
1090
1091 if (value == "linear_11")
1092 {
1093 format = pmbus_utils::SensorDataFormat::linear_11;
1094 }
1095 else if (value == "linear_16")
1096 {
1097 format = pmbus_utils::SensorDataFormat::linear_16;
1098 }
1099 else
1100 {
1101 throw std::invalid_argument{"Element is not a sensor data format"};
1102 }
1103
1104 return format;
1105}
1106
Bob Kinga2f2a0d2020-04-09 13:32:14 +08001107std::unique_ptr<SensorMonitoring> parseSensorMonitoring(const json& element)
1108{
1109 verifyIsObject(element);
1110 unsigned int propertyCount{0};
1111
1112 // Optional comments property; value not stored
1113 if (element.contains("comments"))
1114 {
1115 ++propertyCount;
1116 }
1117
1118 // Required rule_id or actions property
1119 std::vector<std::unique_ptr<Action>> actions{};
1120 actions = parseRuleIDOrActionsProperty(element);
1121 ++propertyCount;
1122
1123 // Verify no invalid properties exist
1124 verifyPropertyCount(element, propertyCount);
1125
1126 return std::make_unique<SensorMonitoring>(std::move(actions));
1127}
1128
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001129SensorType parseSensorType(const json& element)
Bob King84614882020-04-30 13:13:48 +08001130{
Shawn McCarneyb70370b2021-09-07 12:07:40 -05001131 std::string value = parseString(element);
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001132 SensorType type{};
Bob King84614882020-04-30 13:13:48 +08001133
1134 if (value == "iout")
1135 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001136 type = SensorType::iout;
Bob King84614882020-04-30 13:13:48 +08001137 }
1138 else if (value == "iout_peak")
1139 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001140 type = SensorType::iout_peak;
Bob King84614882020-04-30 13:13:48 +08001141 }
1142 else if (value == "iout_valley")
1143 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001144 type = SensorType::iout_valley;
Bob King84614882020-04-30 13:13:48 +08001145 }
1146 else if (value == "pout")
1147 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001148 type = SensorType::pout;
Bob King84614882020-04-30 13:13:48 +08001149 }
1150 else if (value == "temperature")
1151 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001152 type = SensorType::temperature;
Bob King84614882020-04-30 13:13:48 +08001153 }
1154 else if (value == "temperature_peak")
1155 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001156 type = SensorType::temperature_peak;
Bob King84614882020-04-30 13:13:48 +08001157 }
1158 else if (value == "vout")
1159 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001160 type = SensorType::vout;
Bob King84614882020-04-30 13:13:48 +08001161 }
1162 else if (value == "vout_peak")
1163 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001164 type = SensorType::vout_peak;
Bob King84614882020-04-30 13:13:48 +08001165 }
1166 else if (value == "vout_valley")
1167 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001168 type = SensorType::vout_valley;
Bob King84614882020-04-30 13:13:48 +08001169 }
1170 else
1171 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001172 throw std::invalid_argument{"Element is not a sensor type"};
Bob King84614882020-04-30 13:13:48 +08001173 }
1174
1175 return type;
1176}
1177
Bob King18a68502020-04-17 14:19:56 +08001178std::unique_ptr<SetDeviceAction> parseSetDevice(const json& element)
1179{
1180 // String deviceID
1181 std::string deviceID = parseString(element);
1182
1183 return std::make_unique<SetDeviceAction>(deviceID);
1184}
1185
Bob King84614882020-04-30 13:13:48 +08001186pmbus_utils::VoutDataFormat parseVoutDataFormat(const json& element)
1187{
1188 if (!element.is_string())
1189 {
1190 throw std::invalid_argument{"Element is not a string"};
1191 }
1192 std::string value = element.get<std::string>();
1193 pmbus_utils::VoutDataFormat format{};
1194
1195 if (value == "linear")
1196 {
1197 format = pmbus_utils::VoutDataFormat::linear;
1198 }
1199 else if (value == "vid")
1200 {
1201 format = pmbus_utils::VoutDataFormat::vid;
1202 }
1203 else if (value == "direct")
1204 {
1205 format = pmbus_utils::VoutDataFormat::direct;
1206 }
1207 else if (value == "ieee")
1208 {
1209 format = pmbus_utils::VoutDataFormat::ieee;
1210 }
1211 else
1212 {
1213 throw std::invalid_argument{"Element is not a vout data format"};
1214 }
1215
1216 return format;
1217}
1218
Shawn McCarney0e8c68a2020-03-27 01:44:48 -05001219} // namespace internal
1220
1221} // namespace phosphor::power::regulators::config_file_parser