1 /**
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"
20 #include "i2c_interface.hpp"
21 #include "pmbus_utils.hpp"
22 
23 #include <exception>
24 #include <fstream>
25 #include <optional>
26 #include <utility>
27 
28 using json = nlohmann::json;
29 
30 namespace phosphor::power::regulators::config_file_parser
31 {
32 
33 std::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 
52 namespace internal
53 {
54 
55 std::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     {
70         // TODO: Not implemented yet
71         // action = parseAnd(element["and"]);
72         // ++propertyCount;
73     }
74     else if (element.contains("compare_presence"))
75     {
76         // TODO: Not implemented yet
77         // action = parseComparePresence(element["compare_presence"]);
78         // ++propertyCount;
79     }
80     else if (element.contains("compare_vpd"))
81     {
82         // TODO: Not implemented yet
83         // action = parseCompareVPD(element["compare_vpd"]);
84         // ++propertyCount;
85     }
86     else if (element.contains("i2c_compare_bit"))
87     {
88         // TODO: Not implemented yet
89         // action = parseI2CCompareBit(element["i2c_compare_bit"]);
90         // ++propertyCount;
91     }
92     else if (element.contains("i2c_compare_byte"))
93     {
94         // TODO: Not implemented yet
95         // action = parseI2CCompareByte(element["i2c_compare_byte"]);
96         // ++propertyCount;
97     }
98     else if (element.contains("i2c_compare_bytes"))
99     {
100         // TODO: Not implemented yet
101         // action = parseI2CCompareBytes(element["i2c_compare_bytes"]);
102         // ++propertyCount;
103     }
104     else if (element.contains("i2c_write_bit"))
105     {
106         action = parseI2CWriteBit(element["i2c_write_bit"]);
107         ++propertyCount;
108     }
109     else if (element.contains("i2c_write_byte"))
110     {
111         action = parseI2CWriteByte(element["i2c_write_byte"]);
112         ++propertyCount;
113     }
114     else if (element.contains("i2c_write_bytes"))
115     {
116         action = parseI2CWriteBytes(element["i2c_write_bytes"]);
117         ++propertyCount;
118     }
119     else if (element.contains("if"))
120     {
121         // TODO: Not implemented yet
122         // action = parseIf(element["if"]);
123         // ++propertyCount;
124     }
125     else if (element.contains("not"))
126     {
127         // TODO: Not implemented yet
128         // action = parseNot(element["not"]);
129         // ++propertyCount;
130     }
131     else if (element.contains("or"))
132     {
133         // TODO: Not implemented yet
134         // action = parseOr(element["or"]);
135         // ++propertyCount;
136     }
137     else if (element.contains("pmbus_read_sensor"))
138     {
139         // TODO: Not implemented yet
140         // action = parsePMBusReadSensor(element["pmbus_read_sensor"]);
141         // ++propertyCount;
142     }
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     {
151         action = parseRunRule(element["run_rule"]);
152         ++propertyCount;
153     }
154     else if (element.contains("set_device"))
155     {
156         // TODO: Not implemented yet
157         // action = parseSetDevice(element["set_device"]);
158         // ++propertyCount;
159     }
160     else
161     {
162         throw std::invalid_argument{"Required action type property missing"};
163     }
164 
165     // Verify no invalid properties exist
166     verifyPropertyCount(element, propertyCount);
167 
168     return action;
169 }
170 
171 std::vector<std::unique_ptr<Action>> parseActionArray(const json& element)
172 {
173     verifyIsArray(element);
174     std::vector<std::unique_ptr<Action>> actions;
175     for (auto& actionElement : element)
176     {
177         actions.emplace_back(parseAction(actionElement));
178     }
179     return actions;
180 }
181 
182 std::unique_ptr<Chassis> parseChassis(const json& element)
183 {
184     verifyIsObject(element);
185     unsigned int propertyCount{0};
186 
187     // Optional comments property; value not stored
188     if (element.contains("comments"))
189     {
190         ++propertyCount;
191     }
192 
193     // Required number property
194     const json& numberElement = getRequiredProperty(element, "number");
195     unsigned int number = parseUnsignedInteger(numberElement);
196     if (number < 1)
197     {
198         throw std::invalid_argument{"Invalid chassis number: Must be > 0"};
199     }
200     ++propertyCount;
201 
202     // Optional devices property
203     std::vector<std::unique_ptr<Device>> devices{};
204     auto devicesIt = element.find("devices");
205     if (devicesIt != element.end())
206     {
207         devices = parseDeviceArray(*devicesIt);
208         ++propertyCount;
209     }
210 
211     // Verify no invalid properties exist
212     verifyPropertyCount(element, propertyCount);
213 
214     return std::make_unique<Chassis>(number, std::move(devices));
215 }
216 
217 std::vector<std::unique_ptr<Chassis>> parseChassisArray(const json& element)
218 {
219     verifyIsArray(element);
220     std::vector<std::unique_ptr<Chassis>> chassis;
221     for (auto& chassisElement : element)
222     {
223         chassis.emplace_back(parseChassis(chassisElement));
224     }
225     return chassis;
226 }
227 
228 std::unique_ptr<Configuration> parseConfiguration(const json& element)
229 {
230     verifyIsObject(element);
231     unsigned int propertyCount{0};
232 
233     // Optional comments property; value not stored
234     if (element.contains("comments"))
235     {
236         ++propertyCount;
237     }
238 
239     // Optional volts property
240     std::optional<double> volts{};
241     auto voltsIt = element.find("volts");
242     if (voltsIt != element.end())
243     {
244         volts = parseDouble(*voltsIt);
245         ++propertyCount;
246     }
247 
248     // Required rule_id or actions property
249     std::vector<std::unique_ptr<Action>> actions{};
250     actions = parseRuleIDOrActionsProperty(element);
251     ++propertyCount;
252 
253     // Verify no invalid properties exist
254     verifyPropertyCount(element, propertyCount);
255 
256     return std::make_unique<Configuration>(volts, std::move(actions));
257 }
258 
259 std::unique_ptr<Device> parseDevice(const json& element)
260 {
261     verifyIsObject(element);
262     unsigned int propertyCount{0};
263 
264     // Optional comments property; value not stored
265     if (element.contains("comments"))
266     {
267         ++propertyCount;
268     }
269 
270     // Required id property
271     const json& idElement = getRequiredProperty(element, "id");
272     std::string id = parseString(idElement);
273     ++propertyCount;
274 
275     // Required is_regulator property
276     const json& isRegulatorElement =
277         getRequiredProperty(element, "is_regulator");
278     bool isRegulator = parseBoolean(isRegulatorElement);
279     ++propertyCount;
280 
281     // Required fru property
282     const json& fruElement = getRequiredProperty(element, "fru");
283     std::string fru = parseString(fruElement);
284     ++propertyCount;
285 
286     // Required i2c_interface property
287     const json& i2cInterfaceElement =
288         getRequiredProperty(element, "i2c_interface");
289     std::unique_ptr<i2c::I2CInterface> i2cInterface =
290         parseI2CInterface(i2cInterfaceElement);
291     ++propertyCount;
292 
293     // Optional presence_detection property
294     // TODO: Not implemented yet
295     std::unique_ptr<PresenceDetection> presenceDetection{};
296     // auto presenceDetectionIt = element.find("presence_detection");
297     // if (presenceDetectionIt != element.end())
298     // {
299     //     presenceDetection = parsePresenceDetection(*presenceDetectionIt);
300     //     ++propertyCount;
301     // }
302 
303     // Optional configuration property
304     std::unique_ptr<Configuration> configuration{};
305     auto configurationIt = element.find("configuration");
306     if (configurationIt != element.end())
307     {
308         configuration = parseConfiguration(*configurationIt);
309         ++propertyCount;
310     }
311 
312     // Optional rails property
313     std::vector<std::unique_ptr<Rail>> rails{};
314     auto railsIt = element.find("rails");
315     if (railsIt != element.end())
316     {
317         if (!isRegulator)
318         {
319             throw std::invalid_argument{
320                 "Invalid rails property when is_regulator is false"};
321         }
322         rails = parseRailArray(*railsIt);
323         ++propertyCount;
324     }
325 
326     // Verify no invalid properties exist
327     verifyPropertyCount(element, propertyCount);
328 
329     return std::make_unique<Device>(id, isRegulator, fru,
330                                     std::move(i2cInterface),
331                                     std::move(presenceDetection),
332                                     std::move(configuration), std::move(rails));
333 }
334 
335 std::vector<std::unique_ptr<Device>> parseDeviceArray(const json& element)
336 {
337     verifyIsArray(element);
338     std::vector<std::unique_ptr<Device>> devices;
339     for (auto& deviceElement : element)
340     {
341         devices.emplace_back(parseDevice(deviceElement));
342     }
343     return devices;
344 }
345 
346 std::vector<uint8_t> parseHexByteArray(const json& element)
347 {
348     verifyIsArray(element);
349     std::vector<uint8_t> values;
350     for (auto& valueElement : element)
351     {
352         values.emplace_back(parseHexByte(valueElement));
353     }
354     return values;
355 }
356 
357 std::unique_ptr<i2c::I2CInterface> parseI2CInterface(const json& element)
358 {
359     verifyIsObject(element);
360     unsigned int propertyCount{0};
361 
362     // Required bus property
363     const json& busElement = getRequiredProperty(element, "bus");
364     uint8_t bus = parseUint8(busElement);
365     ++propertyCount;
366 
367     // Required address property
368     const json& addressElement = getRequiredProperty(element, "address");
369     uint8_t address = parseHexByte(addressElement);
370     ++propertyCount;
371 
372     verifyPropertyCount(element, propertyCount);
373     return i2c::create(bus, address, i2c::I2CInterface::InitialState::CLOSED);
374 }
375 
376 std::unique_ptr<I2CWriteBitAction> parseI2CWriteBit(const json& element)
377 {
378     verifyIsObject(element);
379     unsigned int propertyCount{0};
380 
381     // Required register property
382     const json& regElement = getRequiredProperty(element, "register");
383     uint8_t reg = parseHexByte(regElement);
384     ++propertyCount;
385 
386     // Required position property
387     const json& positionElement = getRequiredProperty(element, "position");
388     uint8_t position = parseBitPosition(positionElement);
389     ++propertyCount;
390 
391     // Required value property
392     const json& valueElement = getRequiredProperty(element, "value");
393     uint8_t value = parseBitValue(valueElement);
394     ++propertyCount;
395 
396     // Verify no invalid properties exist
397     verifyPropertyCount(element, propertyCount);
398 
399     return std::make_unique<I2CWriteBitAction>(reg, position, value);
400 }
401 
402 std::unique_ptr<I2CWriteByteAction> parseI2CWriteByte(const json& element)
403 {
404     verifyIsObject(element);
405     unsigned int propertyCount{0};
406 
407     // Required register property
408     const json& regElement = getRequiredProperty(element, "register");
409     uint8_t reg = parseHexByte(regElement);
410     ++propertyCount;
411 
412     // Required value property
413     const json& valueElement = getRequiredProperty(element, "value");
414     uint8_t value = parseHexByte(valueElement);
415     ++propertyCount;
416 
417     // Optional mask property
418     uint8_t mask = 0xff;
419     auto maskIt = element.find("mask");
420     if (maskIt != element.end())
421     {
422         mask = parseHexByte(*maskIt);
423         ++propertyCount;
424     }
425 
426     // Verify no invalid properties exist
427     verifyPropertyCount(element, propertyCount);
428 
429     return std::make_unique<I2CWriteByteAction>(reg, value, mask);
430 }
431 
432 std::unique_ptr<I2CWriteBytesAction> parseI2CWriteBytes(const json& element)
433 {
434     verifyIsObject(element);
435     unsigned int propertyCount{0};
436 
437     // Required register property
438     const json& regElement = getRequiredProperty(element, "register");
439     uint8_t reg = parseHexByte(regElement);
440     ++propertyCount;
441 
442     // Required values property
443     const json& valueElement = getRequiredProperty(element, "values");
444     std::vector<uint8_t> values = parseHexByteArray(valueElement);
445     ++propertyCount;
446 
447     // Optional masks property
448     std::vector<uint8_t> masks{};
449     auto masksIt = element.find("masks");
450     if (masksIt != element.end())
451     {
452         masks = parseHexByteArray(*masksIt);
453         ++propertyCount;
454     }
455 
456     // Verify masks array (if specified) was same size as values array
457     if ((!masks.empty()) && (masks.size() != values.size()))
458     {
459         throw std::invalid_argument{"Invalid number of elements in masks"};
460     }
461 
462     // Verify no invalid properties exist
463     verifyPropertyCount(element, propertyCount);
464 
465     if (masks.empty())
466     {
467         return std::make_unique<I2CWriteBytesAction>(reg, values);
468     }
469     return std::make_unique<I2CWriteBytesAction>(reg, values, masks);
470 }
471 
472 std::unique_ptr<PMBusWriteVoutCommandAction>
473     parsePMBusWriteVoutCommand(const json& element)
474 {
475     verifyIsObject(element);
476     unsigned int propertyCount{0};
477 
478     // Optional volts property
479     std::optional<double> volts{};
480     auto voltsIt = element.find("volts");
481     if (voltsIt != element.end())
482     {
483         volts = parseDouble(*voltsIt);
484         ++propertyCount;
485     }
486 
487     // Required format property
488     const json& formatElement = getRequiredProperty(element, "format");
489     std::string formatString = parseString(formatElement);
490     if (formatString != "linear")
491     {
492         throw std::invalid_argument{"Invalid format value: " + formatString};
493     }
494     pmbus_utils::VoutDataFormat format = pmbus_utils::VoutDataFormat::linear;
495     ++propertyCount;
496 
497     // Optional exponent property
498     std::optional<int8_t> exponent{};
499     auto exponentIt = element.find("exponent");
500     if (exponentIt != element.end())
501     {
502         exponent = parseInt8(*exponentIt);
503         ++propertyCount;
504     }
505 
506     // Optional is_verified property
507     bool isVerified = false;
508     auto isVerifiedIt = element.find("is_verified");
509     if (isVerifiedIt != element.end())
510     {
511         isVerified = parseBoolean(*isVerifiedIt);
512         ++propertyCount;
513     }
514 
515     // Verify no invalid properties exist
516     verifyPropertyCount(element, propertyCount);
517 
518     return std::make_unique<PMBusWriteVoutCommandAction>(volts, format,
519                                                          exponent, isVerified);
520 }
521 
522 std::unique_ptr<Rail> parseRail(const json& element)
523 {
524     verifyIsObject(element);
525     unsigned int propertyCount{0};
526 
527     // Optional comments property; value not stored
528     if (element.contains("comments"))
529     {
530         ++propertyCount;
531     }
532 
533     // Required id property
534     const json& idElement = getRequiredProperty(element, "id");
535     std::string id = parseString(idElement);
536     ++propertyCount;
537 
538     // Optional configuration property
539     std::unique_ptr<Configuration> configuration{};
540     auto configurationIt = element.find("configuration");
541     if (configurationIt != element.end())
542     {
543         configuration = parseConfiguration(*configurationIt);
544         ++propertyCount;
545     }
546 
547     // Optional sensor_monitoring property
548     std::unique_ptr<SensorMonitoring> sensorMonitoring{};
549     auto sensorMonitoringIt = element.find("sensor_monitoring");
550     if (sensorMonitoringIt != element.end())
551     {
552         sensorMonitoring = parseSensorMonitoring(*sensorMonitoringIt);
553         ++propertyCount;
554     }
555 
556     // Verify no invalid properties exist
557     verifyPropertyCount(element, propertyCount);
558 
559     return std::make_unique<Rail>(id, std::move(configuration),
560                                   std::move(sensorMonitoring));
561 }
562 
563 std::vector<std::unique_ptr<Rail>> parseRailArray(const json& element)
564 {
565     verifyIsArray(element);
566     std::vector<std::unique_ptr<Rail>> rails;
567     for (auto& railElement : element)
568     {
569         rails.emplace_back(parseRail(railElement));
570     }
571     return rails;
572 }
573 
574 std::tuple<std::vector<std::unique_ptr<Rule>>,
575            std::vector<std::unique_ptr<Chassis>>>
576     parseRoot(const json& element)
577 {
578     verifyIsObject(element);
579     unsigned int propertyCount{0};
580 
581     // Optional comments property; value not stored
582     if (element.contains("comments"))
583     {
584         ++propertyCount;
585     }
586 
587     // Optional rules property
588     std::vector<std::unique_ptr<Rule>> rules{};
589     auto rulesIt = element.find("rules");
590     if (rulesIt != element.end())
591     {
592         rules = parseRuleArray(*rulesIt);
593         ++propertyCount;
594     }
595 
596     // Required chassis property
597     const json& chassisElement = getRequiredProperty(element, "chassis");
598     std::vector<std::unique_ptr<Chassis>> chassis =
599         parseChassisArray(chassisElement);
600     ++propertyCount;
601 
602     // Verify no invalid properties exist
603     verifyPropertyCount(element, propertyCount);
604 
605     return std::make_tuple(std::move(rules), std::move(chassis));
606 }
607 
608 std::unique_ptr<Rule> parseRule(const json& element)
609 {
610     verifyIsObject(element);
611     unsigned int propertyCount{0};
612 
613     // Optional comments property; value not stored
614     if (element.contains("comments"))
615     {
616         ++propertyCount;
617     }
618 
619     // Required id property
620     const json& idElement = getRequiredProperty(element, "id");
621     std::string id = parseString(idElement);
622     ++propertyCount;
623 
624     // Required actions property
625     const json& actionsElement = getRequiredProperty(element, "actions");
626     std::vector<std::unique_ptr<Action>> actions =
627         parseActionArray(actionsElement);
628     ++propertyCount;
629 
630     // Verify no invalid properties exist
631     verifyPropertyCount(element, propertyCount);
632 
633     return std::make_unique<Rule>(id, std::move(actions));
634 }
635 
636 std::vector<std::unique_ptr<Rule>> parseRuleArray(const json& element)
637 {
638     verifyIsArray(element);
639     std::vector<std::unique_ptr<Rule>> rules;
640     for (auto& ruleElement : element)
641     {
642         rules.emplace_back(parseRule(ruleElement));
643     }
644     return rules;
645 }
646 
647 std::vector<std::unique_ptr<Action>>
648     parseRuleIDOrActionsProperty(const json& element)
649 {
650     verifyIsObject(element);
651     // Required rule_id or actions property
652     std::vector<std::unique_ptr<Action>> actions{};
653     auto ruleIDIt = element.find("rule_id");
654     auto actionsIt = element.find("actions");
655     if ((actionsIt == element.end()) && (ruleIDIt != element.end()))
656     {
657         std::string ruleID = parseString(*ruleIDIt);
658         actions.emplace_back(std::make_unique<RunRuleAction>(ruleID));
659     }
660     else if ((actionsIt != element.end()) && (ruleIDIt == element.end()))
661     {
662         actions = parseActionArray(*actionsIt);
663     }
664     else
665     {
666         throw std::invalid_argument{"Invalid property combination: Must "
667                                     "contain either rule_id or actions"};
668     }
669 
670     return actions;
671 }
672 
673 std::unique_ptr<RunRuleAction> parseRunRule(const json& element)
674 {
675     // String ruleID
676     std::string ruleID = parseString(element);
677 
678     return std::make_unique<RunRuleAction>(ruleID);
679 }
680 
681 std::unique_ptr<SensorMonitoring> parseSensorMonitoring(const json& element)
682 {
683     verifyIsObject(element);
684     unsigned int propertyCount{0};
685 
686     // Optional comments property; value not stored
687     if (element.contains("comments"))
688     {
689         ++propertyCount;
690     }
691 
692     // Required rule_id or actions property
693     std::vector<std::unique_ptr<Action>> actions{};
694     actions = parseRuleIDOrActionsProperty(element);
695     ++propertyCount;
696 
697     // Verify no invalid properties exist
698     verifyPropertyCount(element, propertyCount);
699 
700     return std::make_unique<SensorMonitoring>(std::move(actions));
701 }
702 
703 } // namespace internal
704 
705 } // namespace phosphor::power::regulators::config_file_parser
706