blob: 74dfc382a24136ed179424f09c6131e54933de7d [file] [log] [blame]
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001#pragma once
2
Rekha Aparna017567a2025-08-13 02:07:06 -05003#include "error_codes.hpp"
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05004#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>
Rekha Aparnaca9a0862025-08-29 04:08:33 -050012#include <utility/vpd_specific_utility.hpp>
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050013
14#include <fstream>
15#include <type_traits>
16#include <unordered_map>
17
18namespace vpd
19{
20namespace jsonUtility
21{
22
23// forward declaration of API for function map.
24bool processSystemCmdTag(const nlohmann::json& i_parsedConfigJson,
25 const std::string& i_vpdFilePath,
26 const std::string& i_baseAction,
27 const std::string& i_flagToProcess);
28
29// forward declaration of API for function map.
30bool processGpioPresenceTag(
31 const nlohmann::json& i_parsedConfigJson, const std::string& i_vpdFilePath,
32 const std::string& i_baseAction, const std::string& i_flagToProcess);
33
34// forward declaration of API for function map.
35bool procesSetGpioTag(const nlohmann::json& i_parsedConfigJson,
36 const std::string& i_vpdFilePath,
37 const std::string& i_baseAction,
38 const std::string& i_flagToProcess);
39
40// Function pointers to process tags from config JSON.
41typedef bool (*functionPtr)(
42 const nlohmann::json& i_parsedConfigJson, const std::string& i_vpdFilePath,
43 const std::string& i_baseAction, const std::string& i_flagToProcess);
44
45inline std::unordered_map<std::string, functionPtr> funcionMap{
46 {"gpioPresence", processGpioPresenceTag},
47 {"setGpio", procesSetGpioTag},
48 {"systemCmd", processSystemCmdTag}};
49
50/**
51 * @brief API to read VPD offset from JSON file.
52 *
53 * @param[in] i_sysCfgJsonObj - Parsed system config JSON object.
54 * @param[in] i_vpdFilePath - VPD file path.
Rekha Aparna017567a2025-08-13 02:07:06 -050055 * @param[in] o_errCode - To set error code in case of error.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050056 * @return VPD offset if found in JSON, 0 otherwise.
57 */
58inline size_t getVPDOffset(const nlohmann::json& i_sysCfgJsonObj,
Rekha Aparna017567a2025-08-13 02:07:06 -050059 const std::string& i_vpdFilePath,
60 uint16_t& o_errCode)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050061{
62 if (i_vpdFilePath.empty() || (i_sysCfgJsonObj.empty()) ||
63 (!i_sysCfgJsonObj.contains("frus")))
64 {
Rekha Aparna017567a2025-08-13 02:07:06 -050065 o_errCode = error_code::INVALID_INPUT_PARAMETER;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050066 return 0;
67 }
68
69 if (i_sysCfgJsonObj["frus"].contains(i_vpdFilePath))
70 {
71 return i_sysCfgJsonObj["frus"][i_vpdFilePath].at(0).value("offset", 0);
72 }
73
74 const nlohmann::json& l_fruList =
75 i_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
76
77 for (const auto& l_fru : l_fruList.items())
78 {
79 const auto l_fruPath = l_fru.key();
80
81 // check if given path is redundant FRU path
82 if (i_vpdFilePath == i_sysCfgJsonObj["frus"][l_fruPath].at(0).value(
83 "redundantEeprom", ""))
84 {
85 // Return the offset of redundant EEPROM taken from JSON.
86 return i_sysCfgJsonObj["frus"][l_fruPath].at(0).value("offset", 0);
87 }
88 }
89
90 return 0;
91}
92
93/**
94 * @brief API to parse respective JSON.
95 *
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050096 * @param[in] pathToJson - Path to JSON.
Rekha Aparnaca9a0862025-08-29 04:08:33 -050097 * @param[out] o_errCode - To set error code in case of error.
RekhaAparna011ef21002025-02-18 23:47:36 -060098 * @return on success parsed JSON. On failure empty JSON object.
99 *
100 * Note: Caller has to handle it in case an empty JSON object is received.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500101 */
Rekha Aparnaca9a0862025-08-29 04:08:33 -0500102inline nlohmann::json getParsedJson(const std::string& pathToJson,
103 uint16_t& o_errCode) noexcept
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500104{
Rekha Aparnaca9a0862025-08-29 04:08:33 -0500105 if (pathToJson.empty())
106 {
107 o_errCode = error_code::INVALID_INPUT_PARAMETER;
108 return nlohmann::json{};
109 }
110
111 if (!std::filesystem::exists(pathToJson))
112 {
113 o_errCode = error_code::FILE_NOT_FOUND;
114 return nlohmann::json{};
115 }
116
117 if (std::filesystem::is_empty(pathToJson))
118 {
119 o_errCode = error_code::EMPTY_FILE;
120 return nlohmann::json{};
121 }
122
123 std::ifstream l_jsonFile(pathToJson);
124 if (!l_jsonFile)
125 {
126 o_errCode = error_code::FILE_ACCESS_ERROR;
127 return nlohmann::json{};
128 }
129
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500130 try
131 {
RekhaAparna011ef21002025-02-18 23:47:36 -0600132 return nlohmann::json::parse(l_jsonFile);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500133 }
RekhaAparna011ef21002025-02-18 23:47:36 -0600134 catch (const std::exception& l_ex)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500135 {
Rekha Aparnaca9a0862025-08-29 04:08:33 -0500136 o_errCode = error_code::JSON_PARSE_ERROR;
137 return nlohmann::json{};
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500138 }
139}
140
141/**
142 * @brief Get inventory object path from system config JSON.
143 *
144 * Given either D-bus inventory path/FRU EEPROM path/redundant EEPROM path,
145 * this API returns D-bus inventory path if present in JSON.
146 *
147 * @param[in] i_sysCfgJsonObj - System config JSON object
148 * @param[in] i_vpdPath - Path to where VPD is stored.
Rekha Aparna017567a2025-08-13 02:07:06 -0500149 * @param[in] o_errCode - To set error code in case of error.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500150 *
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500151 * @return On success a valid path is returned, on failure an empty string is
RekhaAparna011ef21002025-02-18 23:47:36 -0600152 * returned.
153 *
154 * Note: Caller has to handle it in case an empty string is received.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500155 */
156inline std::string getInventoryObjPathFromJson(
Rekha Aparna017567a2025-08-13 02:07:06 -0500157 const nlohmann::json& i_sysCfgJsonObj, const std::string& i_vpdPath,
158 uint16_t& o_errCode) noexcept
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500159{
Rekha Aparna017567a2025-08-13 02:07:06 -0500160 if (i_vpdPath.empty())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500161 {
Rekha Aparna017567a2025-08-13 02:07:06 -0500162 o_errCode = error_code::INVALID_INPUT_PARAMETER;
163 return std::string{};
RekhaAparna011ef21002025-02-18 23:47:36 -0600164 }
165
Rekha Aparna017567a2025-08-13 02:07:06 -0500166 if (!i_sysCfgJsonObj.contains("frus"))
167 {
168 o_errCode = error_code::INVALID_JSON;
169 return std::string{};
170 }
171
172 // check if given path is FRU path
173 if (i_sysCfgJsonObj["frus"].contains(i_vpdPath))
174 {
175 return i_sysCfgJsonObj["frus"][i_vpdPath].at(0).value(
176 "inventoryPath", "");
177 }
178
179 const nlohmann::json& l_fruList =
180 i_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
181
182 for (const auto& l_fru : l_fruList.items())
183 {
184 const auto l_fruPath = l_fru.key();
185 const auto l_invObjPath =
186 i_sysCfgJsonObj["frus"][l_fruPath].at(0).value("inventoryPath", "");
187
188 // check if given path is redundant FRU path or inventory path
189 if (i_vpdPath == i_sysCfgJsonObj["frus"][l_fruPath].at(0).value(
190 "redundantEeprom", "") ||
191 (i_vpdPath == l_invObjPath))
192 {
193 return l_invObjPath;
194 }
195 }
196
197 return std::string{};
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500198}
199
200/**
201 * @brief Process "PostFailAction" defined in config JSON.
202 *
203 * In case there is some error in the processing of "preAction" execution and a
204 * set of procedure needs to be done as a part of post fail action. This base
205 * action can be defined in the config JSON for that FRU and it will be handled
206 * under this API.
207 *
208 * @param[in] i_parsedConfigJson - config JSON
209 * @param[in] i_vpdFilePath - EEPROM file path
210 * @param[in] i_flagToProcess - To identify which flag(s) needs to be processed
Rekha Aparnaff7d7992025-09-01 11:08:53 -0500211 * @param[out] o_errCode - To set error code in case of error
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500212 * under PostFailAction tag of config JSON.
213 * @return - success or failure
214 */
Rekha Aparnaff7d7992025-09-01 11:08:53 -0500215inline bool executePostFailAction(
216 const nlohmann::json& i_parsedConfigJson, const std::string& i_vpdFilePath,
217 const std::string& i_flagToProcess, uint16_t& o_errCode)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500218{
Rekha Aparnaff7d7992025-09-01 11:08:53 -0500219 if (i_parsedConfigJson.empty() || i_vpdFilePath.empty() ||
220 i_flagToProcess.empty())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500221 {
Rekha Aparnaff7d7992025-09-01 11:08:53 -0500222 o_errCode = error_code::INVALID_INPUT_PARAMETER;
223 return false;
224 }
RekhaAparna01c11e8b62025-02-20 00:34:35 -0600225
Rekha Aparnaff7d7992025-09-01 11:08:53 -0500226 if (!(i_parsedConfigJson["frus"][i_vpdFilePath].at(0))["postFailAction"]
227 .contains(i_flagToProcess))
228 {
229 o_errCode = error_code::MISSING_FLAG;
230 return false;
231 }
RekhaAparna01c11e8b62025-02-20 00:34:35 -0600232
Rekha Aparnaff7d7992025-09-01 11:08:53 -0500233 for (const auto& l_tags : (i_parsedConfigJson["frus"][i_vpdFilePath].at(
234 0))["postFailAction"][i_flagToProcess]
235 .items())
236 {
237 auto itrToFunction = funcionMap.find(l_tags.key());
238 if (itrToFunction != funcionMap.end())
RekhaAparna01c11e8b62025-02-20 00:34:35 -0600239 {
Rekha Aparnaff7d7992025-09-01 11:08:53 -0500240 if (!itrToFunction->second(i_parsedConfigJson, i_vpdFilePath,
241 "postFailAction", i_flagToProcess))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500242 {
Rekha Aparnaff7d7992025-09-01 11:08:53 -0500243 return false;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500244 }
245 }
246 }
247
248 return true;
249}
250
251/**
252 * @brief Process "systemCmd" tag for a given FRU.
253 *
254 * The API will process "systemCmd" tag if it is defined in the config
255 * JSON for the given FRU.
256 *
257 * @param[in] i_parsedConfigJson - config JSON
258 * @param[in] i_vpdFilePath - EEPROM file path
259 * @param[in] i_baseAction - Base action for which this tag has been called.
260 * @param[in] i_flagToProcess - Flag nested under the base action for which this
261 * tag has been called.
262 * @return Execution status.
263 */
264inline bool processSystemCmdTag(
265 const nlohmann::json& i_parsedConfigJson, const std::string& i_vpdFilePath,
266 const std::string& i_baseAction, const std::string& i_flagToProcess)
267{
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500268 try
269 {
RekhaAparna01c11e8b62025-02-20 00:34:35 -0600270 if (i_vpdFilePath.empty() || i_parsedConfigJson.empty() ||
271 i_baseAction.empty() || i_flagToProcess.empty())
272 {
273 throw std::runtime_error(
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530274 std::string(__FUNCTION__) +
275 " Invalid parameter. Abort processing of processSystemCmd.");
RekhaAparna01c11e8b62025-02-20 00:34:35 -0600276 }
277
278 if (!((i_parsedConfigJson["frus"][i_vpdFilePath].at(
279 0)[i_baseAction][i_flagToProcess]["systemCmd"])
280 .contains("cmd")))
281 {
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530282 throw JsonException(
283 std::string(__FUNCTION__) +
284 " Config JSON missing required information to execute system command for EEPROM " +
RekhaAparna01c11e8b62025-02-20 00:34:35 -0600285 i_vpdFilePath);
286 }
287
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500288 const std::string& l_systemCommand =
289 i_parsedConfigJson["frus"][i_vpdFilePath].at(
290 0)[i_baseAction][i_flagToProcess]["systemCmd"]["cmd"];
291
292 commonUtility::executeCmd(l_systemCommand);
293 return true;
294 }
RekhaAparna01c11e8b62025-02-20 00:34:35 -0600295 catch (const std::exception& l_ex)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500296 {
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530297 EventLogger::createSyncPel(
298 EventLogger::getErrorType(l_ex), types::SeverityType::Informational,
299 __FILE__, __FUNCTION__, 0, EventLogger::getErrorMsg(l_ex),
300 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500301 return false;
302 }
303}
304
305/**
306 * @brief Checks for presence of a given FRU using GPIO line.
307 *
308 * This API returns the presence information of the FRU corresponding to the
309 * given VPD file path by setting the presence pin.
310 *
311 * @param[in] i_parsedConfigJson - config JSON
312 * @param[in] i_vpdFilePath - EEPROM file path
313 * @param[in] i_baseAction - Base action for which this tag has been called.
314 * @param[in] i_flagToProcess - Flag nested under the base action for which this
315 * tag has been called.
316 * @return Execution status.
317 */
318inline bool processGpioPresenceTag(
319 const nlohmann::json& i_parsedConfigJson, const std::string& i_vpdFilePath,
320 const std::string& i_baseAction, const std::string& i_flagToProcess)
321{
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530322 std::string l_presencePinName;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500323 try
324 {
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530325 if (i_vpdFilePath.empty() || i_parsedConfigJson.empty() ||
326 i_baseAction.empty() || i_flagToProcess.empty())
327 {
328 throw std::runtime_error(
329 std::string(__FUNCTION__) +
330 "Invalid parameter. Abort processing of processGpioPresence tag");
331 }
332
333 if (!(((i_parsedConfigJson["frus"][i_vpdFilePath].at(
334 0)[i_baseAction][i_flagToProcess]["gpioPresence"])
335 .contains("pin")) &&
336 ((i_parsedConfigJson["frus"][i_vpdFilePath].at(
337 0)[i_baseAction][i_flagToProcess]["gpioPresence"])
338 .contains("value"))))
339 {
340 throw JsonException(
341 std::string(__FUNCTION__) +
342 "Config JSON missing required information to detect presence for EEPROM " +
343 i_vpdFilePath);
344 }
345
346 // get the pin name
347 l_presencePinName = i_parsedConfigJson["frus"][i_vpdFilePath].at(
348 0)[i_baseAction][i_flagToProcess]["gpioPresence"]["pin"];
349
350 // get the pin value
351 uint8_t l_presencePinValue =
352 i_parsedConfigJson["frus"][i_vpdFilePath].at(
353 0)[i_baseAction][i_flagToProcess]["gpioPresence"]["value"];
354
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500355 gpiod::line l_presenceLine = gpiod::find_line(l_presencePinName);
356
357 if (!l_presenceLine)
358 {
359 throw GpioException("Couldn't find the GPIO line.");
360 }
361
362 l_presenceLine.request({"Read the presence line",
363 gpiod::line_request::DIRECTION_INPUT, 0});
364
365 return (l_presencePinValue == l_presenceLine.get_value());
366 }
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530367 catch (const std::exception& l_ex)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500368 {
Sunny Srivastavac09e2102025-04-23 10:47:06 +0530369 // No need to continue in case of JSON failure or Firmware error
370 // as these are errors internal to the code and in that case the FRU
371 // should not be processed. Any other error is considered as external
372 // error in this case and a try to read the EEPROM should be done.
373 if (EventLogger::getErrorType(l_ex) == types::ErrorType::JsonFailure ||
374 EventLogger::getErrorType(l_ex) == types::ErrorType::FirmwareError)
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530375 {
376 EventLogger::createSyncPel(
377 EventLogger::getErrorType(l_ex),
378 types::SeverityType::Informational, __FILE__, __FUNCTION__, 0,
379 EventLogger::getErrorMsg(l_ex), std::nullopt, std::nullopt,
380 std::nullopt, std::nullopt);
381 return false;
382 }
383
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500384 std::string l_errMsg = "Exception on GPIO line: ";
385 l_errMsg += l_presencePinName;
386 l_errMsg += " Reason: ";
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530387 l_errMsg += l_ex.what();
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500388 l_errMsg += " File: " + i_vpdFilePath + " Pel Logged";
389
Rekha Aparna017567a2025-08-13 02:07:06 -0500390 uint16_t l_errCode = 0;
391
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500392 // ToDo -- Update Internal Rc code.
393 EventLogger::createAsyncPelWithInventoryCallout(
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530394 EventLogger::getErrorType(l_ex), types::SeverityType::Informational,
Rekha Aparna017567a2025-08-13 02:07:06 -0500395 {{getInventoryObjPathFromJson(i_parsedConfigJson, i_vpdFilePath,
396 l_errCode),
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500397 types::CalloutPriority::High}},
398 std::source_location::current().file_name(),
399 std::source_location::current().function_name(), 0, l_errMsg,
400 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
401
402 logging::logMessage(l_errMsg);
403
404 // Except when GPIO pin value is false, we go and try collecting the
405 // FRU VPD as we couldn't able to read GPIO pin value due to some
406 // error/exception. So returning true in error scenario.
407 return true;
408 }
409}
410
411/**
412 * @brief Process "setGpio" tag for a given FRU.
413 *
414 * This API enables the GPIO line.
415 *
416 * @param[in] i_parsedConfigJson - config JSON
417 * @param[in] i_vpdFilePath - EEPROM file path
418 * @param[in] i_baseAction - Base action for which this tag has been called.
419 * @param[in] i_flagToProcess - Flag nested under the base action for which this
420 * tag has been called.
421 * @return Execution status.
422 */
423inline bool procesSetGpioTag(
424 const nlohmann::json& i_parsedConfigJson, const std::string& i_vpdFilePath,
425 const std::string& i_baseAction, const std::string& i_flagToProcess)
426{
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530427 std::string l_pinName;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500428 try
429 {
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530430 if (i_vpdFilePath.empty() || i_parsedConfigJson.empty() ||
431 i_baseAction.empty() || i_flagToProcess.empty())
432 {
433 throw std::runtime_error(
434 std::string(__FUNCTION__) +
435 " Invalid parameter. Abort processing of procesSetGpio.");
436 }
437
438 if (!(((i_parsedConfigJson["frus"][i_vpdFilePath].at(
439 0)[i_baseAction][i_flagToProcess]["setGpio"])
440 .contains("pin")) &&
441 ((i_parsedConfigJson["frus"][i_vpdFilePath].at(
442 0)[i_baseAction][i_flagToProcess]["setGpio"])
443 .contains("value"))))
444 {
445 throw JsonException(
446 std::string(__FUNCTION__) +
447 " Config JSON missing required information to set gpio line for EEPROM " +
448 i_vpdFilePath);
449 }
450
451 l_pinName = i_parsedConfigJson["frus"][i_vpdFilePath].at(
452 0)[i_baseAction][i_flagToProcess]["setGpio"]["pin"];
453
454 // Get the value to set
455 uint8_t l_pinValue = i_parsedConfigJson["frus"][i_vpdFilePath].at(
456 0)[i_baseAction][i_flagToProcess]["setGpio"]["value"];
457
458 logging::logMessage(
459 "Setting GPIO: " + l_pinName + " to " + std::to_string(l_pinValue));
460
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500461 gpiod::line l_outputLine = gpiod::find_line(l_pinName);
462
463 if (!l_outputLine)
464 {
465 throw GpioException("Couldn't find GPIO line.");
466 }
467
468 l_outputLine.request(
469 {"FRU Action", ::gpiod::line_request::DIRECTION_OUTPUT, 0},
470 l_pinValue);
471 return true;
472 }
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530473 catch (const std::exception& l_ex)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500474 {
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530475 if (EventLogger::getErrorType(l_ex) != types::ErrorType::GpioError)
476 {
477 EventLogger::createSyncPel(
478 EventLogger::getErrorType(l_ex),
479 types::SeverityType::Informational, __FILE__, __FUNCTION__, 0,
480 EventLogger::getErrorMsg(l_ex), std::nullopt, std::nullopt,
481 std::nullopt, std::nullopt);
482 }
483 else
484 {
485 std::string l_errMsg = "Exception on GPIO line: ";
486 l_errMsg += l_pinName;
487 l_errMsg += " Reason: ";
488 l_errMsg += l_ex.what();
489 l_errMsg += " File: " + i_vpdFilePath + " Pel Logged";
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500490
Rekha Aparna017567a2025-08-13 02:07:06 -0500491 uint16_t l_errCode = 0;
492
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530493 // ToDo -- Update Internal RC code
494 EventLogger::createAsyncPelWithInventoryCallout(
495 EventLogger::getErrorType(l_ex),
496 types::SeverityType::Informational,
Rekha Aparna017567a2025-08-13 02:07:06 -0500497 {{getInventoryObjPathFromJson(i_parsedConfigJson, i_vpdFilePath,
498 l_errCode),
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530499 types::CalloutPriority::High}},
500 std::source_location::current().file_name(),
501 std::source_location::current().function_name(), 0, l_errMsg,
502 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500503
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530504 logging::logMessage(l_errMsg);
505 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500506
507 return false;
508 }
509}
510
511/**
512 * @brief Process any action, if defined in config JSON.
513 *
514 * If any FRU(s) requires any special handling, then this base action can be
515 * defined for that FRU in the config JSON, processing of which will be handled
516 * in this API.
517 * Examples of action - preAction, PostAction etc.
518 *
519 * @param[in] i_parsedConfigJson - config JSON
520 * @param[in] i_action - Base action to be performed.
521 * @param[in] i_vpdFilePath - EEPROM file path
522 * @param[in] i_flagToProcess - To identify which flag(s) needs to be processed
523 * under PreAction tag of config JSON.
524 * @return - success or failure
525 */
526inline bool executeBaseAction(
527 const nlohmann::json& i_parsedConfigJson, const std::string& i_action,
528 const std::string& i_vpdFilePath, const std::string& i_flagToProcess)
529{
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530530 try
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500531 {
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530532 if (i_flagToProcess.empty() || i_action.empty() ||
533 i_vpdFilePath.empty() || !i_parsedConfigJson.contains("frus"))
534 {
535 throw std::runtime_error(
536 std::string(__FUNCTION__) + " Invalid parameter");
537 }
538
539 if (!i_parsedConfigJson["frus"].contains(i_vpdFilePath))
540 {
541 throw JsonException(std::string(__FUNCTION__) + " File path: " +
542 i_vpdFilePath + " not found in JSON");
543 }
544
545 if (!i_parsedConfigJson["frus"][i_vpdFilePath].at(0).contains(i_action))
546 {
547 throw JsonException(
548 std::string(__FUNCTION__) + " Action [" + i_action +
549 "] not defined for file path:" + i_vpdFilePath);
550 }
551
552 if (!(i_parsedConfigJson["frus"][i_vpdFilePath].at(0))[i_action]
553 .contains(i_flagToProcess))
554 {
555 throw JsonException(
556 std::string(__FUNCTION__) + "Config JSON missing flag [" +
557 i_flagToProcess +
558 "] to execute action for path = " + i_vpdFilePath);
559 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500560 }
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530561 catch (const std::exception& l_ex)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500562 {
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530563 EventLogger::createSyncPel(
564 EventLogger::getErrorType(l_ex), types::SeverityType::Informational,
565 __FILE__, __FUNCTION__, 0, EventLogger::getErrorMsg(l_ex),
566 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500567 return false;
568 }
569
570 const nlohmann::json& l_tagsJson =
571 (i_parsedConfigJson["frus"][i_vpdFilePath].at(
572 0))[i_action][i_flagToProcess];
573
574 for (const auto& l_tag : l_tagsJson.items())
575 {
576 auto itrToFunction = funcionMap.find(l_tag.key());
577 if (itrToFunction != funcionMap.end())
578 {
579 if (!itrToFunction->second(i_parsedConfigJson, i_vpdFilePath,
580 i_action, i_flagToProcess))
581 {
582 // In case any of the tag fails to execute. Mark action
583 // as failed for that flag.
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 *
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500602 * @return On success return valid path, on failure return empty string.
603 */
604inline std::string getRedundantEepromPathFromJson(
RekhaAparna017fea9f52025-02-17 04:14:02 -0600605 const nlohmann::json& i_sysCfgJsonObj,
606 const std::string& i_vpdPath) noexcept
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500607{
RekhaAparna017fea9f52025-02-17 04:14:02 -0600608 try
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500609 {
RekhaAparna017fea9f52025-02-17 04:14:02 -0600610 if (i_vpdPath.empty())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500611 {
RekhaAparna017fea9f52025-02-17 04:14:02 -0600612 throw std::runtime_error("Path parameter is empty.");
613 }
614
615 if (!i_sysCfgJsonObj.contains("frus"))
616 {
617 throw std::runtime_error("Missing frus tag in system config JSON.");
618 }
619
620 // check if given path is FRU path
621 if (i_sysCfgJsonObj["frus"].contains(i_vpdPath))
622 {
623 return i_sysCfgJsonObj["frus"][i_vpdPath].at(0).value(
624 "redundantEeprom", "");
625 }
626
627 const nlohmann::json& l_fruList =
628 i_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
629
630 for (const auto& l_fru : l_fruList.items())
631 {
632 const std::string& l_fruPath = l_fru.key();
633 const std::string& l_redundantFruPath =
634 i_sysCfgJsonObj["frus"][l_fruPath].at(0).value(
635 "redundantEeprom", "");
636
637 // check if given path is inventory path or redundant FRU path
638 if ((i_sysCfgJsonObj["frus"][l_fruPath].at(0).value(
639 "inventoryPath", "") == i_vpdPath) ||
640 (l_redundantFruPath == i_vpdPath))
641 {
642 return l_redundantFruPath;
643 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500644 }
645 }
RekhaAparna017fea9f52025-02-17 04:14:02 -0600646 catch (const std::exception& l_ex)
647 {
648 logging::logMessage("Failed to get redundant EEPROM path, error: " +
649 std::string(l_ex.what()));
650 }
651
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500652 return std::string();
653}
654
655/**
656 * @brief Get FRU EEPROM path from system config JSON
657 *
658 * Given either D-bus inventory path/FRU EEPROM path/redundant EEPROM path,
659 * this API returns FRU EEPROM path if present in JSON.
660 *
661 * @param[in] i_sysCfgJsonObj - System config JSON object
662 * @param[in] i_vpdPath - Path to where VPD is stored.
663 *
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500664 * @return On success return valid path, on failure return empty string.
665 */
666inline std::string getFruPathFromJson(const nlohmann::json& i_sysCfgJsonObj,
RekhaAparna017fea9f52025-02-17 04:14:02 -0600667 const std::string& i_vpdPath) noexcept
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500668{
RekhaAparna017fea9f52025-02-17 04:14:02 -0600669 try
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500670 {
RekhaAparna017fea9f52025-02-17 04:14:02 -0600671 if (i_vpdPath.empty())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500672 {
RekhaAparna017fea9f52025-02-17 04:14:02 -0600673 throw std::runtime_error("Path parameter is empty.");
674 }
675
676 if (!i_sysCfgJsonObj.contains("frus"))
677 {
678 throw std::runtime_error("Missing frus tag in system config JSON.");
679 }
680
681 // check if given path is FRU path
682 if (i_sysCfgJsonObj["frus"].contains(i_vpdPath))
683 {
684 return i_vpdPath;
685 }
686
687 const nlohmann::json& l_fruList =
688 i_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
689
690 for (const auto& l_fru : l_fruList.items())
691 {
692 const auto l_fruPath = l_fru.key();
693
694 // check if given path is redundant FRU path or inventory path
695 if (i_vpdPath == i_sysCfgJsonObj["frus"][l_fruPath].at(0).value(
696 "redundantEeprom", "") ||
697 (i_vpdPath == i_sysCfgJsonObj["frus"][l_fruPath].at(0).value(
698 "inventoryPath", "")))
699 {
700 return l_fruPath;
701 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500702 }
703 }
RekhaAparna017fea9f52025-02-17 04:14:02 -0600704 catch (const std::exception& l_ex)
705 {
706 logging::logMessage("Failed to get FRU path from JSON, error: " +
707 std::string(l_ex.what()));
708 }
709
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500710 return std::string();
711}
712
713/**
714 * @brief An API to check backup and restore VPD is required.
715 *
716 * The API checks if there is provision for backup and restore mentioned in the
717 * system config JSON, by looking "backupRestoreConfigPath" tag.
718 * Checks if the path mentioned is a hardware path, by checking if the file path
719 * exists and size of contents in the path.
720 *
721 * @param[in] i_sysCfgJsonObj - System config JSON object.
722 *
723 * @return true if backup and restore is required, false otherwise.
724 */
725inline bool isBackupAndRestoreRequired(const nlohmann::json& i_sysCfgJsonObj)
726{
727 try
728 {
729 const std::string& l_backupAndRestoreCfgFilePath =
730 i_sysCfgJsonObj.value("backupRestoreConfigPath", "");
731 if (!l_backupAndRestoreCfgFilePath.empty() &&
732 std::filesystem::exists(l_backupAndRestoreCfgFilePath) &&
733 !std::filesystem::is_empty(l_backupAndRestoreCfgFilePath))
734 {
735 return true;
736 }
737 }
738 catch (std::exception& ex)
739 {
740 logging::logMessage(ex.what());
741 }
742 return false;
743}
744
745/** @brief API to check if an action is required for given EEPROM path.
746 *
747 * System config JSON can contain pre-action, post-action etc. like actions
748 * defined for an EEPROM path. The API will check if any such action is defined
749 * for the EEPROM.
750 *
751 * @param[in] i_sysCfgJsonObj - System config JSON object.
752 * @param[in] i_vpdFruPath - EEPROM path.
753 * @param[in] i_action - Action to be checked.
754 * @param[in] i_flowFlag - Denotes the flow w.r.t which the action should be
755 * triggered.
756 * @return - True if action is defined for the flow, false otherwise.
757 */
758inline bool isActionRequired(
759 const nlohmann::json& i_sysCfgJsonObj, const std::string& i_vpdFruPath,
760 const std::string& i_action, const std::string& i_flowFlag)
761{
762 if (i_vpdFruPath.empty() || i_action.empty() || i_flowFlag.empty())
763 {
764 logging::logMessage("Invalid parameters recieved.");
765 return false;
766 }
767
768 if (!i_sysCfgJsonObj.contains("frus"))
769 {
770 logging::logMessage("Invalid JSON object recieved.");
771 return false;
772 }
773
774 if (!i_sysCfgJsonObj["frus"].contains(i_vpdFruPath))
775 {
776 logging::logMessage(
777 "JSON object does not contain EEPROM path " + i_vpdFruPath);
778 return false;
779 }
780
781 if ((i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0)).contains(i_action))
782 {
783 if ((i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0))[i_action].contains(
784 i_flowFlag))
785 {
786 return true;
787 }
788
789 logging::logMessage("Flow flag: [" + i_flowFlag +
Souvik Roy410d96c2025-05-09 02:30:15 -0500790 "], not found in JSON for path: " + i_vpdFruPath +
791 " while checking for action: " + i_action);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500792 return false;
793 }
794 return false;
795}
796
797/**
798 * @brief An API to return list of FRUs that needs GPIO polling.
799 *
800 * An API that checks for the FRUs that requires GPIO polling and returns
801 * a list of FRUs that needs polling. Returns an empty list if there are
802 * no FRUs that requires polling.
803 *
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500804 * @param[in] i_sysCfgJsonObj - System config JSON object.
805 *
RekhaAparna017fea9f52025-02-17 04:14:02 -0600806 * @return On success list of FRUs parameters that needs polling. On failure,
807 * empty list.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500808 */
Patrick Williams43fedab2025-02-03 14:28:05 -0500809inline std::vector<std::string> getListOfGpioPollingFrus(
RekhaAparna017fea9f52025-02-17 04:14:02 -0600810 const nlohmann::json& i_sysCfgJsonObj) noexcept
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500811{
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500812 std::vector<std::string> l_gpioPollingRequiredFrusList;
813
RekhaAparna017fea9f52025-02-17 04:14:02 -0600814 try
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500815 {
RekhaAparna017fea9f52025-02-17 04:14:02 -0600816 if (i_sysCfgJsonObj.empty())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500817 {
RekhaAparna017fea9f52025-02-17 04:14:02 -0600818 throw std::runtime_error("Invalid Parameters");
819 }
820
821 if (!i_sysCfgJsonObj.contains("frus"))
822 {
823 throw std::runtime_error(
824 "Missing frus section in system config JSON");
825 }
826
827 for (const auto& l_fru : i_sysCfgJsonObj["frus"].items())
828 {
829 const auto l_fruPath = l_fru.key();
830
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500831 if (isActionRequired(i_sysCfgJsonObj, l_fruPath, "pollingRequired",
832 "hotPlugging"))
833 {
834 if (i_sysCfgJsonObj["frus"][l_fruPath]
835 .at(0)["pollingRequired"]["hotPlugging"]
836 .contains("gpioPresence"))
837 {
838 l_gpioPollingRequiredFrusList.push_back(l_fruPath);
839 }
840 }
841 }
RekhaAparna017fea9f52025-02-17 04:14:02 -0600842 }
843 catch (const std::exception& l_ex)
844 {
845 logging::logMessage("Failed to get list of GPIO polling FRUs, error: " +
846 std::string(l_ex.what()));
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500847 }
848
849 return l_gpioPollingRequiredFrusList;
850}
851
852/**
853 * @brief Get all related path(s) to update keyword value.
854 *
855 * Given FRU EEPROM path/Inventory path needs keyword's value update, this API
856 * returns tuple of FRU EEPROM path, inventory path and redundant EEPROM path if
857 * exists in the system config JSON.
858 *
859 * Note: If the inventory object path or redundant EEPROM path(s) are not found
860 * in the system config JSON, corresponding fields will have empty value in the
861 * returning tuple.
862 *
863 * @param[in] i_sysCfgJsonObj - System config JSON object.
864 * @param[in,out] io_vpdPath - Inventory object path or FRU EEPROM path.
865 *
866 * @return On success returns tuple of EEPROM path, inventory path & redundant
867 * path, on failure returns tuple with given input path alone.
868 */
869inline std::tuple<std::string, std::string, std::string>
870 getAllPathsToUpdateKeyword(const nlohmann::json& i_sysCfgJsonObj,
871 std::string io_vpdPath)
872{
873 types::Path l_inventoryObjPath;
874 types::Path l_redundantFruPath;
875 try
876 {
877 if (!i_sysCfgJsonObj.empty())
878 {
879 // Get hardware path from system config JSON.
880 const types::Path l_fruPath =
881 jsonUtility::getFruPathFromJson(i_sysCfgJsonObj, io_vpdPath);
882
883 if (!l_fruPath.empty())
884 {
885 io_vpdPath = l_fruPath;
886
Rekha Aparna017567a2025-08-13 02:07:06 -0500887 uint16_t l_errCode = 0;
888
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500889 // Get inventory object path from system config JSON
890 l_inventoryObjPath = jsonUtility::getInventoryObjPathFromJson(
Rekha Aparna017567a2025-08-13 02:07:06 -0500891 i_sysCfgJsonObj, l_fruPath, l_errCode);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500892
893 // Get redundant hardware path if present in system config JSON
894 l_redundantFruPath =
895 jsonUtility::getRedundantEepromPathFromJson(i_sysCfgJsonObj,
896 l_fruPath);
897 }
898 }
899 }
900 catch (const std::exception& l_exception)
901 {
902 logging::logMessage(
903 "Failed to get all paths to update keyword value, error " +
904 std::string(l_exception.what()));
905 }
906 return std::make_tuple(io_vpdPath, l_inventoryObjPath, l_redundantFruPath);
907}
908
909/**
910 * @brief An API to get DBus service name.
911 *
912 * Given DBus inventory path, this API returns DBus service name if present in
913 * the JSON.
914 *
915 * @param[in] i_sysCfgJsonObj - System config JSON object.
916 * @param[in] l_inventoryPath - DBus inventory path.
917 *
918 * @return On success returns the service name present in the system config
919 * JSON, otherwise empty string.
920 *
921 * Note: Caller has to handle in case of empty string received.
922 */
923inline std::string getServiceName(const nlohmann::json& i_sysCfgJsonObj,
924 const std::string& l_inventoryPath)
925{
926 try
927 {
928 if (l_inventoryPath.empty())
929 {
930 throw std::runtime_error("Path parameter is empty.");
931 }
932
933 if (!i_sysCfgJsonObj.contains("frus"))
934 {
935 throw std::runtime_error("Missing frus tag in system config JSON.");
936 }
937
938 const nlohmann::json& l_listOfFrus =
939 i_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
940
941 for (const auto& l_frus : l_listOfFrus.items())
942 {
943 for (const auto& l_inventoryItem : l_frus.value())
944 {
945 if (l_inventoryPath.compare(l_inventoryItem["inventoryPath"]) ==
946 constants::STR_CMP_SUCCESS)
947 {
948 return l_inventoryItem["serviceName"];
949 }
950 }
951 }
952 throw std::runtime_error(
953 "Inventory path not found in the system config JSON");
954 }
955 catch (const std::exception& l_exception)
956 {
957 logging::logMessage(
958 "Error while getting DBus service name for given path " +
959 l_inventoryPath + ", error: " + std::string(l_exception.what()));
960 // TODO:log PEL
961 }
962 return std::string{};
963}
964
965/**
966 * @brief An API to check if a FRU is tagged as "powerOffOnly"
967 *
968 * Given the system config JSON and VPD FRU path, this API checks if the FRU
969 * VPD can be collected at Chassis Power Off state only.
970 *
971 * @param[in] i_sysCfgJsonObj - System config JSON object.
972 * @param[in] i_vpdFruPath - EEPROM path.
973 * @return - True if FRU VPD can be collected at Chassis Power Off state only.
974 * False otherwise
975 */
976inline bool isFruPowerOffOnly(const nlohmann::json& i_sysCfgJsonObj,
977 const std::string& i_vpdFruPath)
978{
979 if (i_vpdFruPath.empty())
980 {
981 logging::logMessage("FRU path is empty.");
982 return false;
983 }
984
985 if (!i_sysCfgJsonObj.contains("frus"))
986 {
987 logging::logMessage("Missing frus tag in system config JSON.");
988 return false;
989 }
990
991 if (!i_sysCfgJsonObj["frus"].contains(i_vpdFruPath))
992 {
993 logging::logMessage("JSON object does not contain EEPROM path \'" +
994 i_vpdFruPath + "\'");
995 return false;
996 }
997
998 return ((i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0))
999 .contains("powerOffOnly") &&
1000 (i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0)["powerOffOnly"]));
1001}
1002
1003/**
1004 * @brief API which tells if the FRU is replaceable at runtime
1005 *
1006 * @param[in] i_sysCfgJsonObj - System config JSON object.
1007 * @param[in] i_vpdFruPath - EEPROM path.
Rekha Aparnaad0db9e2025-09-01 20:29:18 -05001008 * @param[out] o_errCode - to set error code in case of error.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001009 *
1010 * @return true if FRU is replaceable at runtime. false otherwise.
1011 */
1012inline bool isFruReplaceableAtRuntime(const nlohmann::json& i_sysCfgJsonObj,
Rekha Aparnaad0db9e2025-09-01 20:29:18 -05001013 const std::string& i_vpdFruPath,
1014 uint16_t& o_errCode)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001015{
Rekha Aparnaad0db9e2025-09-01 20:29:18 -05001016 if (i_vpdFruPath.empty())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001017 {
Rekha Aparnaad0db9e2025-09-01 20:29:18 -05001018 o_errCode = error_code::INVALID_INPUT_PARAMETER;
1019 return false;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001020 }
Rekha Aparnaad0db9e2025-09-01 20:29:18 -05001021
1022 if (i_sysCfgJsonObj.empty() || (!i_sysCfgJsonObj.contains("frus")))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001023 {
Rekha Aparnaad0db9e2025-09-01 20:29:18 -05001024 o_errCode = error_code::INVALID_JSON;
1025 return false;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001026 }
1027
Rekha Aparnaad0db9e2025-09-01 20:29:18 -05001028 return (
1029 (i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0))
1030 .contains("replaceableAtRuntime") &&
1031 (i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0)["replaceableAtRuntime"]));
1032
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001033 return false;
1034}
1035
1036/**
1037 * @brief API which tells if the FRU is replaceable at standby
1038 *
1039 * @param[in] i_sysCfgJsonObj - System config JSON object.
1040 * @param[in] i_vpdFruPath - EEPROM path.
Rekha Aparna40845612025-09-01 19:58:56 -05001041 * @param[out] o_errCode - set error code in case of error.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001042 *
1043 * @return true if FRU is replaceable at standby. false otherwise.
1044 */
1045inline bool isFruReplaceableAtStandby(const nlohmann::json& i_sysCfgJsonObj,
Rekha Aparna40845612025-09-01 19:58:56 -05001046 const std::string& i_vpdFruPath,
1047 uint16_t& o_errCode)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001048{
Rekha Aparna40845612025-09-01 19:58:56 -05001049 if (i_vpdFruPath.empty())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001050 {
Rekha Aparna40845612025-09-01 19:58:56 -05001051 o_errCode = error_code::INVALID_INPUT_PARAMETER;
1052 return false;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001053 }
Rekha Aparna40845612025-09-01 19:58:56 -05001054
1055 if (i_sysCfgJsonObj.empty() || (!i_sysCfgJsonObj.contains("frus")))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001056 {
Rekha Aparna40845612025-09-01 19:58:56 -05001057 o_errCode = error_code::INVALID_JSON;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001058 }
1059
Rekha Aparna40845612025-09-01 19:58:56 -05001060 return (
1061 (i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0))
1062 .contains("replaceableAtStandby") &&
1063 (i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0)["replaceableAtStandby"]));
1064
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001065 return false;
1066}
1067
1068/**
1069 * @brief API to get list of FRUs replaceable at standby from JSON.
1070 *
1071 * The API will return a vector of FRUs inventory path which are replaceable at
1072 * standby.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001073 *
1074 * @param[in] i_sysCfgJsonObj - System config JSON object.
1075 *
RekhaAparna017fea9f52025-02-17 04:14:02 -06001076 * @return - On success, list of FRUs replaceable at standby. On failure, empty
1077 * vector.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001078 */
Patrick Williams43fedab2025-02-03 14:28:05 -05001079inline std::vector<std::string> getListOfFrusReplaceableAtStandby(
RekhaAparna017fea9f52025-02-17 04:14:02 -06001080 const nlohmann::json& i_sysCfgJsonObj) noexcept
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001081{
1082 std::vector<std::string> l_frusReplaceableAtStandby;
1083
RekhaAparna017fea9f52025-02-17 04:14:02 -06001084 try
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001085 {
RekhaAparna017fea9f52025-02-17 04:14:02 -06001086 if (!i_sysCfgJsonObj.contains("frus"))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001087 {
RekhaAparna017fea9f52025-02-17 04:14:02 -06001088 throw std::runtime_error("Missing frus tag in system config JSON.");
1089 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001090
RekhaAparna017fea9f52025-02-17 04:14:02 -06001091 const nlohmann::json& l_fruList =
1092 i_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
1093
1094 for (const auto& l_fru : l_fruList.items())
1095 {
1096 if (i_sysCfgJsonObj["frus"][l_fru.key()].at(0).value(
1097 "replaceableAtStandby", false))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001098 {
RekhaAparna017fea9f52025-02-17 04:14:02 -06001099 const std::string& l_inventoryObjectPath =
1100 i_sysCfgJsonObj["frus"][l_fru.key()].at(0).value(
1101 "inventoryPath", "");
1102
1103 if (!l_inventoryObjectPath.empty())
1104 {
1105 l_frusReplaceableAtStandby.emplace_back(
1106 l_inventoryObjectPath);
1107 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001108 }
1109 }
1110 }
RekhaAparna017fea9f52025-02-17 04:14:02 -06001111 catch (const std::exception& l_ex)
1112 {
1113 logging::logMessage(
1114 "Failed to get list of FRUs replaceable at standby, error: " +
1115 std::string(l_ex.what()));
1116 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001117
1118 return l_frusReplaceableAtStandby;
1119}
1120
Sunny Srivastava022112b2025-02-19 19:53:29 +05301121/**
1122 * @brief API to select powerVS JSON based on system IM.
1123 *
1124 * The API selects respective JSON based on system IM, parse it and return the
1125 * JSON object. Empty JSON will be returned in case of any error. Caller needs
1126 * to handle empty value.
1127 *
1128 * @param[in] i_imValue - IM value of the system.
1129 * @return Parsed JSON object, empty JSON otherwise.
1130 */
1131inline nlohmann::json getPowerVsJson(const types::BinaryVector& i_imValue)
1132{
1133 try
1134 {
Rekha Aparnaca9a0862025-08-29 04:08:33 -05001135 uint16_t l_errCode = 0;
Sunny Srivastava022112b2025-02-19 19:53:29 +05301136 if ((i_imValue.at(0) == constants::HEX_VALUE_50) &&
1137 (i_imValue.at(1) == constants::HEX_VALUE_00) &&
1138 (i_imValue.at(2) == constants::HEX_VALUE_30))
1139 {
Rekha Aparnaca9a0862025-08-29 04:08:33 -05001140 nlohmann::json l_parsedJson = jsonUtility::getParsedJson(
1141 constants::power_vs_50003_json, l_errCode);
1142
1143 if (l_errCode)
1144 {
1145 logging::logMessage(
1146 "Failed to parse JSON file [ " +
1147 std::string(constants::power_vs_50003_json) +
1148 " ], error : " +
1149 vpdSpecificUtility::getErrCodeMsg(l_errCode));
1150 }
1151
1152 return l_parsedJson;
Sunny Srivastava022112b2025-02-19 19:53:29 +05301153 }
1154 else if (i_imValue.at(0) == constants::HEX_VALUE_50 &&
1155 (i_imValue.at(1) == constants::HEX_VALUE_00) &&
1156 (i_imValue.at(2) == constants::HEX_VALUE_10))
1157 {
Rekha Aparnaca9a0862025-08-29 04:08:33 -05001158 nlohmann::json l_parsedJson = jsonUtility::getParsedJson(
1159 constants::power_vs_50001_json, l_errCode);
1160
1161 if (l_errCode)
1162 {
1163 logging::logMessage(
1164 "Failed to parse JSON file [ " +
1165 std::string(constants::power_vs_50001_json) +
1166 " ], error : " +
1167 vpdSpecificUtility::getErrCodeMsg(l_errCode));
1168 }
1169
1170 return l_parsedJson;
Sunny Srivastava022112b2025-02-19 19:53:29 +05301171 }
1172 return nlohmann::json{};
1173 }
1174 catch (const std::exception& l_ex)
1175 {
1176 return nlohmann::json{};
1177 }
1178}
Souvik Roy495eedd2025-07-02 02:13:43 -05001179
1180/**
1181 * @brief API to get list of FRUs for which "monitorPresence" is true.
1182 *
1183 * @param[in] i_sysCfgJsonObj - System config JSON object.
Rekha Aparna2362bed2025-09-01 13:18:40 -05001184 * @param[out] o_errCode - To set error code in case of error.
Souvik Roy495eedd2025-07-02 02:13:43 -05001185 *
1186 * @return On success, returns list of FRUs for which "monitorPresence" is true,
1187 * empty list on error.
1188 */
1189inline std::vector<types::Path> getFrusWithPresenceMonitoring(
Rekha Aparna2362bed2025-09-01 13:18:40 -05001190 const nlohmann::json& i_sysCfgJsonObj, uint16_t& o_errCode)
Souvik Roy495eedd2025-07-02 02:13:43 -05001191{
1192 std::vector<types::Path> l_frusWithPresenceMonitoring;
Rekha Aparna2362bed2025-09-01 13:18:40 -05001193
1194 if (!i_sysCfgJsonObj.contains("frus"))
Souvik Roy495eedd2025-07-02 02:13:43 -05001195 {
Rekha Aparna2362bed2025-09-01 13:18:40 -05001196 o_errCode = error_code::INVALID_JSON;
1197 return l_frusWithPresenceMonitoring;
1198 }
Souvik Roy495eedd2025-07-02 02:13:43 -05001199
Rekha Aparna2362bed2025-09-01 13:18:40 -05001200 const nlohmann::json& l_listOfFrus =
1201 i_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
Souvik Roy495eedd2025-07-02 02:13:43 -05001202
Rekha Aparna2362bed2025-09-01 13:18:40 -05001203 for (const auto& l_aFru : l_listOfFrus)
1204 {
1205 if (l_aFru.at(0).value("monitorPresence", false))
Souvik Roy495eedd2025-07-02 02:13:43 -05001206 {
Rekha Aparna2362bed2025-09-01 13:18:40 -05001207 l_frusWithPresenceMonitoring.emplace_back(
1208 l_aFru.at(0).value("inventoryPath", ""));
Souvik Roy495eedd2025-07-02 02:13:43 -05001209 }
1210 }
Rekha Aparna2362bed2025-09-01 13:18:40 -05001211
Souvik Roy495eedd2025-07-02 02:13:43 -05001212 return l_frusWithPresenceMonitoring;
1213}
Souvik Roye9120152025-07-02 08:24:38 -05001214
1215/**
1216 * @brief API which tells if the FRU's presence is handled
1217 *
1218 * For a given FRU, this API checks if it's presence is handled by vpd-manager
1219 * by checking the "handlePresence" tag.
1220 *
1221 * @param[in] i_sysCfgJsonObj - System config JSON object.
1222 * @param[in] i_vpdFruPath - EEPROM path.
Rekha Aparnaa1187a52025-09-01 12:42:19 -05001223 * @param[out] o_errCode - To set error code in case of failure.
Souvik Roye9120152025-07-02 08:24:38 -05001224 *
1225 * @return true if FRU presence is handled, false otherwise.
1226 */
1227inline bool isFruPresenceHandled(const nlohmann::json& i_sysCfgJsonObj,
Rekha Aparnaa1187a52025-09-01 12:42:19 -05001228 const std::string& i_vpdFruPath,
1229 uint16_t& o_errCode)
Souvik Roye9120152025-07-02 08:24:38 -05001230{
Rekha Aparnaa1187a52025-09-01 12:42:19 -05001231 if (i_vpdFruPath.empty())
Souvik Roye9120152025-07-02 08:24:38 -05001232 {
Rekha Aparnaa1187a52025-09-01 12:42:19 -05001233 o_errCode = error_code::INVALID_INPUT_PARAMETER;
1234 return false;
Souvik Roye9120152025-07-02 08:24:38 -05001235 }
1236
Rekha Aparnaa1187a52025-09-01 12:42:19 -05001237 if (!i_sysCfgJsonObj.contains("frus"))
1238 {
1239 o_errCode = error_code::INVALID_JSON;
1240 return false;
1241 }
1242
1243 if (!i_sysCfgJsonObj["frus"].contains(i_vpdFruPath))
1244 {
1245 o_errCode = error_code::FRU_PATH_NOT_FOUND;
1246 return false;
1247 }
1248
1249 return i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0).value(
1250 "handlePresence", true);
Souvik Roye9120152025-07-02 08:24:38 -05001251}
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001252} // namespace jsonUtility
1253} // namespace vpd