blob: 619a8b661bbfe47d51f8429e7cef0790a82f1399 [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
Shawn McCarney32252592021-09-08 15:29:36 -0500397 // Optional phase_fault_detection property
398 std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
399 auto phaseFaultDetectionIt = element.find("phase_fault_detection");
400 if (phaseFaultDetectionIt != element.end())
401 {
402 if (!isRegulator)
403 {
404 throw std::invalid_argument{"Invalid phase_fault_detection "
405 "property when is_regulator is false"};
406 }
407 phaseFaultDetection = parsePhaseFaultDetection(*phaseFaultDetectionIt);
408 ++propertyCount;
409 }
410
Bob King9c36c5f2020-04-06 11:34:09 +0800411 // Optional rails property
412 std::vector<std::unique_ptr<Rail>> rails{};
413 auto railsIt = element.find("rails");
414 if (railsIt != element.end())
415 {
416 if (!isRegulator)
417 {
418 throw std::invalid_argument{
419 "Invalid rails property when is_regulator is false"};
420 }
421 rails = parseRailArray(*railsIt);
422 ++propertyCount;
423 }
424
425 // Verify no invalid properties exist
426 verifyPropertyCount(element, propertyCount);
427
Shawn McCarney32252592021-09-08 15:29:36 -0500428 return std::make_unique<Device>(
429 id, isRegulator, fru, std::move(i2cInterface),
430 std::move(presenceDetection), std::move(configuration),
431 std::move(phaseFaultDetection), std::move(rails));
Bob King9c36c5f2020-04-06 11:34:09 +0800432}
433
Bob King0e701132020-04-03 21:50:31 +0800434std::vector<std::unique_ptr<Device>> parseDeviceArray(const json& element)
435{
436 verifyIsArray(element);
437 std::vector<std::unique_ptr<Device>> devices;
Bob King9c36c5f2020-04-06 11:34:09 +0800438 for (auto& deviceElement : element)
439 {
440 devices.emplace_back(parseDevice(deviceElement));
441 }
Bob King0e701132020-04-03 21:50:31 +0800442 return devices;
443}
444
Bob Kingbafcb862020-03-31 16:39:00 +0800445std::vector<uint8_t> parseHexByteArray(const json& element)
446{
447 verifyIsArray(element);
448 std::vector<uint8_t> values;
449 for (auto& valueElement : element)
450 {
451 values.emplace_back(parseHexByte(valueElement));
452 }
453 return values;
454}
455
Shawn McCarney91f87a52021-09-07 09:59:57 -0500456std::unique_ptr<I2CCaptureBytesAction> parseI2CCaptureBytes(const json& element)
457{
458 verifyIsObject(element);
459 unsigned int propertyCount{0};
460
461 // Required register property
462 const json& regElement = getRequiredProperty(element, "register");
463 uint8_t reg = parseHexByte(regElement);
464 ++propertyCount;
465
466 // Required count property
467 const json& countElement = getRequiredProperty(element, "count");
468 uint8_t count = parseUint8(countElement);
469 if (count < 1)
470 {
471 throw std::invalid_argument{"Invalid byte count: Must be > 0"};
472 }
473 ++propertyCount;
474
475 // Verify no invalid properties exist
476 verifyPropertyCount(element, propertyCount);
477
478 return std::make_unique<I2CCaptureBytesAction>(reg, count);
479}
480
Bob Kingf09bfe02020-04-13 17:21:15 +0800481std::unique_ptr<I2CCompareBitAction> parseI2CCompareBit(const json& element)
482{
483 verifyIsObject(element);
484 unsigned int propertyCount{0};
485
486 // Required register property
487 const json& regElement = getRequiredProperty(element, "register");
488 uint8_t reg = parseHexByte(regElement);
489 ++propertyCount;
490
491 // Required position property
492 const json& positionElement = getRequiredProperty(element, "position");
493 uint8_t position = parseBitPosition(positionElement);
494 ++propertyCount;
495
496 // Required value property
497 const json& valueElement = getRequiredProperty(element, "value");
498 uint8_t value = parseBitValue(valueElement);
499 ++propertyCount;
500
501 // Verify no invalid properties exist
502 verifyPropertyCount(element, propertyCount);
503
504 return std::make_unique<I2CCompareBitAction>(reg, position, value);
505}
506
507std::unique_ptr<I2CCompareByteAction> parseI2CCompareByte(const json& element)
508{
509 verifyIsObject(element);
510 unsigned int propertyCount{0};
511
512 // Required register property
513 const json& regElement = getRequiredProperty(element, "register");
514 uint8_t reg = parseHexByte(regElement);
515 ++propertyCount;
516
517 // Required value property
518 const json& valueElement = getRequiredProperty(element, "value");
519 uint8_t value = parseHexByte(valueElement);
520 ++propertyCount;
521
522 // Optional mask property
523 uint8_t mask = 0xff;
524 auto maskIt = element.find("mask");
525 if (maskIt != element.end())
526 {
527 mask = parseHexByte(*maskIt);
528 ++propertyCount;
529 }
530
531 // Verify no invalid properties exist
532 verifyPropertyCount(element, propertyCount);
533
534 return std::make_unique<I2CCompareByteAction>(reg, value, mask);
535}
536
537std::unique_ptr<I2CCompareBytesAction> parseI2CCompareBytes(const json& element)
538{
539 verifyIsObject(element);
540 unsigned int propertyCount{0};
541
542 // Required register property
543 const json& regElement = getRequiredProperty(element, "register");
544 uint8_t reg = parseHexByte(regElement);
545 ++propertyCount;
546
547 // Required values property
548 const json& valueElement = getRequiredProperty(element, "values");
549 std::vector<uint8_t> values = parseHexByteArray(valueElement);
550 ++propertyCount;
551
552 // Optional masks property
553 std::vector<uint8_t> masks{};
554 auto masksIt = element.find("masks");
555 if (masksIt != element.end())
556 {
557 masks = parseHexByteArray(*masksIt);
558 ++propertyCount;
559 }
560
561 // Verify masks array (if specified) was same size as values array
562 if ((!masks.empty()) && (masks.size() != values.size()))
563 {
564 throw std::invalid_argument{"Invalid number of elements in masks"};
565 }
566
567 // Verify no invalid properties exist
568 verifyPropertyCount(element, propertyCount);
569
570 if (masks.empty())
571 {
572 return std::make_unique<I2CCompareBytesAction>(reg, values);
573 }
574 return std::make_unique<I2CCompareBytesAction>(reg, values, masks);
575}
576
Bob King9c36c5f2020-04-06 11:34:09 +0800577std::unique_ptr<i2c::I2CInterface> parseI2CInterface(const json& element)
578{
579 verifyIsObject(element);
580 unsigned int propertyCount{0};
581
582 // Required bus property
583 const json& busElement = getRequiredProperty(element, "bus");
584 uint8_t bus = parseUint8(busElement);
585 ++propertyCount;
586
587 // Required address property
588 const json& addressElement = getRequiredProperty(element, "address");
589 uint8_t address = parseHexByte(addressElement);
590 ++propertyCount;
591
592 verifyPropertyCount(element, propertyCount);
593 return i2c::create(bus, address, i2c::I2CInterface::InitialState::CLOSED);
594}
595
Bob Kingf617f892020-03-30 19:03:35 +0800596std::unique_ptr<I2CWriteBitAction> parseI2CWriteBit(const json& element)
597{
598 verifyIsObject(element);
599 unsigned int propertyCount{0};
600
601 // Required register property
602 const json& regElement = getRequiredProperty(element, "register");
Bob Kingbafcb862020-03-31 16:39:00 +0800603 uint8_t reg = parseHexByte(regElement);
Bob Kingf617f892020-03-30 19:03:35 +0800604 ++propertyCount;
605
606 // Required position property
607 const json& positionElement = getRequiredProperty(element, "position");
608 uint8_t position = parseBitPosition(positionElement);
609 ++propertyCount;
610
611 // Required value property
612 const json& valueElement = getRequiredProperty(element, "value");
613 uint8_t value = parseBitValue(valueElement);
614 ++propertyCount;
615
616 // Verify no invalid properties exist
617 verifyPropertyCount(element, propertyCount);
618
619 return std::make_unique<I2CWriteBitAction>(reg, position, value);
620}
621
Bob King87ff9d72020-03-31 14:02:55 +0800622std::unique_ptr<I2CWriteByteAction> parseI2CWriteByte(const json& element)
623{
624 verifyIsObject(element);
625 unsigned int propertyCount{0};
626
627 // Required register property
628 const json& regElement = getRequiredProperty(element, "register");
Bob Kingbafcb862020-03-31 16:39:00 +0800629 uint8_t reg = parseHexByte(regElement);
Bob King87ff9d72020-03-31 14:02:55 +0800630 ++propertyCount;
631
632 // Required value property
633 const json& valueElement = getRequiredProperty(element, "value");
Bob Kingbafcb862020-03-31 16:39:00 +0800634 uint8_t value = parseHexByte(valueElement);
Bob King87ff9d72020-03-31 14:02:55 +0800635 ++propertyCount;
636
637 // Optional mask property
638 uint8_t mask = 0xff;
639 auto maskIt = element.find("mask");
640 if (maskIt != element.end())
641 {
Bob Kingbafcb862020-03-31 16:39:00 +0800642 mask = parseHexByte(*maskIt);
Bob King87ff9d72020-03-31 14:02:55 +0800643 ++propertyCount;
644 }
645
646 // Verify no invalid properties exist
647 verifyPropertyCount(element, propertyCount);
648
649 return std::make_unique<I2CWriteByteAction>(reg, value, mask);
650}
651
Bob Kingbafcb862020-03-31 16:39:00 +0800652std::unique_ptr<I2CWriteBytesAction> parseI2CWriteBytes(const json& element)
653{
654 verifyIsObject(element);
655 unsigned int propertyCount{0};
656
657 // Required register property
658 const json& regElement = getRequiredProperty(element, "register");
659 uint8_t reg = parseHexByte(regElement);
660 ++propertyCount;
661
662 // Required values property
663 const json& valueElement = getRequiredProperty(element, "values");
664 std::vector<uint8_t> values = parseHexByteArray(valueElement);
665 ++propertyCount;
666
667 // Optional masks property
668 std::vector<uint8_t> masks{};
669 auto masksIt = element.find("masks");
670 if (masksIt != element.end())
671 {
672 masks = parseHexByteArray(*masksIt);
673 ++propertyCount;
674 }
675
676 // Verify masks array (if specified) was same size as values array
677 if ((!masks.empty()) && (masks.size() != values.size()))
678 {
679 throw std::invalid_argument{"Invalid number of elements in masks"};
680 }
681
682 // Verify no invalid properties exist
683 verifyPropertyCount(element, propertyCount);
684
685 if (masks.empty())
686 {
687 return std::make_unique<I2CWriteBytesAction>(reg, values);
688 }
689 return std::make_unique<I2CWriteBytesAction>(reg, values, masks);
690}
691
Bob King93a89d72020-04-15 15:11:11 +0800692std::unique_ptr<IfAction> parseIf(const json& element)
693{
694 verifyIsObject(element);
695 unsigned int propertyCount{0};
696
697 // Required condition property
698 const json& conditionElement = getRequiredProperty(element, "condition");
699 std::unique_ptr<Action> conditionAction = parseAction(conditionElement);
700 ++propertyCount;
701
702 // Required then property
703 const json& thenElement = getRequiredProperty(element, "then");
704 std::vector<std::unique_ptr<Action>> thenActions =
705 parseActionArray(thenElement);
706 ++propertyCount;
707
708 // Optional else property
709 std::vector<std::unique_ptr<Action>> elseActions{};
710 auto elseIt = element.find("else");
711 if (elseIt != element.end())
712 {
713 elseActions = parseActionArray(*elseIt);
714 ++propertyCount;
715 }
716
717 // Verify no invalid properties exist
718 verifyPropertyCount(element, propertyCount);
719
720 return std::make_unique<IfAction>(std::move(conditionAction),
721 std::move(thenActions),
722 std::move(elseActions));
723}
724
Bob Kinga76898f2020-10-13 15:08:33 +0800725std::string parseInventoryPath(const json& element)
726{
727 std::string inventoryPath = parseString(element);
728 std::string absPath = "/xyz/openbmc_project/inventory";
729 if (inventoryPath.front() != '/')
730 {
731 absPath += '/';
732 }
733 absPath += inventoryPath;
734 return absPath;
735}
736
Shawn McCarney11157852021-09-07 14:04:36 -0500737std::unique_ptr<LogPhaseFaultAction> parseLogPhaseFault(const json& element)
738{
739 verifyIsObject(element);
740 unsigned int propertyCount{0};
741
742 // Required type property
743 const json& typeElement = getRequiredProperty(element, "type");
744 PhaseFaultType type = parsePhaseFaultType(typeElement);
745 ++propertyCount;
746
747 // Verify no invalid properties exist
748 verifyPropertyCount(element, propertyCount);
749
750 return std::make_unique<LogPhaseFaultAction>(type);
751}
752
Bob Kingf1b58dc2020-04-14 14:53:10 +0800753std::unique_ptr<NotAction> parseNot(const json& element)
754{
755 // Required action to execute
756 std::unique_ptr<Action> action = parseAction(element);
757
758 return std::make_unique<NotAction>(std::move(action));
759}
760
Bob King0b51a9b2020-04-15 13:24:18 +0800761std::unique_ptr<OrAction> parseOr(const json& element)
762{
763 verifyIsArray(element);
764
765 // Verify if array size less than 2
766 if (element.size() < 2)
767 {
768 throw std::invalid_argument{"Array must contain two or more actions"};
769 }
770 // Array of two or more actions
771 std::vector<std::unique_ptr<Action>> actions = parseActionArray(element);
772
773 return std::make_unique<OrAction>(std::move(actions));
774}
775
Shawn McCarney39eb08a2021-09-07 16:34:49 -0500776std::unique_ptr<PhaseFaultDetection>
777 parsePhaseFaultDetection(const json& element)
778{
779 verifyIsObject(element);
780 unsigned int propertyCount{0};
781
782 // Optional comments property; value not stored
783 if (element.contains("comments"))
784 {
785 ++propertyCount;
786 }
787
788 // Optional device_id property
789 std::string deviceID{};
790 auto deviceIDIt = element.find("device_id");
791 if (deviceIDIt != element.end())
792 {
793 deviceID = parseString(*deviceIDIt);
794 ++propertyCount;
795 }
796
797 // Required rule_id or actions property
798 std::vector<std::unique_ptr<Action>> actions{};
799 actions = parseRuleIDOrActionsProperty(element);
800 ++propertyCount;
801
802 // Verify no invalid properties exist
803 verifyPropertyCount(element, propertyCount);
804
805 return std::make_unique<PhaseFaultDetection>(std::move(actions), deviceID);
806}
807
Shawn McCarneyb70370b2021-09-07 12:07:40 -0500808PhaseFaultType parsePhaseFaultType(const json& element)
809{
810 std::string value = parseString(element);
811 PhaseFaultType type{};
812
813 if (value == "n")
814 {
815 type = PhaseFaultType::n;
816 }
817 else if (value == "n+1")
818 {
819 type = PhaseFaultType::n_plus_1;
820 }
821 else
822 {
823 throw std::invalid_argument{"Element is not a phase fault type"};
824 }
825
826 return type;
827}
828
Bob King84614882020-04-30 13:13:48 +0800829std::unique_ptr<PMBusReadSensorAction> parsePMBusReadSensor(const json& element)
830{
831 verifyIsObject(element);
832 unsigned int propertyCount{0};
833
834 // Required type property
835 const json& typeElement = getRequiredProperty(element, "type");
Shawn McCarney2f9e14f2021-04-29 02:45:18 -0500836 SensorType type = parseSensorType(typeElement);
Bob King84614882020-04-30 13:13:48 +0800837 ++propertyCount;
838
839 // Required command property
840 const json& commandElement = getRequiredProperty(element, "command");
841 uint8_t command = parseHexByte(commandElement);
842 ++propertyCount;
843
844 // Required format property
845 const json& formatElement = getRequiredProperty(element, "format");
846 pmbus_utils::SensorDataFormat format = parseSensorDataFormat(formatElement);
847 ++propertyCount;
848
849 // Optional exponent property
850 std::optional<int8_t> exponent{};
851 auto exponentIt = element.find("exponent");
852 if (exponentIt != element.end())
853 {
854 exponent = parseInt8(*exponentIt);
855 ++propertyCount;
856 }
857
858 // Verify no invalid properties exist
859 verifyPropertyCount(element, propertyCount);
860
861 return std::make_unique<PMBusReadSensorAction>(type, command, format,
862 exponent);
863}
864
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500865std::unique_ptr<PMBusWriteVoutCommandAction>
866 parsePMBusWriteVoutCommand(const json& element)
867{
868 verifyIsObject(element);
869 unsigned int propertyCount{0};
870
871 // Optional volts property
872 std::optional<double> volts{};
873 auto voltsIt = element.find("volts");
874 if (voltsIt != element.end())
875 {
876 volts = parseDouble(*voltsIt);
877 ++propertyCount;
878 }
879
880 // Required format property
881 const json& formatElement = getRequiredProperty(element, "format");
882 std::string formatString = parseString(formatElement);
883 if (formatString != "linear")
884 {
885 throw std::invalid_argument{"Invalid format value: " + formatString};
886 }
887 pmbus_utils::VoutDataFormat format = pmbus_utils::VoutDataFormat::linear;
888 ++propertyCount;
889
890 // Optional exponent property
891 std::optional<int8_t> exponent{};
892 auto exponentIt = element.find("exponent");
893 if (exponentIt != element.end())
894 {
895 exponent = parseInt8(*exponentIt);
896 ++propertyCount;
897 }
898
899 // Optional is_verified property
900 bool isVerified = false;
901 auto isVerifiedIt = element.find("is_verified");
902 if (isVerifiedIt != element.end())
903 {
904 isVerified = parseBoolean(*isVerifiedIt);
905 ++propertyCount;
906 }
907
908 // Verify no invalid properties exist
909 verifyPropertyCount(element, propertyCount);
910
911 return std::make_unique<PMBusWriteVoutCommandAction>(volts, format,
912 exponent, isVerified);
913}
914
Bob King2aafb1c2020-04-16 15:24:32 +0800915std::unique_ptr<PresenceDetection> parsePresenceDetection(const json& element)
916{
917 verifyIsObject(element);
918 unsigned int propertyCount{0};
919
920 // Optional comments property; value not stored
921 if (element.contains("comments"))
922 {
923 ++propertyCount;
924 }
925
926 // Required rule_id or actions property
927 std::vector<std::unique_ptr<Action>> actions{};
928 actions = parseRuleIDOrActionsProperty(element);
929 ++propertyCount;
930
931 // Verify no invalid properties exist
932 verifyPropertyCount(element, propertyCount);
933
934 return std::make_unique<PresenceDetection>(std::move(actions));
935}
936
Bob Kinga2f2a0d2020-04-09 13:32:14 +0800937std::unique_ptr<Rail> parseRail(const json& element)
938{
939 verifyIsObject(element);
940 unsigned int propertyCount{0};
941
942 // Optional comments property; value not stored
943 if (element.contains("comments"))
944 {
945 ++propertyCount;
946 }
947
948 // Required id property
949 const json& idElement = getRequiredProperty(element, "id");
950 std::string id = parseString(idElement);
951 ++propertyCount;
952
953 // Optional configuration property
954 std::unique_ptr<Configuration> configuration{};
955 auto configurationIt = element.find("configuration");
956 if (configurationIt != element.end())
957 {
958 configuration = parseConfiguration(*configurationIt);
959 ++propertyCount;
960 }
961
962 // Optional sensor_monitoring property
963 std::unique_ptr<SensorMonitoring> sensorMonitoring{};
964 auto sensorMonitoringIt = element.find("sensor_monitoring");
965 if (sensorMonitoringIt != element.end())
966 {
967 sensorMonitoring = parseSensorMonitoring(*sensorMonitoringIt);
968 ++propertyCount;
969 }
970
971 // Verify no invalid properties exist
972 verifyPropertyCount(element, propertyCount);
973
974 return std::make_unique<Rail>(id, std::move(configuration),
975 std::move(sensorMonitoring));
976}
977
Bob King9c36c5f2020-04-06 11:34:09 +0800978std::vector<std::unique_ptr<Rail>> parseRailArray(const json& element)
979{
980 verifyIsArray(element);
981 std::vector<std::unique_ptr<Rail>> rails;
Bob Kinga2f2a0d2020-04-09 13:32:14 +0800982 for (auto& railElement : element)
983 {
984 rails.emplace_back(parseRail(railElement));
985 }
Bob King9c36c5f2020-04-06 11:34:09 +0800986 return rails;
987}
988
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500989std::tuple<std::vector<std::unique_ptr<Rule>>,
990 std::vector<std::unique_ptr<Chassis>>>
991 parseRoot(const json& element)
992{
993 verifyIsObject(element);
994 unsigned int propertyCount{0};
995
996 // Optional comments property; value not stored
997 if (element.contains("comments"))
998 {
999 ++propertyCount;
1000 }
1001
1002 // Optional rules property
1003 std::vector<std::unique_ptr<Rule>> rules{};
1004 auto rulesIt = element.find("rules");
1005 if (rulesIt != element.end())
1006 {
1007 rules = parseRuleArray(*rulesIt);
1008 ++propertyCount;
1009 }
1010
1011 // Required chassis property
1012 const json& chassisElement = getRequiredProperty(element, "chassis");
1013 std::vector<std::unique_ptr<Chassis>> chassis =
1014 parseChassisArray(chassisElement);
1015 ++propertyCount;
1016
1017 // Verify no invalid properties exist
1018 verifyPropertyCount(element, propertyCount);
1019
1020 return std::make_tuple(std::move(rules), std::move(chassis));
1021}
1022
1023std::unique_ptr<Rule> parseRule(const json& element)
1024{
1025 verifyIsObject(element);
1026 unsigned int propertyCount{0};
1027
1028 // Optional comments property; value not stored
1029 if (element.contains("comments"))
1030 {
1031 ++propertyCount;
1032 }
1033
1034 // Required id property
1035 const json& idElement = getRequiredProperty(element, "id");
1036 std::string id = parseString(idElement);
1037 ++propertyCount;
1038
1039 // Required actions property
1040 const json& actionsElement = getRequiredProperty(element, "actions");
1041 std::vector<std::unique_ptr<Action>> actions =
1042 parseActionArray(actionsElement);
1043 ++propertyCount;
1044
1045 // Verify no invalid properties exist
1046 verifyPropertyCount(element, propertyCount);
1047
1048 return std::make_unique<Rule>(id, std::move(actions));
1049}
1050
1051std::vector<std::unique_ptr<Rule>> parseRuleArray(const json& element)
1052{
1053 verifyIsArray(element);
1054 std::vector<std::unique_ptr<Rule>> rules;
1055 for (auto& ruleElement : element)
1056 {
1057 rules.emplace_back(parseRule(ruleElement));
1058 }
1059 return rules;
1060}
1061
Bob King33e7eaa2020-04-01 18:09:34 +08001062std::vector<std::unique_ptr<Action>>
1063 parseRuleIDOrActionsProperty(const json& element)
1064{
1065 verifyIsObject(element);
1066 // Required rule_id or actions property
1067 std::vector<std::unique_ptr<Action>> actions{};
1068 auto ruleIDIt = element.find("rule_id");
1069 auto actionsIt = element.find("actions");
1070 if ((actionsIt == element.end()) && (ruleIDIt != element.end()))
1071 {
1072 std::string ruleID = parseString(*ruleIDIt);
1073 actions.emplace_back(std::make_unique<RunRuleAction>(ruleID));
1074 }
1075 else if ((actionsIt != element.end()) && (ruleIDIt == element.end()))
1076 {
1077 actions = parseActionArray(*actionsIt);
1078 }
1079 else
1080 {
1081 throw std::invalid_argument{"Invalid property combination: Must "
1082 "contain either rule_id or actions"};
1083 }
1084
1085 return actions;
1086}
1087
Bob King315b0b62020-04-03 21:47:58 +08001088std::unique_ptr<RunRuleAction> parseRunRule(const json& element)
1089{
1090 // String ruleID
1091 std::string ruleID = parseString(element);
1092
1093 return std::make_unique<RunRuleAction>(ruleID);
1094}
1095
Bob King84614882020-04-30 13:13:48 +08001096pmbus_utils::SensorDataFormat parseSensorDataFormat(const json& element)
1097{
1098 if (!element.is_string())
1099 {
1100 throw std::invalid_argument{"Element is not a string"};
1101 }
1102 std::string value = element.get<std::string>();
1103 pmbus_utils::SensorDataFormat format{};
1104
1105 if (value == "linear_11")
1106 {
1107 format = pmbus_utils::SensorDataFormat::linear_11;
1108 }
1109 else if (value == "linear_16")
1110 {
1111 format = pmbus_utils::SensorDataFormat::linear_16;
1112 }
1113 else
1114 {
1115 throw std::invalid_argument{"Element is not a sensor data format"};
1116 }
1117
1118 return format;
1119}
1120
Bob Kinga2f2a0d2020-04-09 13:32:14 +08001121std::unique_ptr<SensorMonitoring> parseSensorMonitoring(const json& element)
1122{
1123 verifyIsObject(element);
1124 unsigned int propertyCount{0};
1125
1126 // Optional comments property; value not stored
1127 if (element.contains("comments"))
1128 {
1129 ++propertyCount;
1130 }
1131
1132 // Required rule_id or actions property
1133 std::vector<std::unique_ptr<Action>> actions{};
1134 actions = parseRuleIDOrActionsProperty(element);
1135 ++propertyCount;
1136
1137 // Verify no invalid properties exist
1138 verifyPropertyCount(element, propertyCount);
1139
1140 return std::make_unique<SensorMonitoring>(std::move(actions));
1141}
1142
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001143SensorType parseSensorType(const json& element)
Bob King84614882020-04-30 13:13:48 +08001144{
Shawn McCarneyb70370b2021-09-07 12:07:40 -05001145 std::string value = parseString(element);
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001146 SensorType type{};
Bob King84614882020-04-30 13:13:48 +08001147
1148 if (value == "iout")
1149 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001150 type = SensorType::iout;
Bob King84614882020-04-30 13:13:48 +08001151 }
1152 else if (value == "iout_peak")
1153 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001154 type = SensorType::iout_peak;
Bob King84614882020-04-30 13:13:48 +08001155 }
1156 else if (value == "iout_valley")
1157 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001158 type = SensorType::iout_valley;
Bob King84614882020-04-30 13:13:48 +08001159 }
1160 else if (value == "pout")
1161 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001162 type = SensorType::pout;
Bob King84614882020-04-30 13:13:48 +08001163 }
1164 else if (value == "temperature")
1165 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001166 type = SensorType::temperature;
Bob King84614882020-04-30 13:13:48 +08001167 }
1168 else if (value == "temperature_peak")
1169 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001170 type = SensorType::temperature_peak;
Bob King84614882020-04-30 13:13:48 +08001171 }
1172 else if (value == "vout")
1173 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001174 type = SensorType::vout;
Bob King84614882020-04-30 13:13:48 +08001175 }
1176 else if (value == "vout_peak")
1177 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001178 type = SensorType::vout_peak;
Bob King84614882020-04-30 13:13:48 +08001179 }
1180 else if (value == "vout_valley")
1181 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001182 type = SensorType::vout_valley;
Bob King84614882020-04-30 13:13:48 +08001183 }
1184 else
1185 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001186 throw std::invalid_argument{"Element is not a sensor type"};
Bob King84614882020-04-30 13:13:48 +08001187 }
1188
1189 return type;
1190}
1191
Bob King18a68502020-04-17 14:19:56 +08001192std::unique_ptr<SetDeviceAction> parseSetDevice(const json& element)
1193{
1194 // String deviceID
1195 std::string deviceID = parseString(element);
1196
1197 return std::make_unique<SetDeviceAction>(deviceID);
1198}
1199
Bob King84614882020-04-30 13:13:48 +08001200pmbus_utils::VoutDataFormat parseVoutDataFormat(const json& element)
1201{
1202 if (!element.is_string())
1203 {
1204 throw std::invalid_argument{"Element is not a string"};
1205 }
1206 std::string value = element.get<std::string>();
1207 pmbus_utils::VoutDataFormat format{};
1208
1209 if (value == "linear")
1210 {
1211 format = pmbus_utils::VoutDataFormat::linear;
1212 }
1213 else if (value == "vid")
1214 {
1215 format = pmbus_utils::VoutDataFormat::vid;
1216 }
1217 else if (value == "direct")
1218 {
1219 format = pmbus_utils::VoutDataFormat::direct;
1220 }
1221 else if (value == "ieee")
1222 {
1223 format = pmbus_utils::VoutDataFormat::ieee;
1224 }
1225 else
1226 {
1227 throw std::invalid_argument{"Element is not a vout data format"};
1228 }
1229
1230 return format;
1231}
1232
Shawn McCarney0e8c68a2020-03-27 01:44:48 -05001233} // namespace internal
1234
1235} // namespace phosphor::power::regulators::config_file_parser