blob: 1d64c9631afd63ae111f4f7755892067f53feeae [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 {
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 {
Bob Kingf617f892020-03-30 19:03:35 +0800106 action = parseI2CWriteBit(element["i2c_write_bit"]);
107 ++propertyCount;
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500108 }
109 else if (element.contains("i2c_write_byte"))
110 {
Bob King87ff9d72020-03-31 14:02:55 +0800111 action = parseI2CWriteByte(element["i2c_write_byte"]);
112 ++propertyCount;
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500113 }
114 else if (element.contains("i2c_write_bytes"))
115 {
Bob Kingbafcb862020-03-31 16:39:00 +0800116 action = parseI2CWriteBytes(element["i2c_write_bytes"]);
117 ++propertyCount;
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500118 }
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 {
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 {
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
171std::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
182std::vector<std::unique_ptr<Chassis>> parseChassisArray(const json& element)
183{
184 verifyIsArray(element);
185 std::vector<std::unique_ptr<Chassis>> chassis;
186 // TODO: Not implemented yet
187 // for (auto& chassisElement : element)
188 // {
189 // chassis.emplace_back(parseChassis(chassisElement));
190 // }
191 return chassis;
192}
193
Bob Kingbafcb862020-03-31 16:39:00 +0800194std::vector<uint8_t> parseHexByteArray(const json& element)
195{
196 verifyIsArray(element);
197 std::vector<uint8_t> values;
198 for (auto& valueElement : element)
199 {
200 values.emplace_back(parseHexByte(valueElement));
201 }
202 return values;
203}
204
Bob Kingf617f892020-03-30 19:03:35 +0800205std::unique_ptr<I2CWriteBitAction> parseI2CWriteBit(const json& element)
206{
207 verifyIsObject(element);
208 unsigned int propertyCount{0};
209
210 // Required register property
211 const json& regElement = getRequiredProperty(element, "register");
Bob Kingbafcb862020-03-31 16:39:00 +0800212 uint8_t reg = parseHexByte(regElement);
Bob Kingf617f892020-03-30 19:03:35 +0800213 ++propertyCount;
214
215 // Required position property
216 const json& positionElement = getRequiredProperty(element, "position");
217 uint8_t position = parseBitPosition(positionElement);
218 ++propertyCount;
219
220 // Required value property
221 const json& valueElement = getRequiredProperty(element, "value");
222 uint8_t value = parseBitValue(valueElement);
223 ++propertyCount;
224
225 // Verify no invalid properties exist
226 verifyPropertyCount(element, propertyCount);
227
228 return std::make_unique<I2CWriteBitAction>(reg, position, value);
229}
230
Bob King87ff9d72020-03-31 14:02:55 +0800231std::unique_ptr<I2CWriteByteAction> parseI2CWriteByte(const json& element)
232{
233 verifyIsObject(element);
234 unsigned int propertyCount{0};
235
236 // Required register property
237 const json& regElement = getRequiredProperty(element, "register");
Bob Kingbafcb862020-03-31 16:39:00 +0800238 uint8_t reg = parseHexByte(regElement);
Bob King87ff9d72020-03-31 14:02:55 +0800239 ++propertyCount;
240
241 // Required value property
242 const json& valueElement = getRequiredProperty(element, "value");
Bob Kingbafcb862020-03-31 16:39:00 +0800243 uint8_t value = parseHexByte(valueElement);
Bob King87ff9d72020-03-31 14:02:55 +0800244 ++propertyCount;
245
246 // Optional mask property
247 uint8_t mask = 0xff;
248 auto maskIt = element.find("mask");
249 if (maskIt != element.end())
250 {
Bob Kingbafcb862020-03-31 16:39:00 +0800251 mask = parseHexByte(*maskIt);
Bob King87ff9d72020-03-31 14:02:55 +0800252 ++propertyCount;
253 }
254
255 // Verify no invalid properties exist
256 verifyPropertyCount(element, propertyCount);
257
258 return std::make_unique<I2CWriteByteAction>(reg, value, mask);
259}
260
Bob Kingbafcb862020-03-31 16:39:00 +0800261std::unique_ptr<I2CWriteBytesAction> parseI2CWriteBytes(const json& element)
262{
263 verifyIsObject(element);
264 unsigned int propertyCount{0};
265
266 // Required register property
267 const json& regElement = getRequiredProperty(element, "register");
268 uint8_t reg = parseHexByte(regElement);
269 ++propertyCount;
270
271 // Required values property
272 const json& valueElement = getRequiredProperty(element, "values");
273 std::vector<uint8_t> values = parseHexByteArray(valueElement);
274 ++propertyCount;
275
276 // Optional masks property
277 std::vector<uint8_t> masks{};
278 auto masksIt = element.find("masks");
279 if (masksIt != element.end())
280 {
281 masks = parseHexByteArray(*masksIt);
282 ++propertyCount;
283 }
284
285 // Verify masks array (if specified) was same size as values array
286 if ((!masks.empty()) && (masks.size() != values.size()))
287 {
288 throw std::invalid_argument{"Invalid number of elements in masks"};
289 }
290
291 // Verify no invalid properties exist
292 verifyPropertyCount(element, propertyCount);
293
294 if (masks.empty())
295 {
296 return std::make_unique<I2CWriteBytesAction>(reg, values);
297 }
298 return std::make_unique<I2CWriteBytesAction>(reg, values, masks);
299}
300
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500301std::unique_ptr<PMBusWriteVoutCommandAction>
302 parsePMBusWriteVoutCommand(const json& element)
303{
304 verifyIsObject(element);
305 unsigned int propertyCount{0};
306
307 // Optional volts property
308 std::optional<double> volts{};
309 auto voltsIt = element.find("volts");
310 if (voltsIt != element.end())
311 {
312 volts = parseDouble(*voltsIt);
313 ++propertyCount;
314 }
315
316 // Required format property
317 const json& formatElement = getRequiredProperty(element, "format");
318 std::string formatString = parseString(formatElement);
319 if (formatString != "linear")
320 {
321 throw std::invalid_argument{"Invalid format value: " + formatString};
322 }
323 pmbus_utils::VoutDataFormat format = pmbus_utils::VoutDataFormat::linear;
324 ++propertyCount;
325
326 // Optional exponent property
327 std::optional<int8_t> exponent{};
328 auto exponentIt = element.find("exponent");
329 if (exponentIt != element.end())
330 {
331 exponent = parseInt8(*exponentIt);
332 ++propertyCount;
333 }
334
335 // Optional is_verified property
336 bool isVerified = false;
337 auto isVerifiedIt = element.find("is_verified");
338 if (isVerifiedIt != element.end())
339 {
340 isVerified = parseBoolean(*isVerifiedIt);
341 ++propertyCount;
342 }
343
344 // Verify no invalid properties exist
345 verifyPropertyCount(element, propertyCount);
346
347 return std::make_unique<PMBusWriteVoutCommandAction>(volts, format,
348 exponent, isVerified);
349}
350
351std::tuple<std::vector<std::unique_ptr<Rule>>,
352 std::vector<std::unique_ptr<Chassis>>>
353 parseRoot(const json& element)
354{
355 verifyIsObject(element);
356 unsigned int propertyCount{0};
357
358 // Optional comments property; value not stored
359 if (element.contains("comments"))
360 {
361 ++propertyCount;
362 }
363
364 // Optional rules property
365 std::vector<std::unique_ptr<Rule>> rules{};
366 auto rulesIt = element.find("rules");
367 if (rulesIt != element.end())
368 {
369 rules = parseRuleArray(*rulesIt);
370 ++propertyCount;
371 }
372
373 // Required chassis property
374 const json& chassisElement = getRequiredProperty(element, "chassis");
375 std::vector<std::unique_ptr<Chassis>> chassis =
376 parseChassisArray(chassisElement);
377 ++propertyCount;
378
379 // Verify no invalid properties exist
380 verifyPropertyCount(element, propertyCount);
381
382 return std::make_tuple(std::move(rules), std::move(chassis));
383}
384
385std::unique_ptr<Rule> parseRule(const json& element)
386{
387 verifyIsObject(element);
388 unsigned int propertyCount{0};
389
390 // Optional comments property; value not stored
391 if (element.contains("comments"))
392 {
393 ++propertyCount;
394 }
395
396 // Required id property
397 const json& idElement = getRequiredProperty(element, "id");
398 std::string id = parseString(idElement);
399 ++propertyCount;
400
401 // Required actions property
402 const json& actionsElement = getRequiredProperty(element, "actions");
403 std::vector<std::unique_ptr<Action>> actions =
404 parseActionArray(actionsElement);
405 ++propertyCount;
406
407 // Verify no invalid properties exist
408 verifyPropertyCount(element, propertyCount);
409
410 return std::make_unique<Rule>(id, std::move(actions));
411}
412
413std::vector<std::unique_ptr<Rule>> parseRuleArray(const json& element)
414{
415 verifyIsArray(element);
416 std::vector<std::unique_ptr<Rule>> rules;
417 for (auto& ruleElement : element)
418 {
419 rules.emplace_back(parseRule(ruleElement));
420 }
421 return rules;
422}
423
Bob King315b0b62020-04-03 21:47:58 +0800424std::unique_ptr<RunRuleAction> parseRunRule(const json& element)
425{
426 // String ruleID
427 std::string ruleID = parseString(element);
428
429 return std::make_unique<RunRuleAction>(ruleID);
430}
431
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500432} // namespace internal
433
434} // namespace phosphor::power::regulators::config_file_parser