blob: 791f3f77792add056f15e79132159ab03a2b253e [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 {
116 // TODO: Not implemented yet
117 // action = parseI2CWriteBytes(element["i2c_write_bytes"]);
118 // ++propertyCount;
119 }
120 else if (element.contains("if"))
121 {
122 // TODO: Not implemented yet
123 // action = parseIf(element["if"]);
124 // ++propertyCount;
125 }
126 else if (element.contains("not"))
127 {
128 // TODO: Not implemented yet
129 // action = parseNot(element["not"]);
130 // ++propertyCount;
131 }
132 else if (element.contains("or"))
133 {
134 // TODO: Not implemented yet
135 // action = parseOr(element["or"]);
136 // ++propertyCount;
137 }
138 else if (element.contains("pmbus_read_sensor"))
139 {
140 // TODO: Not implemented yet
141 // action = parsePMBusReadSensor(element["pmbus_read_sensor"]);
142 // ++propertyCount;
143 }
144 else if (element.contains("pmbus_write_vout_command"))
145 {
146 action =
147 parsePMBusWriteVoutCommand(element["pmbus_write_vout_command"]);
148 ++propertyCount;
149 }
150 else if (element.contains("run_rule"))
151 {
152 // TODO: Not implemented yet
153 // action = parseRunRule(element["run_rule"]);
154 // ++propertyCount;
155 }
156 else if (element.contains("set_device"))
157 {
158 // TODO: Not implemented yet
159 // action = parseSetDevice(element["set_device"]);
160 // ++propertyCount;
161 }
162 else
163 {
164 throw std::invalid_argument{"Required action type property missing"};
165 }
166
167 // Verify no invalid properties exist
168 verifyPropertyCount(element, propertyCount);
169
170 return action;
171}
172
173std::vector<std::unique_ptr<Action>> parseActionArray(const json& element)
174{
175 verifyIsArray(element);
176 std::vector<std::unique_ptr<Action>> actions;
177 for (auto& actionElement : element)
178 {
179 actions.emplace_back(parseAction(actionElement));
180 }
181 return actions;
182}
183
184std::vector<std::unique_ptr<Chassis>> parseChassisArray(const json& element)
185{
186 verifyIsArray(element);
187 std::vector<std::unique_ptr<Chassis>> chassis;
188 // TODO: Not implemented yet
189 // for (auto& chassisElement : element)
190 // {
191 // chassis.emplace_back(parseChassis(chassisElement));
192 // }
193 return chassis;
194}
195
Bob Kingf617f892020-03-30 19:03:35 +0800196std::unique_ptr<I2CWriteBitAction> parseI2CWriteBit(const json& element)
197{
198 verifyIsObject(element);
199 unsigned int propertyCount{0};
200
201 // Required register property
202 const json& regElement = getRequiredProperty(element, "register");
203 uint8_t reg = parseStringToUint8(regElement);
204 ++propertyCount;
205
206 // Required position property
207 const json& positionElement = getRequiredProperty(element, "position");
208 uint8_t position = parseBitPosition(positionElement);
209 ++propertyCount;
210
211 // Required value property
212 const json& valueElement = getRequiredProperty(element, "value");
213 uint8_t value = parseBitValue(valueElement);
214 ++propertyCount;
215
216 // Verify no invalid properties exist
217 verifyPropertyCount(element, propertyCount);
218
219 return std::make_unique<I2CWriteBitAction>(reg, position, value);
220}
221
Bob King87ff9d72020-03-31 14:02:55 +0800222std::unique_ptr<I2CWriteByteAction> parseI2CWriteByte(const json& element)
223{
224 verifyIsObject(element);
225 unsigned int propertyCount{0};
226
227 // Required register property
228 const json& regElement = getRequiredProperty(element, "register");
229 uint8_t reg = parseStringToUint8(regElement);
230 ++propertyCount;
231
232 // Required value property
233 const json& valueElement = getRequiredProperty(element, "value");
234 uint8_t value = parseStringToUint8(valueElement);
235 ++propertyCount;
236
237 // Optional mask property
238 uint8_t mask = 0xff;
239 auto maskIt = element.find("mask");
240 if (maskIt != element.end())
241 {
242 mask = parseStringToUint8(*maskIt);
243 ++propertyCount;
244 }
245
246 // Verify no invalid properties exist
247 verifyPropertyCount(element, propertyCount);
248
249 return std::make_unique<I2CWriteByteAction>(reg, value, mask);
250}
251
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500252std::unique_ptr<PMBusWriteVoutCommandAction>
253 parsePMBusWriteVoutCommand(const json& element)
254{
255 verifyIsObject(element);
256 unsigned int propertyCount{0};
257
258 // Optional volts property
259 std::optional<double> volts{};
260 auto voltsIt = element.find("volts");
261 if (voltsIt != element.end())
262 {
263 volts = parseDouble(*voltsIt);
264 ++propertyCount;
265 }
266
267 // Required format property
268 const json& formatElement = getRequiredProperty(element, "format");
269 std::string formatString = parseString(formatElement);
270 if (formatString != "linear")
271 {
272 throw std::invalid_argument{"Invalid format value: " + formatString};
273 }
274 pmbus_utils::VoutDataFormat format = pmbus_utils::VoutDataFormat::linear;
275 ++propertyCount;
276
277 // Optional exponent property
278 std::optional<int8_t> exponent{};
279 auto exponentIt = element.find("exponent");
280 if (exponentIt != element.end())
281 {
282 exponent = parseInt8(*exponentIt);
283 ++propertyCount;
284 }
285
286 // Optional is_verified property
287 bool isVerified = false;
288 auto isVerifiedIt = element.find("is_verified");
289 if (isVerifiedIt != element.end())
290 {
291 isVerified = parseBoolean(*isVerifiedIt);
292 ++propertyCount;
293 }
294
295 // Verify no invalid properties exist
296 verifyPropertyCount(element, propertyCount);
297
298 return std::make_unique<PMBusWriteVoutCommandAction>(volts, format,
299 exponent, isVerified);
300}
301
302std::tuple<std::vector<std::unique_ptr<Rule>>,
303 std::vector<std::unique_ptr<Chassis>>>
304 parseRoot(const json& element)
305{
306 verifyIsObject(element);
307 unsigned int propertyCount{0};
308
309 // Optional comments property; value not stored
310 if (element.contains("comments"))
311 {
312 ++propertyCount;
313 }
314
315 // Optional rules property
316 std::vector<std::unique_ptr<Rule>> rules{};
317 auto rulesIt = element.find("rules");
318 if (rulesIt != element.end())
319 {
320 rules = parseRuleArray(*rulesIt);
321 ++propertyCount;
322 }
323
324 // Required chassis property
325 const json& chassisElement = getRequiredProperty(element, "chassis");
326 std::vector<std::unique_ptr<Chassis>> chassis =
327 parseChassisArray(chassisElement);
328 ++propertyCount;
329
330 // Verify no invalid properties exist
331 verifyPropertyCount(element, propertyCount);
332
333 return std::make_tuple(std::move(rules), std::move(chassis));
334}
335
336std::unique_ptr<Rule> parseRule(const json& element)
337{
338 verifyIsObject(element);
339 unsigned int propertyCount{0};
340
341 // Optional comments property; value not stored
342 if (element.contains("comments"))
343 {
344 ++propertyCount;
345 }
346
347 // Required id property
348 const json& idElement = getRequiredProperty(element, "id");
349 std::string id = parseString(idElement);
350 ++propertyCount;
351
352 // Required actions property
353 const json& actionsElement = getRequiredProperty(element, "actions");
354 std::vector<std::unique_ptr<Action>> actions =
355 parseActionArray(actionsElement);
356 ++propertyCount;
357
358 // Verify no invalid properties exist
359 verifyPropertyCount(element, propertyCount);
360
361 return std::make_unique<Rule>(id, std::move(actions));
362}
363
364std::vector<std::unique_ptr<Rule>> parseRuleArray(const json& element)
365{
366 verifyIsArray(element);
367 std::vector<std::unique_ptr<Rule>> rules;
368 for (auto& ruleElement : element)
369 {
370 rules.emplace_back(parseRule(ruleElement));
371 }
372 return rules;
373}
374
375} // namespace internal
376
377} // namespace phosphor::power::regulators::config_file_parser