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