1 #pragma once
2
3 #include "error_codes.hpp"
4 #include "event_logger.hpp"
5 #include "exceptions.hpp"
6 #include "logger.hpp"
7 #include "types.hpp"
8
9 #include <gpiod.hpp>
10 #include <nlohmann/json.hpp>
11 #include <utility/common_utility.hpp>
12 #include <utility/vpd_specific_utility.hpp>
13
14 #include <fstream>
15 #include <type_traits>
16 #include <unordered_map>
17
18 namespace vpd
19 {
20 namespace jsonUtility
21 {
22
23 // forward declaration of API for function map.
24 bool processSystemCmdTag(
25 const nlohmann::json& i_parsedConfigJson, const std::string& i_vpdFilePath,
26 const std::string& i_baseAction, const std::string& i_flagToProcess,
27 uint16_t& o_errCode);
28
29 // forward declaration of API for function map.
30 bool processGpioPresenceTag(
31 const nlohmann::json& i_parsedConfigJson, const std::string& i_vpdFilePath,
32 const std::string& i_baseAction, const std::string& i_flagToProcess,
33 uint16_t& o_errCode);
34
35 // forward declaration of API for function map.
36 bool procesSetGpioTag(const nlohmann::json& i_parsedConfigJson,
37 const std::string& i_vpdFilePath,
38 const std::string& i_baseAction,
39 const std::string& i_flagToProcess, uint16_t& o_errCode);
40
41 // Function pointers to process tags from config JSON.
42 typedef bool (*functionPtr)(
43 const nlohmann::json& i_parsedConfigJson, const std::string& i_vpdFilePath,
44 const std::string& i_baseAction, const std::string& i_flagToProcess,
45 uint16_t& o_errCode);
46
47 inline std::unordered_map<std::string, functionPtr> funcionMap{
48 {"gpioPresence", processGpioPresenceTag},
49 {"setGpio", procesSetGpioTag},
50 {"systemCmd", processSystemCmdTag}};
51
52 /**
53 * @brief API to read VPD offset from JSON file.
54 *
55 * @param[in] i_sysCfgJsonObj - Parsed system config JSON object.
56 * @param[in] i_vpdFilePath - VPD file path.
57 * @param[in] o_errCode - To set error code in case of error.
58 * @return VPD offset if found in JSON, 0 otherwise.
59 */
getVPDOffset(const nlohmann::json & i_sysCfgJsonObj,const std::string & i_vpdFilePath,uint16_t & o_errCode)60 inline size_t getVPDOffset(const nlohmann::json& i_sysCfgJsonObj,
61 const std::string& i_vpdFilePath,
62 uint16_t& o_errCode)
63 {
64 if (i_vpdFilePath.empty() || (i_sysCfgJsonObj.empty()) ||
65 (!i_sysCfgJsonObj.contains("frus")))
66 {
67 o_errCode = error_code::INVALID_INPUT_PARAMETER;
68 return 0;
69 }
70
71 if (i_sysCfgJsonObj["frus"].contains(i_vpdFilePath))
72 {
73 return i_sysCfgJsonObj["frus"][i_vpdFilePath].at(0).value("offset", 0);
74 }
75
76 const nlohmann::json& l_fruList =
77 i_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
78
79 for (const auto& l_fru : l_fruList.items())
80 {
81 const auto l_fruPath = l_fru.key();
82
83 // check if given path is redundant FRU path
84 if (i_vpdFilePath == i_sysCfgJsonObj["frus"][l_fruPath].at(0).value(
85 "redundantEeprom", ""))
86 {
87 // Return the offset of redundant EEPROM taken from JSON.
88 return i_sysCfgJsonObj["frus"][l_fruPath].at(0).value("offset", 0);
89 }
90 }
91
92 return 0;
93 }
94
95 /**
96 * @brief API to parse respective JSON.
97 *
98 * @param[in] pathToJson - Path to JSON.
99 * @param[out] o_errCode - To set error code in case of error.
100 * @return on success parsed JSON. On failure empty JSON object.
101 *
102 * Note: Caller has to handle it in case an empty JSON object is received.
103 */
getParsedJson(const std::string & pathToJson,uint16_t & o_errCode)104 inline nlohmann::json getParsedJson(const std::string& pathToJson,
105 uint16_t& o_errCode) noexcept
106 {
107 if (pathToJson.empty())
108 {
109 o_errCode = error_code::INVALID_INPUT_PARAMETER;
110 return nlohmann::json{};
111 }
112
113 if (!std::filesystem::exists(pathToJson))
114 {
115 o_errCode = error_code::FILE_NOT_FOUND;
116 return nlohmann::json{};
117 }
118
119 if (std::filesystem::is_empty(pathToJson))
120 {
121 o_errCode = error_code::EMPTY_FILE;
122 return nlohmann::json{};
123 }
124
125 std::ifstream l_jsonFile(pathToJson);
126 if (!l_jsonFile)
127 {
128 o_errCode = error_code::FILE_ACCESS_ERROR;
129 return nlohmann::json{};
130 }
131
132 try
133 {
134 return nlohmann::json::parse(l_jsonFile);
135 }
136 catch (const std::exception& l_ex)
137 {
138 o_errCode = error_code::JSON_PARSE_ERROR;
139 return nlohmann::json{};
140 }
141 }
142
143 /**
144 * @brief Get inventory object path from system config JSON.
145 *
146 * Given either D-bus inventory path/FRU EEPROM path/redundant EEPROM path,
147 * this API returns D-bus inventory path if present in JSON.
148 *
149 * @param[in] i_sysCfgJsonObj - System config JSON object
150 * @param[in] i_vpdPath - Path to where VPD is stored.
151 * @param[in] o_errCode - To set error code in case of error.
152 *
153 * @return On success a valid path is returned, on failure an empty string is
154 * returned.
155 *
156 * Note: Caller has to handle it in case an empty string is received.
157 */
getInventoryObjPathFromJson(const nlohmann::json & i_sysCfgJsonObj,const std::string & i_vpdPath,uint16_t & o_errCode)158 inline std::string getInventoryObjPathFromJson(
159 const nlohmann::json& i_sysCfgJsonObj, const std::string& i_vpdPath,
160 uint16_t& o_errCode) noexcept
161 {
162 if (i_vpdPath.empty())
163 {
164 o_errCode = error_code::INVALID_INPUT_PARAMETER;
165 return std::string{};
166 }
167
168 if (!i_sysCfgJsonObj.contains("frus"))
169 {
170 o_errCode = error_code::INVALID_JSON;
171 return std::string{};
172 }
173
174 // check if given path is FRU path
175 if (i_sysCfgJsonObj["frus"].contains(i_vpdPath))
176 {
177 return i_sysCfgJsonObj["frus"][i_vpdPath].at(0).value(
178 "inventoryPath", "");
179 }
180
181 const nlohmann::json& l_fruList =
182 i_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
183
184 for (const auto& l_fru : l_fruList.items())
185 {
186 const auto l_fruPath = l_fru.key();
187 const auto l_invObjPath =
188 i_sysCfgJsonObj["frus"][l_fruPath].at(0).value("inventoryPath", "");
189
190 // check if given path is redundant FRU path or inventory path
191 if (i_vpdPath == i_sysCfgJsonObj["frus"][l_fruPath].at(0).value(
192 "redundantEeprom", "") ||
193 (i_vpdPath == l_invObjPath))
194 {
195 return l_invObjPath;
196 }
197 }
198
199 return std::string{};
200 }
201
202 /**
203 * @brief Process "PostFailAction" defined in config JSON.
204 *
205 * In case there is some error in the processing of "preAction" execution and a
206 * set of procedure needs to be done as a part of post fail action. This base
207 * action can be defined in the config JSON for that FRU and it will be handled
208 * under this API.
209 *
210 * @param[in] i_parsedConfigJson - config JSON
211 * @param[in] i_vpdFilePath - EEPROM file path
212 * @param[in] i_flagToProcess - To identify which flag(s) needs to be processed
213 * @param[out] o_errCode - To set error code in case of error
214 * under PostFailAction tag of config JSON.
215 * @return - success or failure
216 */
executePostFailAction(const nlohmann::json & i_parsedConfigJson,const std::string & i_vpdFilePath,const std::string & i_flagToProcess,uint16_t & o_errCode)217 inline bool executePostFailAction(
218 const nlohmann::json& i_parsedConfigJson, const std::string& i_vpdFilePath,
219 const std::string& i_flagToProcess, uint16_t& o_errCode)
220 {
221 if (i_parsedConfigJson.empty() || i_vpdFilePath.empty() ||
222 i_flagToProcess.empty())
223 {
224 o_errCode = error_code::INVALID_INPUT_PARAMETER;
225 return false;
226 }
227
228 if (!i_parsedConfigJson.contains("frus"))
229 {
230 o_errCode = error_code::INVALID_JSON;
231 return false;
232 }
233
234 if (!i_parsedConfigJson["frus"].contains(i_vpdFilePath))
235 {
236 o_errCode = error_code::FRU_PATH_NOT_FOUND;
237 return false;
238 }
239
240 if (!i_parsedConfigJson["frus"][i_vpdFilePath].at(0).contains(
241 "postFailAction"))
242 {
243 o_errCode = error_code::MISSING_ACTION_TAG;
244 return false;
245 }
246
247 if (!(i_parsedConfigJson["frus"][i_vpdFilePath].at(0))["postFailAction"]
248 .contains(i_flagToProcess))
249 {
250 o_errCode = error_code::MISSING_FLAG;
251 return false;
252 }
253
254 for (const auto& l_tags : (i_parsedConfigJson["frus"][i_vpdFilePath].at(
255 0))["postFailAction"][i_flagToProcess]
256 .items())
257 {
258 auto itrToFunction = funcionMap.find(l_tags.key());
259 if (itrToFunction != funcionMap.end())
260 {
261 if (!itrToFunction->second(i_parsedConfigJson, i_vpdFilePath,
262 "postFailAction", i_flagToProcess,
263 o_errCode))
264 {
265 if (o_errCode)
266 {
267 logging::logMessage(
268 l_tags.key() + " failed for [" + i_vpdFilePath +
269 "]. Reason " +
270 vpdSpecificUtility::getErrCodeMsg(o_errCode));
271 }
272 return false;
273 }
274 }
275 }
276
277 return true;
278 }
279
280 /**
281 * @brief Process "systemCmd" tag for a given FRU.
282 *
283 * The API will process "systemCmd" tag if it is defined in the config
284 * JSON for the given FRU.
285 *
286 * @param[in] i_parsedConfigJson - config JSON
287 * @param[in] i_vpdFilePath - EEPROM file path
288 * @param[in] i_baseAction - Base action for which this tag has been called.
289 * @param[in] i_flagToProcess - Flag nested under the base action for which this
290 * tag has been called.
291 * @param[out] o_errCode - To set error code in case of error.
292 * @return Execution status.
293 */
processSystemCmdTag(const nlohmann::json & i_parsedConfigJson,const std::string & i_vpdFilePath,const std::string & i_baseAction,const std::string & i_flagToProcess,uint16_t & o_errCode)294 inline bool processSystemCmdTag(
295 const nlohmann::json& i_parsedConfigJson, const std::string& i_vpdFilePath,
296 const std::string& i_baseAction, const std::string& i_flagToProcess,
297 uint16_t& o_errCode)
298 {
299 if (i_vpdFilePath.empty() || i_parsedConfigJson.empty() ||
300 i_baseAction.empty() || i_flagToProcess.empty())
301 {
302 o_errCode = error_code::INVALID_INPUT_PARAMETER;
303 return false;
304 }
305
306 try
307 {
308 if (!((i_parsedConfigJson["frus"][i_vpdFilePath].at(
309 0)[i_baseAction][i_flagToProcess]["systemCmd"])
310 .contains("cmd")))
311 {
312 o_errCode = error_code::MISSING_FLAG;
313 return false;
314 }
315
316 const std::string& l_systemCommand =
317 i_parsedConfigJson["frus"][i_vpdFilePath].at(
318 0)[i_baseAction][i_flagToProcess]["systemCmd"]["cmd"];
319
320 commonUtility::executeCmd(l_systemCommand);
321 }
322 catch (const std::exception& l_ex)
323 {
324 o_errCode = error_code::ERROR_PROCESSING_SYSTEM_CMD;
325 return false;
326 }
327 return true;
328 }
329
330 /**
331 * @brief Checks for presence of a given FRU using GPIO line.
332 *
333 * This API returns the presence information of the FRU corresponding to the
334 * given VPD file path by setting the presence pin.
335 *
336 * @param[in] i_parsedConfigJson - config JSON
337 * @param[in] i_vpdFilePath - EEPROM file path
338 * @param[in] i_baseAction - Base action for which this tag has been called.
339 * @param[in] i_flagToProcess - Flag nested under the base action for which this
340 * tag has been called.
341 * @param[out] o_errCode - To set error code in case of error
342 * @return Execution status.
343 */
processGpioPresenceTag(const nlohmann::json & i_parsedConfigJson,const std::string & i_vpdFilePath,const std::string & i_baseAction,const std::string & i_flagToProcess,uint16_t & o_errCode)344 inline bool processGpioPresenceTag(
345 const nlohmann::json& i_parsedConfigJson, const std::string& i_vpdFilePath,
346 const std::string& i_baseAction, const std::string& i_flagToProcess,
347 uint16_t& o_errCode)
348 {
349 std::string l_presencePinName;
350 try
351 {
352 if (i_vpdFilePath.empty() || i_parsedConfigJson.empty() ||
353 i_baseAction.empty() || i_flagToProcess.empty())
354 {
355 o_errCode = error_code::INVALID_INPUT_PARAMETER;
356 return false;
357 }
358
359 if (!(((i_parsedConfigJson["frus"][i_vpdFilePath].at(
360 0)[i_baseAction][i_flagToProcess]["gpioPresence"])
361 .contains("pin")) &&
362 ((i_parsedConfigJson["frus"][i_vpdFilePath].at(
363 0)[i_baseAction][i_flagToProcess]["gpioPresence"])
364 .contains("value"))))
365 {
366 o_errCode = error_code::JSON_MISSING_GPIO_INFO;
367 return false;
368 }
369
370 // get the pin name
371 l_presencePinName = i_parsedConfigJson["frus"][i_vpdFilePath].at(
372 0)[i_baseAction][i_flagToProcess]["gpioPresence"]["pin"];
373
374 // get the pin value
375 uint8_t l_presencePinValue =
376 i_parsedConfigJson["frus"][i_vpdFilePath].at(
377 0)[i_baseAction][i_flagToProcess]["gpioPresence"]["value"];
378
379 gpiod::line l_presenceLine = gpiod::find_line(l_presencePinName);
380
381 if (!l_presenceLine)
382 {
383 o_errCode = error_code::DEVICE_PRESENCE_UNKNOWN;
384 throw GpioException("Couldn't find the GPIO line.");
385 }
386
387 l_presenceLine.request({"Read the presence line",
388 gpiod::line_request::DIRECTION_INPUT, 0});
389
390 if (l_presencePinValue != l_presenceLine.get_value())
391 {
392 // As false is being returned in this case, caller needs to know
393 // that it is not due to some exception. It is because the pin was
394 // read correctly but was not having expected value.
395 o_errCode = error_code::DEVICE_NOT_PRESENT;
396 return false;
397 }
398
399 return true;
400 }
401 catch (const std::exception& l_ex)
402 {
403 std::string l_errMsg = "Exception on GPIO line: ";
404 l_errMsg += l_presencePinName;
405 l_errMsg += " Reason: ";
406 l_errMsg += l_ex.what();
407 l_errMsg += " File: " + i_vpdFilePath + " Pel Logged";
408
409 uint16_t l_errCode = 0;
410
411 // ToDo -- Update Internal Rc code.
412 EventLogger::createAsyncPelWithInventoryCallout(
413 EventLogger::getErrorType(l_ex), types::SeverityType::Informational,
414 {{getInventoryObjPathFromJson(i_parsedConfigJson, i_vpdFilePath,
415 l_errCode),
416 types::CalloutPriority::High}},
417 std::source_location::current().file_name(),
418 std::source_location::current().function_name(), 0, l_errMsg,
419 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
420
421 logging::logMessage(l_errMsg);
422
423 // Except when GPIO pin value is false, we go and try collecting the
424 // FRU VPD as we couldn't able to read GPIO pin value due to some
425 // error/exception. So returning true in error scenario.
426 return true;
427 }
428 }
429
430 /**
431 * @brief Process "setGpio" tag for a given FRU.
432 *
433 * This API enables the GPIO line.
434 *
435 * @param[in] i_parsedConfigJson - config JSON
436 * @param[in] i_vpdFilePath - EEPROM file path
437 * @param[in] i_baseAction - Base action for which this tag has been called.
438 * @param[in] i_flagToProcess - Flag nested under the base action for which this
439 * tag has been called.
440 * @param[out] o_errCode - To set error code in case of error
441 * @return Execution status.
442 */
procesSetGpioTag(const nlohmann::json & i_parsedConfigJson,const std::string & i_vpdFilePath,const std::string & i_baseAction,const std::string & i_flagToProcess,uint16_t & o_errCode)443 inline bool procesSetGpioTag(
444 const nlohmann::json& i_parsedConfigJson, const std::string& i_vpdFilePath,
445 const std::string& i_baseAction, const std::string& i_flagToProcess,
446 uint16_t& o_errCode)
447 {
448 std::string l_pinName;
449 try
450 {
451 if (i_vpdFilePath.empty() || i_parsedConfigJson.empty() ||
452 i_baseAction.empty() || i_flagToProcess.empty())
453 {
454 o_errCode = error_code::INVALID_INPUT_PARAMETER;
455 return false;
456 }
457
458 if (!(((i_parsedConfigJson["frus"][i_vpdFilePath].at(
459 0)[i_baseAction][i_flagToProcess]["setGpio"])
460 .contains("pin")) &&
461 ((i_parsedConfigJson["frus"][i_vpdFilePath].at(
462 0)[i_baseAction][i_flagToProcess]["setGpio"])
463 .contains("value"))))
464 {
465 o_errCode = error_code::JSON_MISSING_GPIO_INFO;
466 return false;
467 }
468
469 l_pinName = i_parsedConfigJson["frus"][i_vpdFilePath].at(
470 0)[i_baseAction][i_flagToProcess]["setGpio"]["pin"];
471
472 // Get the value to set
473 uint8_t l_pinValue = i_parsedConfigJson["frus"][i_vpdFilePath].at(
474 0)[i_baseAction][i_flagToProcess]["setGpio"]["value"];
475
476 logging::logMessage(
477 "Setting GPIO: " + l_pinName + " to " + std::to_string(l_pinValue));
478
479 gpiod::line l_outputLine = gpiod::find_line(l_pinName);
480
481 if (!l_outputLine)
482 {
483 o_errCode = error_code::GPIO_LINE_EXCEPTION;
484 throw GpioException("Couldn't find GPIO line.");
485 }
486
487 l_outputLine.request(
488 {"FRU Action", ::gpiod::line_request::DIRECTION_OUTPUT, 0},
489 l_pinValue);
490 return true;
491 }
492 catch (const std::exception& l_ex)
493 {
494 std::string l_errMsg = "Exception on GPIO line: ";
495 l_errMsg += l_pinName;
496 l_errMsg += " Reason: ";
497 l_errMsg += l_ex.what();
498 l_errMsg += " File: " + i_vpdFilePath + " Pel Logged";
499
500 uint16_t l_errCode = 0;
501
502 // ToDo -- Update Internal RC code
503 EventLogger::createAsyncPelWithInventoryCallout(
504 EventLogger::getErrorType(l_ex), types::SeverityType::Informational,
505 {{getInventoryObjPathFromJson(i_parsedConfigJson, i_vpdFilePath,
506 l_errCode),
507 types::CalloutPriority::High}},
508 std::source_location::current().file_name(),
509 std::source_location::current().function_name(), 0, l_errMsg,
510 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
511
512 logging::logMessage(l_errMsg);
513
514 return false;
515 }
516 }
517
518 /**
519 * @brief Process any action, if defined in config JSON.
520 *
521 * If any FRU(s) requires any special handling, then this base action can be
522 * defined for that FRU in the config JSON, processing of which will be handled
523 * in this API.
524 * Examples of action - preAction, PostAction etc.
525 *
526 * @param[in] i_parsedConfigJson - config JSON
527 * @param[in] i_action - Base action to be performed.
528 * @param[in] i_vpdFilePath - EEPROM file path
529 * @param[in] i_flagToProcess - To identify which flag(s) needs to be processed
530 * under PreAction tag of config JSON.
531 * @param[out] o_errCode - To set error code in case of error.
532 * @return - success or failure
533 */
executeBaseAction(const nlohmann::json & i_parsedConfigJson,const std::string & i_action,const std::string & i_vpdFilePath,const std::string & i_flagToProcess,uint16_t & o_errCode)534 inline bool executeBaseAction(
535 const nlohmann::json& i_parsedConfigJson, const std::string& i_action,
536 const std::string& i_vpdFilePath, const std::string& i_flagToProcess,
537 uint16_t& o_errCode)
538 {
539 if (i_flagToProcess.empty() || i_action.empty() || i_vpdFilePath.empty() ||
540 !i_parsedConfigJson.contains("frus"))
541 {
542 o_errCode = error_code::INVALID_INPUT_PARAMETER;
543 return false;
544 }
545 if (!i_parsedConfigJson["frus"].contains(i_vpdFilePath))
546 {
547 o_errCode = error_code::FILE_NOT_FOUND;
548 return false;
549 }
550 if (!i_parsedConfigJson["frus"][i_vpdFilePath].at(0).contains(i_action))
551 {
552 o_errCode = error_code::MISSING_ACTION_TAG;
553 return false;
554 }
555
556 if (!(i_parsedConfigJson["frus"][i_vpdFilePath].at(0))[i_action].contains(
557 i_flagToProcess))
558 {
559 o_errCode = error_code::MISSING_FLAG;
560 return false;
561 }
562
563 const nlohmann::json& l_tagsJson =
564 (i_parsedConfigJson["frus"][i_vpdFilePath].at(
565 0))[i_action][i_flagToProcess];
566
567 for (const auto& l_tag : l_tagsJson.items())
568 {
569 auto itrToFunction = funcionMap.find(l_tag.key());
570 if (itrToFunction != funcionMap.end())
571 {
572 if (!itrToFunction->second(i_parsedConfigJson, i_vpdFilePath,
573 i_action, i_flagToProcess, o_errCode))
574 {
575 // In case any of the tag fails to execute. Mark action
576 // as failed for that flag.
577 if (o_errCode)
578 {
579 logging::logMessage(
580 l_tag.key() + " failed for [" + i_vpdFilePath +
581 "]. Reason " +
582 vpdSpecificUtility::getErrCodeMsg(o_errCode));
583 }
584 return false;
585 }
586 }
587 }
588
589 return true;
590 }
591
592 /**
593 * @brief Get redundant FRU path from system config JSON
594 *
595 * Given either D-bus inventory path/FRU path/redundant FRU path, this
596 * API returns the redundant FRU path taken from "redundantEeprom" tag from
597 * system config JSON.
598 *
599 * @param[in] i_sysCfgJsonObj - System config JSON object.
600 * @param[in] i_vpdPath - Path to where VPD is stored.
601 * @param[out] o_errCode - To set error code in case of error.
602 *
603 * @return On success return valid path, on failure return empty string.
604 */
getRedundantEepromPathFromJson(const nlohmann::json & i_sysCfgJsonObj,const std::string & i_vpdPath,uint16_t & o_errCode)605 inline std::string getRedundantEepromPathFromJson(
606 const nlohmann::json& i_sysCfgJsonObj, const std::string& i_vpdPath,
607 uint16_t& o_errCode)
608 {
609 if (i_vpdPath.empty())
610 {
611 o_errCode = error_code::INVALID_INPUT_PARAMETER;
612 return std::string{};
613 }
614
615 if (!i_sysCfgJsonObj.contains("frus"))
616 {
617 o_errCode = error_code::INVALID_JSON;
618 return std::string{};
619 }
620
621 // check if given path is FRU path
622 if (i_sysCfgJsonObj["frus"].contains(i_vpdPath))
623 {
624 return i_sysCfgJsonObj["frus"][i_vpdPath].at(0).value(
625 "redundantEeprom", "");
626 }
627
628 const nlohmann::json& l_fruList =
629 i_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
630
631 for (const auto& l_fru : l_fruList.items())
632 {
633 const std::string& l_fruPath = l_fru.key();
634 const std::string& l_redundantFruPath =
635 i_sysCfgJsonObj["frus"][l_fruPath].at(0).value("redundantEeprom",
636 "");
637
638 // check if given path is inventory path or redundant FRU path
639 if ((i_sysCfgJsonObj["frus"][l_fruPath].at(0).value("inventoryPath",
640 "") == i_vpdPath) ||
641 (l_redundantFruPath == i_vpdPath))
642 {
643 return l_redundantFruPath;
644 }
645 }
646
647 return std::string();
648 }
649
650 /**
651 * @brief Get FRU EEPROM path from system config JSON
652 *
653 * Given either D-bus inventory path/FRU EEPROM path/redundant EEPROM path,
654 * this API returns FRU EEPROM path if present in JSON.
655 *
656 * @param[in] i_sysCfgJsonObj - System config JSON object
657 * @param[in] i_vpdPath - Path to where VPD is stored.
658 * @param[out] o_errCode - To set error code in case of error.
659 *
660 * @return On success return valid path, on failure return empty string.
661 */
getFruPathFromJson(const nlohmann::json & i_sysCfgJsonObj,const std::string & i_vpdPath,uint16_t & o_errCode)662 inline std::string getFruPathFromJson(const nlohmann::json& i_sysCfgJsonObj,
663 const std::string& i_vpdPath,
664 uint16_t& o_errCode)
665 {
666 if (i_vpdPath.empty())
667 {
668 o_errCode = error_code::INVALID_INPUT_PARAMETER;
669 return std::string{};
670 }
671
672 if (!i_sysCfgJsonObj.contains("frus"))
673 {
674 o_errCode = error_code::INVALID_JSON;
675 return std::string{};
676 }
677
678 // check if given path is FRU path
679 if (i_sysCfgJsonObj["frus"].contains(i_vpdPath))
680 {
681 return i_vpdPath;
682 }
683
684 const nlohmann::json& l_fruList =
685 i_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
686
687 for (const auto& l_fru : l_fruList.items())
688 {
689 const auto l_fruPath = l_fru.key();
690
691 // check if given path is redundant FRU path or inventory path
692 if (i_vpdPath == i_sysCfgJsonObj["frus"][l_fruPath].at(0).value(
693 "redundantEeprom", "") ||
694 (i_vpdPath == i_sysCfgJsonObj["frus"][l_fruPath].at(0).value(
695 "inventoryPath", "")))
696 {
697 return l_fruPath;
698 }
699 }
700
701 return std::string();
702 }
703
704 /**
705 * @brief An API to check backup and restore VPD is required.
706 *
707 * The API checks if there is provision for backup and restore mentioned in the
708 * system config JSON, by looking "backupRestoreConfigPath" tag.
709 * Checks if the path mentioned is a hardware path, by checking if the file path
710 * exists and size of contents in the path.
711 *
712 * @param[in] i_sysCfgJsonObj - System config JSON object.
713 * @param[out] o_errCode - To set error code in case of error.
714 *
715 * @return true if backup and restore is required, false otherwise.
716 */
isBackupAndRestoreRequired(const nlohmann::json & i_sysCfgJsonObj,uint16_t & o_errCode)717 inline bool isBackupAndRestoreRequired(const nlohmann::json& i_sysCfgJsonObj,
718 uint16_t& o_errCode)
719 {
720 if (i_sysCfgJsonObj.empty())
721 {
722 o_errCode = error_code::INVALID_INPUT_PARAMETER;
723 return false;
724 }
725
726 const std::string& l_backupAndRestoreCfgFilePath =
727 i_sysCfgJsonObj.value("backupRestoreConfigPath", "");
728
729 if (!l_backupAndRestoreCfgFilePath.empty() &&
730 std::filesystem::exists(l_backupAndRestoreCfgFilePath) &&
731 !std::filesystem::is_empty(l_backupAndRestoreCfgFilePath))
732 {
733 return true;
734 }
735
736 return false;
737 }
738
739 /** @brief API to check if an action is required for given EEPROM path.
740 *
741 * System config JSON can contain pre-action, post-action etc. like actions
742 * defined for an EEPROM path. The API will check if any such action is defined
743 * for the EEPROM.
744 *
745 * @param[in] i_sysCfgJsonObj - System config JSON object.
746 * @param[in] i_vpdFruPath - EEPROM path.
747 * @param[in] i_action - Action to be checked.
748 * @param[in] i_flowFlag - Denotes the flow w.r.t which the action should be
749 * triggered.
750 * @param[out] o_errCode - To set error code in case of error.
751 * @return - True if action is defined for the flow, false otherwise.
752 */
isActionRequired(const nlohmann::json & i_sysCfgJsonObj,const std::string & i_vpdFruPath,const std::string & i_action,const std::string & i_flowFlag,uint16_t & o_errCode)753 inline bool isActionRequired(const nlohmann::json& i_sysCfgJsonObj,
754 const std::string& i_vpdFruPath,
755 const std::string& i_action,
756 const std::string& i_flowFlag, uint16_t& o_errCode)
757 {
758 if (i_vpdFruPath.empty() || i_action.empty() || i_flowFlag.empty())
759 {
760 o_errCode = error_code::INVALID_INPUT_PARAMETER;
761 return false;
762 }
763
764 if (!i_sysCfgJsonObj.contains("frus"))
765 {
766 o_errCode = error_code::INVALID_JSON;
767 return false;
768 }
769
770 if (!i_sysCfgJsonObj["frus"].contains(i_vpdFruPath))
771 {
772 o_errCode = error_code::FRU_PATH_NOT_FOUND;
773 return false;
774 }
775
776 if ((i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0)).contains(i_action))
777 {
778 if ((i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0))[i_action].contains(
779 i_flowFlag))
780 {
781 return true;
782 }
783 }
784 return false;
785 }
786
787 /**
788 * @brief An API to return list of FRUs that needs GPIO polling.
789 *
790 * An API that checks for the FRUs that requires GPIO polling and returns
791 * a list of FRUs that needs polling. Returns an empty list if there are
792 * no FRUs that requires polling.
793 *
794 * @param[in] i_sysCfgJsonObj - System config JSON object.
795 * @param[out] o_errCode - To set error codes in case of error.
796 *
797 * @return On success list of FRUs parameters that needs polling. On failure,
798 * empty list.
799 */
getListOfGpioPollingFrus(const nlohmann::json & i_sysCfgJsonObj,uint16_t & o_errCode)800 inline std::vector<std::string> getListOfGpioPollingFrus(
801 const nlohmann::json& i_sysCfgJsonObj, uint16_t& o_errCode)
802 {
803 std::vector<std::string> l_gpioPollingRequiredFrusList;
804
805 if (i_sysCfgJsonObj.empty())
806 {
807 o_errCode = error_code::INVALID_INPUT_PARAMETER;
808 return l_gpioPollingRequiredFrusList;
809 }
810
811 if (!i_sysCfgJsonObj.contains("frus"))
812 {
813 o_errCode = error_code::INVALID_JSON;
814 return l_gpioPollingRequiredFrusList;
815 }
816
817 for (const auto& l_fru : i_sysCfgJsonObj["frus"].items())
818 {
819 const auto l_fruPath = l_fru.key();
820
821 bool l_isHotPluggableFru =
822 isActionRequired(i_sysCfgJsonObj, l_fruPath, "pollingRequired",
823 "hotPlugging", o_errCode);
824
825 if (o_errCode)
826 {
827 logging::logMessage(
828 "Error while checking if action required for FRU [" +
829 std::string(l_fruPath) +
830 "], error : " + vpdSpecificUtility::getErrCodeMsg(o_errCode));
831
832 return l_gpioPollingRequiredFrusList;
833 }
834
835 if (l_isHotPluggableFru)
836 {
837 if (i_sysCfgJsonObj["frus"][l_fruPath]
838 .at(0)["pollingRequired"]["hotPlugging"]
839 .contains("gpioPresence"))
840 {
841 l_gpioPollingRequiredFrusList.push_back(l_fruPath);
842 }
843 }
844 }
845
846 return l_gpioPollingRequiredFrusList;
847 }
848
849 /**
850 * @brief Get all related path(s) to update keyword value.
851 *
852 * Given FRU EEPROM path/Inventory path needs keyword's value update, this API
853 * returns tuple of FRU EEPROM path, inventory path and redundant EEPROM path if
854 * exists in the system config JSON.
855 *
856 * Note: If the inventory object path or redundant EEPROM path(s) are not found
857 * in the system config JSON, corresponding fields will have empty value in the
858 * returning tuple.
859 *
860 * @param[in] i_sysCfgJsonObj - System config JSON object.
861 * @param[in,out] io_vpdPath - Inventory object path or FRU EEPROM path.
862 * @param[out] o_errCode - To set error code in case of error.
863 *
864 * @return On success returns tuple of EEPROM path, inventory path & redundant
865 * path, on failure returns tuple with given input path alone.
866 */
867 inline std::tuple<std::string, std::string, std::string>
getAllPathsToUpdateKeyword(const nlohmann::json & i_sysCfgJsonObj,std::string io_vpdPath,uint16_t & o_errCode)868 getAllPathsToUpdateKeyword(const nlohmann::json& i_sysCfgJsonObj,
869 std::string io_vpdPath, uint16_t& o_errCode)
870 {
871 types::Path l_inventoryObjPath;
872 types::Path l_redundantFruPath;
873 o_errCode = 0;
874
875 if (i_sysCfgJsonObj.empty() || io_vpdPath.empty())
876 {
877 o_errCode = error_code::INVALID_INPUT_PARAMETER;
878 return std::make_tuple(io_vpdPath, l_inventoryObjPath,
879 l_redundantFruPath);
880 }
881
882 // Get hardware path from system config JSON.
883 const types::Path l_fruPath =
884 jsonUtility::getFruPathFromJson(i_sysCfgJsonObj, io_vpdPath, o_errCode);
885
886 if (!l_fruPath.empty())
887 {
888 io_vpdPath = l_fruPath;
889
890 // Get inventory object path from system config JSON
891 l_inventoryObjPath = jsonUtility::getInventoryObjPathFromJson(
892 i_sysCfgJsonObj, l_fruPath, o_errCode);
893
894 if (l_inventoryObjPath.empty())
895 {
896 if (o_errCode)
897 {
898 logging::logMessage(
899 "Failed to get inventory path from JSON for [" +
900 io_vpdPath + "], error : " +
901 vpdSpecificUtility::getErrCodeMsg(o_errCode));
902 }
903 else
904 {
905 o_errCode = error_code::FRU_PATH_NOT_FOUND;
906 }
907
908 return std::make_tuple(io_vpdPath, l_inventoryObjPath,
909 l_redundantFruPath);
910 }
911
912 // Get redundant hardware path if present in system config JSON
913 l_redundantFruPath = jsonUtility::getRedundantEepromPathFromJson(
914 i_sysCfgJsonObj, l_fruPath, o_errCode);
915
916 if (l_redundantFruPath.empty())
917 {
918 if (o_errCode)
919 {
920 logging::logMessage(
921 "Failed to get redundant EEPROM path for FRU [" +
922 l_fruPath + "], error : " +
923 vpdSpecificUtility::getErrCodeMsg(o_errCode));
924
925 o_errCode = error_code::ERROR_GETTING_REDUNDANT_PATH;
926 }
927 else
928 {
929 o_errCode = error_code::REDUNDANT_PATH_NOT_FOUND;
930 }
931
932 return std::make_tuple(io_vpdPath, l_inventoryObjPath,
933 l_redundantFruPath);
934 }
935 }
936 else if (o_errCode)
937 {
938 logging::logMessage(
939 "Failed to get FRU path from JSON for [" + io_vpdPath +
940 "], error : " + vpdSpecificUtility::getErrCodeMsg(o_errCode));
941 }
942 else
943 {
944 o_errCode = error_code::NO_EEPROM_PATH;
945 }
946
947 return std::make_tuple(io_vpdPath, l_inventoryObjPath, l_redundantFruPath);
948 }
949
950 /**
951 * @brief An API to get DBus service name.
952 *
953 * Given DBus inventory path, this API returns DBus service name if present in
954 * the JSON.
955 *
956 * @param[in] i_sysCfgJsonObj - System config JSON object.
957 * @param[in] l_inventoryPath - DBus inventory path.
958 * @param[out] o_errCode - To set error code in case of error.
959 *
960 * @return On success returns the service name present in the system config
961 * JSON, otherwise empty string.
962 *
963 * Note: Caller has to handle in case of empty string received.
964 */
getServiceName(const nlohmann::json & i_sysCfgJsonObj,const std::string & l_inventoryPath,uint16_t & o_errCode)965 inline std::string getServiceName(const nlohmann::json& i_sysCfgJsonObj,
966 const std::string& l_inventoryPath,
967 uint16_t& o_errCode)
968 {
969 if (l_inventoryPath.empty())
970 {
971 o_errCode = error_code::INVALID_INPUT_PARAMETER;
972 return std::string{};
973 }
974
975 if (!i_sysCfgJsonObj.contains("frus"))
976 {
977 o_errCode = error_code::INVALID_JSON;
978 return std::string{};
979 }
980
981 const nlohmann::json& l_listOfFrus =
982 i_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
983
984 for (const auto& l_frus : l_listOfFrus.items())
985 {
986 for (const auto& l_inventoryItem : l_frus.value())
987 {
988 if (l_inventoryPath.compare(l_inventoryItem["inventoryPath"]) ==
989 constants::STR_CMP_SUCCESS)
990 {
991 if (l_inventoryItem.contains("serviceName"))
992 {
993 return l_inventoryItem.value("serviceName", "");
994 }
995
996 o_errCode = error_code::JSON_MISSING_SERVICE_NAME;
997 return std::string{};
998 }
999 }
1000 }
1001
1002 o_errCode = error_code::FRU_PATH_NOT_FOUND;
1003 return std::string{};
1004 }
1005
1006 /**
1007 * @brief An API to check if a FRU is tagged as "powerOffOnly"
1008 *
1009 * Given the system config JSON and VPD FRU path, this API checks if the FRU
1010 * VPD can be collected at Chassis Power Off state only.
1011 *
1012 * @param[in] i_sysCfgJsonObj - System config JSON object.
1013 * @param[in] i_vpdFruPath - EEPROM path.
1014 * @param[out] o_errCode - To set error code for the error.
1015 * @return - True if FRU VPD can be collected at Chassis Power Off state only.
1016 * False otherwise
1017 */
isFruPowerOffOnly(const nlohmann::json & i_sysCfgJsonObj,const std::string & i_vpdFruPath,uint16_t & o_errCode)1018 inline bool isFruPowerOffOnly(const nlohmann::json& i_sysCfgJsonObj,
1019 const std::string& i_vpdFruPath,
1020 uint16_t& o_errCode)
1021 {
1022 if (i_vpdFruPath.empty())
1023 {
1024 o_errCode = error_code::INVALID_INPUT_PARAMETER;
1025 return false;
1026 }
1027
1028 if (!i_sysCfgJsonObj.contains("frus"))
1029 {
1030 o_errCode = error_code::INVALID_JSON;
1031 return false;
1032 }
1033
1034 if (!i_sysCfgJsonObj["frus"].contains(i_vpdFruPath))
1035 {
1036 o_errCode = error_code::FRU_PATH_NOT_FOUND;
1037 return false;
1038 }
1039
1040 return ((i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0))
1041 .contains("powerOffOnly") &&
1042 (i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0)["powerOffOnly"]));
1043 }
1044
1045 /**
1046 * @brief API which tells if the FRU is replaceable at runtime
1047 *
1048 * @param[in] i_sysCfgJsonObj - System config JSON object.
1049 * @param[in] i_vpdFruPath - EEPROM path.
1050 * @param[out] o_errCode - to set error code in case of error.
1051 *
1052 * @return true if FRU is replaceable at runtime. false otherwise.
1053 */
isFruReplaceableAtRuntime(const nlohmann::json & i_sysCfgJsonObj,const std::string & i_vpdFruPath,uint16_t & o_errCode)1054 inline bool isFruReplaceableAtRuntime(const nlohmann::json& i_sysCfgJsonObj,
1055 const std::string& i_vpdFruPath,
1056 uint16_t& o_errCode)
1057 {
1058 if (i_vpdFruPath.empty())
1059 {
1060 o_errCode = error_code::INVALID_INPUT_PARAMETER;
1061 return false;
1062 }
1063
1064 if (i_sysCfgJsonObj.empty() || (!i_sysCfgJsonObj.contains("frus")))
1065 {
1066 o_errCode = error_code::INVALID_JSON;
1067 return false;
1068 }
1069
1070 if (!i_sysCfgJsonObj["frus"].contains(i_vpdFruPath))
1071 {
1072 o_errCode = error_code::FRU_PATH_NOT_FOUND;
1073 return false;
1074 }
1075
1076 return (
1077 (i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0))
1078 .contains("replaceableAtRuntime") &&
1079 (i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0)["replaceableAtRuntime"]));
1080
1081 return false;
1082 }
1083
1084 /**
1085 * @brief API which tells if the FRU is replaceable at standby
1086 *
1087 * @param[in] i_sysCfgJsonObj - System config JSON object.
1088 * @param[in] i_vpdFruPath - EEPROM path.
1089 * @param[out] o_errCode - set error code in case of error.
1090 *
1091 * @return true if FRU is replaceable at standby. false otherwise.
1092 */
isFruReplaceableAtStandby(const nlohmann::json & i_sysCfgJsonObj,const std::string & i_vpdFruPath,uint16_t & o_errCode)1093 inline bool isFruReplaceableAtStandby(const nlohmann::json& i_sysCfgJsonObj,
1094 const std::string& i_vpdFruPath,
1095 uint16_t& o_errCode)
1096 {
1097 if (i_vpdFruPath.empty())
1098 {
1099 o_errCode = error_code::INVALID_INPUT_PARAMETER;
1100 return false;
1101 }
1102
1103 if (i_sysCfgJsonObj.empty() || (!i_sysCfgJsonObj.contains("frus")))
1104 {
1105 o_errCode = error_code::INVALID_JSON;
1106 return false;
1107 }
1108
1109 if (!i_sysCfgJsonObj["frus"].contains(i_vpdFruPath))
1110 {
1111 o_errCode = error_code::FRU_PATH_NOT_FOUND;
1112 return false;
1113 }
1114
1115 return (
1116 (i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0))
1117 .contains("replaceableAtStandby") &&
1118 (i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0)["replaceableAtStandby"]));
1119
1120 return false;
1121 }
1122
1123 /**
1124 * @brief API to get list of FRUs replaceable at standby from JSON.
1125 *
1126 * The API will return a vector of FRUs inventory path which are replaceable at
1127 * standby.
1128 *
1129 * @param[in] i_sysCfgJsonObj - System config JSON object.
1130 * @param[out] o_errCode - To set error code in case of error.
1131 *
1132 * @return - On success, list of FRUs replaceable at standby. On failure, empty
1133 * vector.
1134 */
getListOfFrusReplaceableAtStandby(const nlohmann::json & i_sysCfgJsonObj,uint16_t & o_errCode)1135 inline std::vector<std::string> getListOfFrusReplaceableAtStandby(
1136 const nlohmann::json& i_sysCfgJsonObj, uint16_t& o_errCode)
1137 {
1138 std::vector<std::string> l_frusReplaceableAtStandby;
1139
1140 if (!i_sysCfgJsonObj.contains("frus"))
1141 {
1142 o_errCode = error_code::INVALID_JSON;
1143 return l_frusReplaceableAtStandby;
1144 }
1145
1146 const nlohmann::json& l_fruList =
1147 i_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
1148
1149 for (const auto& l_fru : l_fruList.items())
1150 {
1151 if (i_sysCfgJsonObj["frus"][l_fru.key()].at(0).value(
1152 "replaceableAtStandby", false))
1153 {
1154 const std::string& l_inventoryObjectPath =
1155 i_sysCfgJsonObj["frus"][l_fru.key()].at(0).value(
1156 "inventoryPath", "");
1157
1158 if (!l_inventoryObjectPath.empty())
1159 {
1160 l_frusReplaceableAtStandby.emplace_back(l_inventoryObjectPath);
1161 }
1162 }
1163 }
1164
1165 return l_frusReplaceableAtStandby;
1166 }
1167
1168 /**
1169 * @brief API to select powerVS JSON based on system IM.
1170 *
1171 * The API selects respective JSON based on system IM, parse it and return the
1172 * JSON object. Empty JSON will be returned in case of any error. Caller needs
1173 * to handle empty value.
1174 *
1175 * @param[in] i_imValue - IM value of the system.
1176 * @param[out] o_errCode - to set error code in case of error.
1177 * @return Parsed JSON object, empty JSON otherwise.
1178 */
getPowerVsJson(const types::BinaryVector & i_imValue,uint16_t & o_errCode)1179 inline nlohmann::json getPowerVsJson(const types::BinaryVector& i_imValue,
1180 uint16_t& o_errCode)
1181 {
1182 if (i_imValue.empty() || i_imValue.size() < 4)
1183 {
1184 o_errCode = error_code::INVALID_INPUT_PARAMETER;
1185 return nlohmann::json{};
1186 }
1187
1188 o_errCode = 0;
1189 if ((i_imValue.at(0) == constants::HEX_VALUE_50) &&
1190 (i_imValue.at(1) == constants::HEX_VALUE_00) &&
1191 (i_imValue.at(2) == constants::HEX_VALUE_30))
1192 {
1193 nlohmann::json l_parsedJson = jsonUtility::getParsedJson(
1194 constants::power_vs_50003_json, o_errCode);
1195
1196 if (o_errCode)
1197 {
1198 logging::logMessage(
1199 "Failed to parse JSON file [ " +
1200 std::string(constants::power_vs_50003_json) +
1201 " ], error : " + vpdSpecificUtility::getErrCodeMsg(o_errCode));
1202 }
1203
1204 return l_parsedJson;
1205 }
1206 else if (i_imValue.at(0) == constants::HEX_VALUE_50 &&
1207 (i_imValue.at(1) == constants::HEX_VALUE_00) &&
1208 (i_imValue.at(2) == constants::HEX_VALUE_10))
1209 {
1210 nlohmann::json l_parsedJson = jsonUtility::getParsedJson(
1211 constants::power_vs_50001_json, o_errCode);
1212
1213 if (o_errCode)
1214 {
1215 logging::logMessage(
1216 "Failed to parse JSON file [ " +
1217 std::string(constants::power_vs_50001_json) +
1218 " ], error : " + vpdSpecificUtility::getErrCodeMsg(o_errCode));
1219 }
1220
1221 return l_parsedJson;
1222 }
1223 return nlohmann::json{};
1224 }
1225
1226 /**
1227 * @brief API to get list of FRUs for which "monitorPresence" is true.
1228 *
1229 * @param[in] i_sysCfgJsonObj - System config JSON object.
1230 * @param[out] o_errCode - To set error code in case of error.
1231 *
1232 * @return On success, returns list of FRUs for which "monitorPresence" is true,
1233 * empty list on error.
1234 */
getFrusWithPresenceMonitoring(const nlohmann::json & i_sysCfgJsonObj,uint16_t & o_errCode)1235 inline std::vector<types::Path> getFrusWithPresenceMonitoring(
1236 const nlohmann::json& i_sysCfgJsonObj, uint16_t& o_errCode)
1237 {
1238 std::vector<types::Path> l_frusWithPresenceMonitoring;
1239
1240 if (!i_sysCfgJsonObj.contains("frus"))
1241 {
1242 o_errCode = error_code::INVALID_JSON;
1243 return l_frusWithPresenceMonitoring;
1244 }
1245
1246 const nlohmann::json& l_listOfFrus =
1247 i_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
1248
1249 for (const auto& l_aFru : l_listOfFrus)
1250 {
1251 if (l_aFru.at(0).value("monitorPresence", false))
1252 {
1253 l_frusWithPresenceMonitoring.emplace_back(
1254 l_aFru.at(0).value("inventoryPath", ""));
1255 }
1256 }
1257
1258 return l_frusWithPresenceMonitoring;
1259 }
1260
1261 /**
1262 * @brief API which tells if the FRU's presence is handled
1263 *
1264 * For a given FRU, this API checks if it's presence is handled by vpd-manager
1265 * by checking the "handlePresence" tag.
1266 *
1267 * @param[in] i_sysCfgJsonObj - System config JSON object.
1268 * @param[in] i_vpdFruPath - EEPROM path.
1269 * @param[out] o_errCode - To set error code in case of failure.
1270 *
1271 * @return true if FRU presence is handled, false otherwise.
1272 */
isFruPresenceHandled(const nlohmann::json & i_sysCfgJsonObj,const std::string & i_vpdFruPath,uint16_t & o_errCode)1273 inline bool isFruPresenceHandled(const nlohmann::json& i_sysCfgJsonObj,
1274 const std::string& i_vpdFruPath,
1275 uint16_t& o_errCode)
1276 {
1277 if (i_vpdFruPath.empty())
1278 {
1279 o_errCode = error_code::INVALID_INPUT_PARAMETER;
1280 return false;
1281 }
1282
1283 if (!i_sysCfgJsonObj.contains("frus"))
1284 {
1285 o_errCode = error_code::INVALID_JSON;
1286 return false;
1287 }
1288
1289 if (!i_sysCfgJsonObj["frus"].contains(i_vpdFruPath))
1290 {
1291 o_errCode = error_code::FRU_PATH_NOT_FOUND;
1292 return false;
1293 }
1294
1295 return i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0).value(
1296 "handlePresence", true);
1297 }
1298 } // namespace jsonUtility
1299 } // namespace vpd
1300