xref: /openbmc/openpower-vpd-parser/vpd-manager/include/utility/json_utility.hpp (revision 41f47e77ce0904f17ee5849af178e2fe23cdb28b)
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