blob: 0abbf5b7d37dd154403d6453ad78953afd3f4817 [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.
1008 *
1009 * @return true if FRU is replaceable at runtime. false otherwise.
1010 */
1011inline bool isFruReplaceableAtRuntime(const nlohmann::json& i_sysCfgJsonObj,
1012 const std::string& i_vpdFruPath)
1013{
1014 try
1015 {
1016 if (i_vpdFruPath.empty())
1017 {
1018 throw std::runtime_error("Given FRU path is empty.");
1019 }
1020
1021 if (i_sysCfgJsonObj.empty() || (!i_sysCfgJsonObj.contains("frus")))
1022 {
1023 throw std::runtime_error("Invalid system config JSON object.");
1024 }
1025
1026 return ((i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0))
1027 .contains("replaceableAtRuntime") &&
1028 (i_sysCfgJsonObj["frus"][i_vpdFruPath].at(
1029 0)["replaceableAtRuntime"]));
1030 }
1031 catch (const std::exception& l_error)
1032 {
1033 // TODO: Log PEL
1034 logging::logMessage(l_error.what());
1035 }
1036
1037 return false;
1038}
1039
1040/**
1041 * @brief API which tells if the FRU is replaceable at standby
1042 *
1043 * @param[in] i_sysCfgJsonObj - System config JSON object.
1044 * @param[in] i_vpdFruPath - EEPROM path.
Rekha Aparna40845612025-09-01 19:58:56 -05001045 * @param[out] o_errCode - set error code in case of error.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001046 *
1047 * @return true if FRU is replaceable at standby. false otherwise.
1048 */
1049inline bool isFruReplaceableAtStandby(const nlohmann::json& i_sysCfgJsonObj,
Rekha Aparna40845612025-09-01 19:58:56 -05001050 const std::string& i_vpdFruPath,
1051 uint16_t& o_errCode)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001052{
Rekha Aparna40845612025-09-01 19:58:56 -05001053 if (i_vpdFruPath.empty())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001054 {
Rekha Aparna40845612025-09-01 19:58:56 -05001055 o_errCode = error_code::INVALID_INPUT_PARAMETER;
1056 return false;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001057 }
Rekha Aparna40845612025-09-01 19:58:56 -05001058
1059 if (i_sysCfgJsonObj.empty() || (!i_sysCfgJsonObj.contains("frus")))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001060 {
Rekha Aparna40845612025-09-01 19:58:56 -05001061 o_errCode = error_code::INVALID_JSON;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001062 }
1063
Rekha Aparna40845612025-09-01 19:58:56 -05001064 return (
1065 (i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0))
1066 .contains("replaceableAtStandby") &&
1067 (i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0)["replaceableAtStandby"]));
1068
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001069 return false;
1070}
1071
1072/**
1073 * @brief API to get list of FRUs replaceable at standby from JSON.
1074 *
1075 * The API will return a vector of FRUs inventory path which are replaceable at
1076 * standby.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001077 *
1078 * @param[in] i_sysCfgJsonObj - System config JSON object.
1079 *
RekhaAparna017fea9f52025-02-17 04:14:02 -06001080 * @return - On success, list of FRUs replaceable at standby. On failure, empty
1081 * vector.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001082 */
Patrick Williams43fedab2025-02-03 14:28:05 -05001083inline std::vector<std::string> getListOfFrusReplaceableAtStandby(
RekhaAparna017fea9f52025-02-17 04:14:02 -06001084 const nlohmann::json& i_sysCfgJsonObj) noexcept
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001085{
1086 std::vector<std::string> l_frusReplaceableAtStandby;
1087
RekhaAparna017fea9f52025-02-17 04:14:02 -06001088 try
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001089 {
RekhaAparna017fea9f52025-02-17 04:14:02 -06001090 if (!i_sysCfgJsonObj.contains("frus"))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001091 {
RekhaAparna017fea9f52025-02-17 04:14:02 -06001092 throw std::runtime_error("Missing frus tag in system config JSON.");
1093 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001094
RekhaAparna017fea9f52025-02-17 04:14:02 -06001095 const nlohmann::json& l_fruList =
1096 i_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
1097
1098 for (const auto& l_fru : l_fruList.items())
1099 {
1100 if (i_sysCfgJsonObj["frus"][l_fru.key()].at(0).value(
1101 "replaceableAtStandby", false))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001102 {
RekhaAparna017fea9f52025-02-17 04:14:02 -06001103 const std::string& l_inventoryObjectPath =
1104 i_sysCfgJsonObj["frus"][l_fru.key()].at(0).value(
1105 "inventoryPath", "");
1106
1107 if (!l_inventoryObjectPath.empty())
1108 {
1109 l_frusReplaceableAtStandby.emplace_back(
1110 l_inventoryObjectPath);
1111 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001112 }
1113 }
1114 }
RekhaAparna017fea9f52025-02-17 04:14:02 -06001115 catch (const std::exception& l_ex)
1116 {
1117 logging::logMessage(
1118 "Failed to get list of FRUs replaceable at standby, error: " +
1119 std::string(l_ex.what()));
1120 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001121
1122 return l_frusReplaceableAtStandby;
1123}
1124
Sunny Srivastava022112b2025-02-19 19:53:29 +05301125/**
1126 * @brief API to select powerVS JSON based on system IM.
1127 *
1128 * The API selects respective JSON based on system IM, parse it and return the
1129 * JSON object. Empty JSON will be returned in case of any error. Caller needs
1130 * to handle empty value.
1131 *
1132 * @param[in] i_imValue - IM value of the system.
1133 * @return Parsed JSON object, empty JSON otherwise.
1134 */
1135inline nlohmann::json getPowerVsJson(const types::BinaryVector& i_imValue)
1136{
1137 try
1138 {
Rekha Aparnaca9a0862025-08-29 04:08:33 -05001139 uint16_t l_errCode = 0;
Sunny Srivastava022112b2025-02-19 19:53:29 +05301140 if ((i_imValue.at(0) == constants::HEX_VALUE_50) &&
1141 (i_imValue.at(1) == constants::HEX_VALUE_00) &&
1142 (i_imValue.at(2) == constants::HEX_VALUE_30))
1143 {
Rekha Aparnaca9a0862025-08-29 04:08:33 -05001144 nlohmann::json l_parsedJson = jsonUtility::getParsedJson(
1145 constants::power_vs_50003_json, l_errCode);
1146
1147 if (l_errCode)
1148 {
1149 logging::logMessage(
1150 "Failed to parse JSON file [ " +
1151 std::string(constants::power_vs_50003_json) +
1152 " ], error : " +
1153 vpdSpecificUtility::getErrCodeMsg(l_errCode));
1154 }
1155
1156 return l_parsedJson;
Sunny Srivastava022112b2025-02-19 19:53:29 +05301157 }
1158 else if (i_imValue.at(0) == constants::HEX_VALUE_50 &&
1159 (i_imValue.at(1) == constants::HEX_VALUE_00) &&
1160 (i_imValue.at(2) == constants::HEX_VALUE_10))
1161 {
Rekha Aparnaca9a0862025-08-29 04:08:33 -05001162 nlohmann::json l_parsedJson = jsonUtility::getParsedJson(
1163 constants::power_vs_50001_json, l_errCode);
1164
1165 if (l_errCode)
1166 {
1167 logging::logMessage(
1168 "Failed to parse JSON file [ " +
1169 std::string(constants::power_vs_50001_json) +
1170 " ], error : " +
1171 vpdSpecificUtility::getErrCodeMsg(l_errCode));
1172 }
1173
1174 return l_parsedJson;
Sunny Srivastava022112b2025-02-19 19:53:29 +05301175 }
1176 return nlohmann::json{};
1177 }
1178 catch (const std::exception& l_ex)
1179 {
1180 return nlohmann::json{};
1181 }
1182}
Souvik Roy495eedd2025-07-02 02:13:43 -05001183
1184/**
1185 * @brief API to get list of FRUs for which "monitorPresence" is true.
1186 *
1187 * @param[in] i_sysCfgJsonObj - System config JSON object.
Rekha Aparna2362bed2025-09-01 13:18:40 -05001188 * @param[out] o_errCode - To set error code in case of error.
Souvik Roy495eedd2025-07-02 02:13:43 -05001189 *
1190 * @return On success, returns list of FRUs for which "monitorPresence" is true,
1191 * empty list on error.
1192 */
1193inline std::vector<types::Path> getFrusWithPresenceMonitoring(
Rekha Aparna2362bed2025-09-01 13:18:40 -05001194 const nlohmann::json& i_sysCfgJsonObj, uint16_t& o_errCode)
Souvik Roy495eedd2025-07-02 02:13:43 -05001195{
1196 std::vector<types::Path> l_frusWithPresenceMonitoring;
Rekha Aparna2362bed2025-09-01 13:18:40 -05001197
1198 if (!i_sysCfgJsonObj.contains("frus"))
Souvik Roy495eedd2025-07-02 02:13:43 -05001199 {
Rekha Aparna2362bed2025-09-01 13:18:40 -05001200 o_errCode = error_code::INVALID_JSON;
1201 return l_frusWithPresenceMonitoring;
1202 }
Souvik Roy495eedd2025-07-02 02:13:43 -05001203
Rekha Aparna2362bed2025-09-01 13:18:40 -05001204 const nlohmann::json& l_listOfFrus =
1205 i_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
Souvik Roy495eedd2025-07-02 02:13:43 -05001206
Rekha Aparna2362bed2025-09-01 13:18:40 -05001207 for (const auto& l_aFru : l_listOfFrus)
1208 {
1209 if (l_aFru.at(0).value("monitorPresence", false))
Souvik Roy495eedd2025-07-02 02:13:43 -05001210 {
Rekha Aparna2362bed2025-09-01 13:18:40 -05001211 l_frusWithPresenceMonitoring.emplace_back(
1212 l_aFru.at(0).value("inventoryPath", ""));
Souvik Roy495eedd2025-07-02 02:13:43 -05001213 }
1214 }
Rekha Aparna2362bed2025-09-01 13:18:40 -05001215
Souvik Roy495eedd2025-07-02 02:13:43 -05001216 return l_frusWithPresenceMonitoring;
1217}
Souvik Roye9120152025-07-02 08:24:38 -05001218
1219/**
1220 * @brief API which tells if the FRU's presence is handled
1221 *
1222 * For a given FRU, this API checks if it's presence is handled by vpd-manager
1223 * by checking the "handlePresence" tag.
1224 *
1225 * @param[in] i_sysCfgJsonObj - System config JSON object.
1226 * @param[in] i_vpdFruPath - EEPROM path.
Rekha Aparnaa1187a52025-09-01 12:42:19 -05001227 * @param[out] o_errCode - To set error code in case of failure.
Souvik Roye9120152025-07-02 08:24:38 -05001228 *
1229 * @return true if FRU presence is handled, false otherwise.
1230 */
1231inline bool isFruPresenceHandled(const nlohmann::json& i_sysCfgJsonObj,
Rekha Aparnaa1187a52025-09-01 12:42:19 -05001232 const std::string& i_vpdFruPath,
1233 uint16_t& o_errCode)
Souvik Roye9120152025-07-02 08:24:38 -05001234{
Rekha Aparnaa1187a52025-09-01 12:42:19 -05001235 if (i_vpdFruPath.empty())
Souvik Roye9120152025-07-02 08:24:38 -05001236 {
Rekha Aparnaa1187a52025-09-01 12:42:19 -05001237 o_errCode = error_code::INVALID_INPUT_PARAMETER;
1238 return false;
Souvik Roye9120152025-07-02 08:24:38 -05001239 }
1240
Rekha Aparnaa1187a52025-09-01 12:42:19 -05001241 if (!i_sysCfgJsonObj.contains("frus"))
1242 {
1243 o_errCode = error_code::INVALID_JSON;
1244 return false;
1245 }
1246
1247 if (!i_sysCfgJsonObj["frus"].contains(i_vpdFruPath))
1248 {
1249 o_errCode = error_code::FRU_PATH_NOT_FOUND;
1250 return false;
1251 }
1252
1253 return i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0).value(
1254 "handlePresence", true);
Souvik Roye9120152025-07-02 08:24:38 -05001255}
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001256} // namespace jsonUtility
1257} // namespace vpd