blob: 66be4fe6fe4f11cd6bb8175a72732d0743bea21e [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
211 * under PostFailAction tag of config JSON.
212 * @return - success or failure
213 */
214inline bool executePostFailAction(const nlohmann::json& i_parsedConfigJson,
215 const std::string& i_vpdFilePath,
216 const std::string& i_flagToProcess)
217{
RekhaAparna01c11e8b62025-02-20 00:34:35 -0600218 try
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500219 {
RekhaAparna01c11e8b62025-02-20 00:34:35 -0600220 if (i_parsedConfigJson.empty() || i_vpdFilePath.empty() ||
221 i_flagToProcess.empty())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500222 {
RekhaAparna01c11e8b62025-02-20 00:34:35 -0600223 throw std::runtime_error(
224 "Invalid parameters. Abort processing for post fail action");
225 }
226
227 if (!(i_parsedConfigJson["frus"][i_vpdFilePath].at(0))["postFailAction"]
228 .contains(i_flagToProcess))
229 {
230 throw std::runtime_error(
231 "Config JSON missing flag " + i_flagToProcess +
232 " to execute post fail action for path = " + i_vpdFilePath);
233 }
234
235 for (const auto& l_tags : (i_parsedConfigJson["frus"][i_vpdFilePath].at(
236 0))["postFailAction"][i_flagToProcess]
237 .items())
238 {
239 auto itrToFunction = funcionMap.find(l_tags.key());
240 if (itrToFunction != funcionMap.end())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500241 {
RekhaAparna01c11e8b62025-02-20 00:34:35 -0600242 if (!itrToFunction->second(i_parsedConfigJson, i_vpdFilePath,
243 "postFailAction", i_flagToProcess))
244 {
245 return false;
246 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500247 }
248 }
249 }
RekhaAparna01c11e8b62025-02-20 00:34:35 -0600250 catch (const std::exception& l_ex)
251 {
252 logging::logMessage("Execute post fail action failed. Error : " +
253 std::string(l_ex.what()));
254 return false;
255 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500256
257 return true;
258}
259
260/**
261 * @brief Process "systemCmd" tag for a given FRU.
262 *
263 * The API will process "systemCmd" tag if it is defined in the config
264 * JSON for the given FRU.
265 *
266 * @param[in] i_parsedConfigJson - config JSON
267 * @param[in] i_vpdFilePath - EEPROM file path
268 * @param[in] i_baseAction - Base action for which this tag has been called.
269 * @param[in] i_flagToProcess - Flag nested under the base action for which this
270 * tag has been called.
271 * @return Execution status.
272 */
273inline bool processSystemCmdTag(
274 const nlohmann::json& i_parsedConfigJson, const std::string& i_vpdFilePath,
275 const std::string& i_baseAction, const std::string& i_flagToProcess)
276{
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500277 try
278 {
RekhaAparna01c11e8b62025-02-20 00:34:35 -0600279 if (i_vpdFilePath.empty() || i_parsedConfigJson.empty() ||
280 i_baseAction.empty() || i_flagToProcess.empty())
281 {
282 throw std::runtime_error(
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530283 std::string(__FUNCTION__) +
284 " Invalid parameter. Abort processing of processSystemCmd.");
RekhaAparna01c11e8b62025-02-20 00:34:35 -0600285 }
286
287 if (!((i_parsedConfigJson["frus"][i_vpdFilePath].at(
288 0)[i_baseAction][i_flagToProcess]["systemCmd"])
289 .contains("cmd")))
290 {
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530291 throw JsonException(
292 std::string(__FUNCTION__) +
293 " Config JSON missing required information to execute system command for EEPROM " +
RekhaAparna01c11e8b62025-02-20 00:34:35 -0600294 i_vpdFilePath);
295 }
296
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500297 const std::string& l_systemCommand =
298 i_parsedConfigJson["frus"][i_vpdFilePath].at(
299 0)[i_baseAction][i_flagToProcess]["systemCmd"]["cmd"];
300
301 commonUtility::executeCmd(l_systemCommand);
302 return true;
303 }
RekhaAparna01c11e8b62025-02-20 00:34:35 -0600304 catch (const std::exception& l_ex)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500305 {
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530306 EventLogger::createSyncPel(
307 EventLogger::getErrorType(l_ex), types::SeverityType::Informational,
308 __FILE__, __FUNCTION__, 0, EventLogger::getErrorMsg(l_ex),
309 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500310 return false;
311 }
312}
313
314/**
315 * @brief Checks for presence of a given FRU using GPIO line.
316 *
317 * This API returns the presence information of the FRU corresponding to the
318 * given VPD file path by setting the presence pin.
319 *
320 * @param[in] i_parsedConfigJson - config JSON
321 * @param[in] i_vpdFilePath - EEPROM file path
322 * @param[in] i_baseAction - Base action for which this tag has been called.
323 * @param[in] i_flagToProcess - Flag nested under the base action for which this
324 * tag has been called.
325 * @return Execution status.
326 */
327inline bool processGpioPresenceTag(
328 const nlohmann::json& i_parsedConfigJson, const std::string& i_vpdFilePath,
329 const std::string& i_baseAction, const std::string& i_flagToProcess)
330{
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530331 std::string l_presencePinName;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500332 try
333 {
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530334 if (i_vpdFilePath.empty() || i_parsedConfigJson.empty() ||
335 i_baseAction.empty() || i_flagToProcess.empty())
336 {
337 throw std::runtime_error(
338 std::string(__FUNCTION__) +
339 "Invalid parameter. Abort processing of processGpioPresence tag");
340 }
341
342 if (!(((i_parsedConfigJson["frus"][i_vpdFilePath].at(
343 0)[i_baseAction][i_flagToProcess]["gpioPresence"])
344 .contains("pin")) &&
345 ((i_parsedConfigJson["frus"][i_vpdFilePath].at(
346 0)[i_baseAction][i_flagToProcess]["gpioPresence"])
347 .contains("value"))))
348 {
349 throw JsonException(
350 std::string(__FUNCTION__) +
351 "Config JSON missing required information to detect presence for EEPROM " +
352 i_vpdFilePath);
353 }
354
355 // get the pin name
356 l_presencePinName = i_parsedConfigJson["frus"][i_vpdFilePath].at(
357 0)[i_baseAction][i_flagToProcess]["gpioPresence"]["pin"];
358
359 // get the pin value
360 uint8_t l_presencePinValue =
361 i_parsedConfigJson["frus"][i_vpdFilePath].at(
362 0)[i_baseAction][i_flagToProcess]["gpioPresence"]["value"];
363
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500364 gpiod::line l_presenceLine = gpiod::find_line(l_presencePinName);
365
366 if (!l_presenceLine)
367 {
368 throw GpioException("Couldn't find the GPIO line.");
369 }
370
371 l_presenceLine.request({"Read the presence line",
372 gpiod::line_request::DIRECTION_INPUT, 0});
373
374 return (l_presencePinValue == l_presenceLine.get_value());
375 }
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530376 catch (const std::exception& l_ex)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500377 {
Sunny Srivastavac09e2102025-04-23 10:47:06 +0530378 // No need to continue in case of JSON failure or Firmware error
379 // as these are errors internal to the code and in that case the FRU
380 // should not be processed. Any other error is considered as external
381 // error in this case and a try to read the EEPROM should be done.
382 if (EventLogger::getErrorType(l_ex) == types::ErrorType::JsonFailure ||
383 EventLogger::getErrorType(l_ex) == types::ErrorType::FirmwareError)
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530384 {
385 EventLogger::createSyncPel(
386 EventLogger::getErrorType(l_ex),
387 types::SeverityType::Informational, __FILE__, __FUNCTION__, 0,
388 EventLogger::getErrorMsg(l_ex), std::nullopt, std::nullopt,
389 std::nullopt, std::nullopt);
390 return false;
391 }
392
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500393 std::string l_errMsg = "Exception on GPIO line: ";
394 l_errMsg += l_presencePinName;
395 l_errMsg += " Reason: ";
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530396 l_errMsg += l_ex.what();
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500397 l_errMsg += " File: " + i_vpdFilePath + " Pel Logged";
398
Rekha Aparna017567a2025-08-13 02:07:06 -0500399 uint16_t l_errCode = 0;
400
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500401 // ToDo -- Update Internal Rc code.
402 EventLogger::createAsyncPelWithInventoryCallout(
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530403 EventLogger::getErrorType(l_ex), types::SeverityType::Informational,
Rekha Aparna017567a2025-08-13 02:07:06 -0500404 {{getInventoryObjPathFromJson(i_parsedConfigJson, i_vpdFilePath,
405 l_errCode),
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500406 types::CalloutPriority::High}},
407 std::source_location::current().file_name(),
408 std::source_location::current().function_name(), 0, l_errMsg,
409 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
410
411 logging::logMessage(l_errMsg);
412
413 // Except when GPIO pin value is false, we go and try collecting the
414 // FRU VPD as we couldn't able to read GPIO pin value due to some
415 // error/exception. So returning true in error scenario.
416 return true;
417 }
418}
419
420/**
421 * @brief Process "setGpio" tag for a given FRU.
422 *
423 * This API enables the GPIO line.
424 *
425 * @param[in] i_parsedConfigJson - config JSON
426 * @param[in] i_vpdFilePath - EEPROM file path
427 * @param[in] i_baseAction - Base action for which this tag has been called.
428 * @param[in] i_flagToProcess - Flag nested under the base action for which this
429 * tag has been called.
430 * @return Execution status.
431 */
432inline bool procesSetGpioTag(
433 const nlohmann::json& i_parsedConfigJson, const std::string& i_vpdFilePath,
434 const std::string& i_baseAction, const std::string& i_flagToProcess)
435{
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530436 std::string l_pinName;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500437 try
438 {
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530439 if (i_vpdFilePath.empty() || i_parsedConfigJson.empty() ||
440 i_baseAction.empty() || i_flagToProcess.empty())
441 {
442 throw std::runtime_error(
443 std::string(__FUNCTION__) +
444 " Invalid parameter. Abort processing of procesSetGpio.");
445 }
446
447 if (!(((i_parsedConfigJson["frus"][i_vpdFilePath].at(
448 0)[i_baseAction][i_flagToProcess]["setGpio"])
449 .contains("pin")) &&
450 ((i_parsedConfigJson["frus"][i_vpdFilePath].at(
451 0)[i_baseAction][i_flagToProcess]["setGpio"])
452 .contains("value"))))
453 {
454 throw JsonException(
455 std::string(__FUNCTION__) +
456 " Config JSON missing required information to set gpio line for EEPROM " +
457 i_vpdFilePath);
458 }
459
460 l_pinName = i_parsedConfigJson["frus"][i_vpdFilePath].at(
461 0)[i_baseAction][i_flagToProcess]["setGpio"]["pin"];
462
463 // Get the value to set
464 uint8_t l_pinValue = i_parsedConfigJson["frus"][i_vpdFilePath].at(
465 0)[i_baseAction][i_flagToProcess]["setGpio"]["value"];
466
467 logging::logMessage(
468 "Setting GPIO: " + l_pinName + " to " + std::to_string(l_pinValue));
469
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500470 gpiod::line l_outputLine = gpiod::find_line(l_pinName);
471
472 if (!l_outputLine)
473 {
474 throw GpioException("Couldn't find GPIO line.");
475 }
476
477 l_outputLine.request(
478 {"FRU Action", ::gpiod::line_request::DIRECTION_OUTPUT, 0},
479 l_pinValue);
480 return true;
481 }
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530482 catch (const std::exception& l_ex)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500483 {
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530484 if (EventLogger::getErrorType(l_ex) != types::ErrorType::GpioError)
485 {
486 EventLogger::createSyncPel(
487 EventLogger::getErrorType(l_ex),
488 types::SeverityType::Informational, __FILE__, __FUNCTION__, 0,
489 EventLogger::getErrorMsg(l_ex), std::nullopt, std::nullopt,
490 std::nullopt, std::nullopt);
491 }
492 else
493 {
494 std::string l_errMsg = "Exception on GPIO line: ";
495 l_errMsg += l_pinName;
496 l_errMsg += " Reason: ";
497 l_errMsg += l_ex.what();
498 l_errMsg += " File: " + i_vpdFilePath + " Pel Logged";
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500499
Rekha Aparna017567a2025-08-13 02:07:06 -0500500 uint16_t l_errCode = 0;
501
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530502 // ToDo -- Update Internal RC code
503 EventLogger::createAsyncPelWithInventoryCallout(
504 EventLogger::getErrorType(l_ex),
505 types::SeverityType::Informational,
Rekha Aparna017567a2025-08-13 02:07:06 -0500506 {{getInventoryObjPathFromJson(i_parsedConfigJson, i_vpdFilePath,
507 l_errCode),
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530508 types::CalloutPriority::High}},
509 std::source_location::current().file_name(),
510 std::source_location::current().function_name(), 0, l_errMsg,
511 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500512
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530513 logging::logMessage(l_errMsg);
514 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500515
516 return false;
517 }
518}
519
520/**
521 * @brief Process any action, if defined in config JSON.
522 *
523 * If any FRU(s) requires any special handling, then this base action can be
524 * defined for that FRU in the config JSON, processing of which will be handled
525 * in this API.
526 * Examples of action - preAction, PostAction etc.
527 *
528 * @param[in] i_parsedConfigJson - config JSON
529 * @param[in] i_action - Base action to be performed.
530 * @param[in] i_vpdFilePath - EEPROM file path
531 * @param[in] i_flagToProcess - To identify which flag(s) needs to be processed
532 * under PreAction tag of config JSON.
533 * @return - success or failure
534 */
535inline bool executeBaseAction(
536 const nlohmann::json& i_parsedConfigJson, const std::string& i_action,
537 const std::string& i_vpdFilePath, const std::string& i_flagToProcess)
538{
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530539 try
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500540 {
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530541 if (i_flagToProcess.empty() || i_action.empty() ||
542 i_vpdFilePath.empty() || !i_parsedConfigJson.contains("frus"))
543 {
544 throw std::runtime_error(
545 std::string(__FUNCTION__) + " Invalid parameter");
546 }
547
548 if (!i_parsedConfigJson["frus"].contains(i_vpdFilePath))
549 {
550 throw JsonException(std::string(__FUNCTION__) + " File path: " +
551 i_vpdFilePath + " not found in JSON");
552 }
553
554 if (!i_parsedConfigJson["frus"][i_vpdFilePath].at(0).contains(i_action))
555 {
556 throw JsonException(
557 std::string(__FUNCTION__) + " Action [" + i_action +
558 "] not defined for file path:" + i_vpdFilePath);
559 }
560
561 if (!(i_parsedConfigJson["frus"][i_vpdFilePath].at(0))[i_action]
562 .contains(i_flagToProcess))
563 {
564 throw JsonException(
565 std::string(__FUNCTION__) + "Config JSON missing flag [" +
566 i_flagToProcess +
567 "] to execute action for path = " + i_vpdFilePath);
568 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500569 }
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530570 catch (const std::exception& l_ex)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500571 {
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530572 EventLogger::createSyncPel(
573 EventLogger::getErrorType(l_ex), types::SeverityType::Informational,
574 __FILE__, __FUNCTION__, 0, EventLogger::getErrorMsg(l_ex),
575 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500576 return false;
577 }
578
579 const nlohmann::json& l_tagsJson =
580 (i_parsedConfigJson["frus"][i_vpdFilePath].at(
581 0))[i_action][i_flagToProcess];
582
583 for (const auto& l_tag : l_tagsJson.items())
584 {
585 auto itrToFunction = funcionMap.find(l_tag.key());
586 if (itrToFunction != funcionMap.end())
587 {
588 if (!itrToFunction->second(i_parsedConfigJson, i_vpdFilePath,
589 i_action, i_flagToProcess))
590 {
591 // In case any of the tag fails to execute. Mark action
592 // as failed for that flag.
593 return false;
594 }
595 }
596 }
597
598 return true;
599}
600
601/**
602 * @brief Get redundant FRU path from system config JSON
603 *
604 * Given either D-bus inventory path/FRU path/redundant FRU path, this
605 * API returns the redundant FRU path taken from "redundantEeprom" tag from
606 * system config JSON.
607 *
608 * @param[in] i_sysCfgJsonObj - System config JSON object.
609 * @param[in] i_vpdPath - Path to where VPD is stored.
610 *
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500611 * @return On success return valid path, on failure return empty string.
612 */
613inline std::string getRedundantEepromPathFromJson(
RekhaAparna017fea9f52025-02-17 04:14:02 -0600614 const nlohmann::json& i_sysCfgJsonObj,
615 const std::string& i_vpdPath) noexcept
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500616{
RekhaAparna017fea9f52025-02-17 04:14:02 -0600617 try
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500618 {
RekhaAparna017fea9f52025-02-17 04:14:02 -0600619 if (i_vpdPath.empty())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500620 {
RekhaAparna017fea9f52025-02-17 04:14:02 -0600621 throw std::runtime_error("Path parameter is empty.");
622 }
623
624 if (!i_sysCfgJsonObj.contains("frus"))
625 {
626 throw std::runtime_error("Missing frus tag in system config JSON.");
627 }
628
629 // check if given path is FRU path
630 if (i_sysCfgJsonObj["frus"].contains(i_vpdPath))
631 {
632 return i_sysCfgJsonObj["frus"][i_vpdPath].at(0).value(
633 "redundantEeprom", "");
634 }
635
636 const nlohmann::json& l_fruList =
637 i_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
638
639 for (const auto& l_fru : l_fruList.items())
640 {
641 const std::string& l_fruPath = l_fru.key();
642 const std::string& l_redundantFruPath =
643 i_sysCfgJsonObj["frus"][l_fruPath].at(0).value(
644 "redundantEeprom", "");
645
646 // check if given path is inventory path or redundant FRU path
647 if ((i_sysCfgJsonObj["frus"][l_fruPath].at(0).value(
648 "inventoryPath", "") == i_vpdPath) ||
649 (l_redundantFruPath == i_vpdPath))
650 {
651 return l_redundantFruPath;
652 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500653 }
654 }
RekhaAparna017fea9f52025-02-17 04:14:02 -0600655 catch (const std::exception& l_ex)
656 {
657 logging::logMessage("Failed to get redundant EEPROM path, error: " +
658 std::string(l_ex.what()));
659 }
660
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500661 return std::string();
662}
663
664/**
665 * @brief Get FRU EEPROM path from system config JSON
666 *
667 * Given either D-bus inventory path/FRU EEPROM path/redundant EEPROM path,
668 * this API returns FRU EEPROM path if present in JSON.
669 *
670 * @param[in] i_sysCfgJsonObj - System config JSON object
671 * @param[in] i_vpdPath - Path to where VPD is stored.
672 *
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500673 * @return On success return valid path, on failure return empty string.
674 */
675inline std::string getFruPathFromJson(const nlohmann::json& i_sysCfgJsonObj,
RekhaAparna017fea9f52025-02-17 04:14:02 -0600676 const std::string& i_vpdPath) noexcept
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500677{
RekhaAparna017fea9f52025-02-17 04:14:02 -0600678 try
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500679 {
RekhaAparna017fea9f52025-02-17 04:14:02 -0600680 if (i_vpdPath.empty())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500681 {
RekhaAparna017fea9f52025-02-17 04:14:02 -0600682 throw std::runtime_error("Path parameter is empty.");
683 }
684
685 if (!i_sysCfgJsonObj.contains("frus"))
686 {
687 throw std::runtime_error("Missing frus tag in system config JSON.");
688 }
689
690 // check if given path is FRU path
691 if (i_sysCfgJsonObj["frus"].contains(i_vpdPath))
692 {
693 return i_vpdPath;
694 }
695
696 const nlohmann::json& l_fruList =
697 i_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
698
699 for (const auto& l_fru : l_fruList.items())
700 {
701 const auto l_fruPath = l_fru.key();
702
703 // check if given path is redundant FRU path or inventory path
704 if (i_vpdPath == i_sysCfgJsonObj["frus"][l_fruPath].at(0).value(
705 "redundantEeprom", "") ||
706 (i_vpdPath == i_sysCfgJsonObj["frus"][l_fruPath].at(0).value(
707 "inventoryPath", "")))
708 {
709 return l_fruPath;
710 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500711 }
712 }
RekhaAparna017fea9f52025-02-17 04:14:02 -0600713 catch (const std::exception& l_ex)
714 {
715 logging::logMessage("Failed to get FRU path from JSON, error: " +
716 std::string(l_ex.what()));
717 }
718
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500719 return std::string();
720}
721
722/**
723 * @brief An API to check backup and restore VPD is required.
724 *
725 * The API checks if there is provision for backup and restore mentioned in the
726 * system config JSON, by looking "backupRestoreConfigPath" tag.
727 * Checks if the path mentioned is a hardware path, by checking if the file path
728 * exists and size of contents in the path.
729 *
730 * @param[in] i_sysCfgJsonObj - System config JSON object.
731 *
732 * @return true if backup and restore is required, false otherwise.
733 */
734inline bool isBackupAndRestoreRequired(const nlohmann::json& i_sysCfgJsonObj)
735{
736 try
737 {
738 const std::string& l_backupAndRestoreCfgFilePath =
739 i_sysCfgJsonObj.value("backupRestoreConfigPath", "");
740 if (!l_backupAndRestoreCfgFilePath.empty() &&
741 std::filesystem::exists(l_backupAndRestoreCfgFilePath) &&
742 !std::filesystem::is_empty(l_backupAndRestoreCfgFilePath))
743 {
744 return true;
745 }
746 }
747 catch (std::exception& ex)
748 {
749 logging::logMessage(ex.what());
750 }
751 return false;
752}
753
754/** @brief API to check if an action is required for given EEPROM path.
755 *
756 * System config JSON can contain pre-action, post-action etc. like actions
757 * defined for an EEPROM path. The API will check if any such action is defined
758 * for the EEPROM.
759 *
760 * @param[in] i_sysCfgJsonObj - System config JSON object.
761 * @param[in] i_vpdFruPath - EEPROM path.
762 * @param[in] i_action - Action to be checked.
763 * @param[in] i_flowFlag - Denotes the flow w.r.t which the action should be
764 * triggered.
765 * @return - True if action is defined for the flow, false otherwise.
766 */
767inline bool isActionRequired(
768 const nlohmann::json& i_sysCfgJsonObj, const std::string& i_vpdFruPath,
769 const std::string& i_action, const std::string& i_flowFlag)
770{
771 if (i_vpdFruPath.empty() || i_action.empty() || i_flowFlag.empty())
772 {
773 logging::logMessage("Invalid parameters recieved.");
774 return false;
775 }
776
777 if (!i_sysCfgJsonObj.contains("frus"))
778 {
779 logging::logMessage("Invalid JSON object recieved.");
780 return false;
781 }
782
783 if (!i_sysCfgJsonObj["frus"].contains(i_vpdFruPath))
784 {
785 logging::logMessage(
786 "JSON object does not contain EEPROM path " + i_vpdFruPath);
787 return false;
788 }
789
790 if ((i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0)).contains(i_action))
791 {
792 if ((i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0))[i_action].contains(
793 i_flowFlag))
794 {
795 return true;
796 }
797
798 logging::logMessage("Flow flag: [" + i_flowFlag +
Souvik Roy410d96c2025-05-09 02:30:15 -0500799 "], not found in JSON for path: " + i_vpdFruPath +
800 " while checking for action: " + i_action);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500801 return false;
802 }
803 return false;
804}
805
806/**
807 * @brief An API to return list of FRUs that needs GPIO polling.
808 *
809 * An API that checks for the FRUs that requires GPIO polling and returns
810 * a list of FRUs that needs polling. Returns an empty list if there are
811 * no FRUs that requires polling.
812 *
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500813 * @param[in] i_sysCfgJsonObj - System config JSON object.
814 *
RekhaAparna017fea9f52025-02-17 04:14:02 -0600815 * @return On success list of FRUs parameters that needs polling. On failure,
816 * empty list.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500817 */
Patrick Williams43fedab2025-02-03 14:28:05 -0500818inline std::vector<std::string> getListOfGpioPollingFrus(
RekhaAparna017fea9f52025-02-17 04:14:02 -0600819 const nlohmann::json& i_sysCfgJsonObj) noexcept
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500820{
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500821 std::vector<std::string> l_gpioPollingRequiredFrusList;
822
RekhaAparna017fea9f52025-02-17 04:14:02 -0600823 try
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500824 {
RekhaAparna017fea9f52025-02-17 04:14:02 -0600825 if (i_sysCfgJsonObj.empty())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500826 {
RekhaAparna017fea9f52025-02-17 04:14:02 -0600827 throw std::runtime_error("Invalid Parameters");
828 }
829
830 if (!i_sysCfgJsonObj.contains("frus"))
831 {
832 throw std::runtime_error(
833 "Missing frus section in system config JSON");
834 }
835
836 for (const auto& l_fru : i_sysCfgJsonObj["frus"].items())
837 {
838 const auto l_fruPath = l_fru.key();
839
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500840 if (isActionRequired(i_sysCfgJsonObj, l_fruPath, "pollingRequired",
841 "hotPlugging"))
842 {
843 if (i_sysCfgJsonObj["frus"][l_fruPath]
844 .at(0)["pollingRequired"]["hotPlugging"]
845 .contains("gpioPresence"))
846 {
847 l_gpioPollingRequiredFrusList.push_back(l_fruPath);
848 }
849 }
850 }
RekhaAparna017fea9f52025-02-17 04:14:02 -0600851 }
852 catch (const std::exception& l_ex)
853 {
854 logging::logMessage("Failed to get list of GPIO polling FRUs, error: " +
855 std::string(l_ex.what()));
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500856 }
857
858 return l_gpioPollingRequiredFrusList;
859}
860
861/**
862 * @brief Get all related path(s) to update keyword value.
863 *
864 * Given FRU EEPROM path/Inventory path needs keyword's value update, this API
865 * returns tuple of FRU EEPROM path, inventory path and redundant EEPROM path if
866 * exists in the system config JSON.
867 *
868 * Note: If the inventory object path or redundant EEPROM path(s) are not found
869 * in the system config JSON, corresponding fields will have empty value in the
870 * returning tuple.
871 *
872 * @param[in] i_sysCfgJsonObj - System config JSON object.
873 * @param[in,out] io_vpdPath - Inventory object path or FRU EEPROM path.
874 *
875 * @return On success returns tuple of EEPROM path, inventory path & redundant
876 * path, on failure returns tuple with given input path alone.
877 */
878inline std::tuple<std::string, std::string, std::string>
879 getAllPathsToUpdateKeyword(const nlohmann::json& i_sysCfgJsonObj,
880 std::string io_vpdPath)
881{
882 types::Path l_inventoryObjPath;
883 types::Path l_redundantFruPath;
884 try
885 {
886 if (!i_sysCfgJsonObj.empty())
887 {
888 // Get hardware path from system config JSON.
889 const types::Path l_fruPath =
890 jsonUtility::getFruPathFromJson(i_sysCfgJsonObj, io_vpdPath);
891
892 if (!l_fruPath.empty())
893 {
894 io_vpdPath = l_fruPath;
895
Rekha Aparna017567a2025-08-13 02:07:06 -0500896 uint16_t l_errCode = 0;
897
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500898 // Get inventory object path from system config JSON
899 l_inventoryObjPath = jsonUtility::getInventoryObjPathFromJson(
Rekha Aparna017567a2025-08-13 02:07:06 -0500900 i_sysCfgJsonObj, l_fruPath, l_errCode);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500901
902 // Get redundant hardware path if present in system config JSON
903 l_redundantFruPath =
904 jsonUtility::getRedundantEepromPathFromJson(i_sysCfgJsonObj,
905 l_fruPath);
906 }
907 }
908 }
909 catch (const std::exception& l_exception)
910 {
911 logging::logMessage(
912 "Failed to get all paths to update keyword value, error " +
913 std::string(l_exception.what()));
914 }
915 return std::make_tuple(io_vpdPath, l_inventoryObjPath, l_redundantFruPath);
916}
917
918/**
919 * @brief An API to get DBus service name.
920 *
921 * Given DBus inventory path, this API returns DBus service name if present in
922 * the JSON.
923 *
924 * @param[in] i_sysCfgJsonObj - System config JSON object.
925 * @param[in] l_inventoryPath - DBus inventory path.
926 *
927 * @return On success returns the service name present in the system config
928 * JSON, otherwise empty string.
929 *
930 * Note: Caller has to handle in case of empty string received.
931 */
932inline std::string getServiceName(const nlohmann::json& i_sysCfgJsonObj,
933 const std::string& l_inventoryPath)
934{
935 try
936 {
937 if (l_inventoryPath.empty())
938 {
939 throw std::runtime_error("Path parameter is empty.");
940 }
941
942 if (!i_sysCfgJsonObj.contains("frus"))
943 {
944 throw std::runtime_error("Missing frus tag in system config JSON.");
945 }
946
947 const nlohmann::json& l_listOfFrus =
948 i_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
949
950 for (const auto& l_frus : l_listOfFrus.items())
951 {
952 for (const auto& l_inventoryItem : l_frus.value())
953 {
954 if (l_inventoryPath.compare(l_inventoryItem["inventoryPath"]) ==
955 constants::STR_CMP_SUCCESS)
956 {
957 return l_inventoryItem["serviceName"];
958 }
959 }
960 }
961 throw std::runtime_error(
962 "Inventory path not found in the system config JSON");
963 }
964 catch (const std::exception& l_exception)
965 {
966 logging::logMessage(
967 "Error while getting DBus service name for given path " +
968 l_inventoryPath + ", error: " + std::string(l_exception.what()));
969 // TODO:log PEL
970 }
971 return std::string{};
972}
973
974/**
975 * @brief An API to check if a FRU is tagged as "powerOffOnly"
976 *
977 * Given the system config JSON and VPD FRU path, this API checks if the FRU
978 * VPD can be collected at Chassis Power Off state only.
979 *
980 * @param[in] i_sysCfgJsonObj - System config JSON object.
981 * @param[in] i_vpdFruPath - EEPROM path.
982 * @return - True if FRU VPD can be collected at Chassis Power Off state only.
983 * False otherwise
984 */
985inline bool isFruPowerOffOnly(const nlohmann::json& i_sysCfgJsonObj,
986 const std::string& i_vpdFruPath)
987{
988 if (i_vpdFruPath.empty())
989 {
990 logging::logMessage("FRU path is empty.");
991 return false;
992 }
993
994 if (!i_sysCfgJsonObj.contains("frus"))
995 {
996 logging::logMessage("Missing frus tag in system config JSON.");
997 return false;
998 }
999
1000 if (!i_sysCfgJsonObj["frus"].contains(i_vpdFruPath))
1001 {
1002 logging::logMessage("JSON object does not contain EEPROM path \'" +
1003 i_vpdFruPath + "\'");
1004 return false;
1005 }
1006
1007 return ((i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0))
1008 .contains("powerOffOnly") &&
1009 (i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0)["powerOffOnly"]));
1010}
1011
1012/**
1013 * @brief API which tells if the FRU is replaceable at runtime
1014 *
1015 * @param[in] i_sysCfgJsonObj - System config JSON object.
1016 * @param[in] i_vpdFruPath - EEPROM path.
1017 *
1018 * @return true if FRU is replaceable at runtime. false otherwise.
1019 */
1020inline bool isFruReplaceableAtRuntime(const nlohmann::json& i_sysCfgJsonObj,
1021 const std::string& i_vpdFruPath)
1022{
1023 try
1024 {
1025 if (i_vpdFruPath.empty())
1026 {
1027 throw std::runtime_error("Given FRU path is empty.");
1028 }
1029
1030 if (i_sysCfgJsonObj.empty() || (!i_sysCfgJsonObj.contains("frus")))
1031 {
1032 throw std::runtime_error("Invalid system config JSON object.");
1033 }
1034
1035 return ((i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0))
1036 .contains("replaceableAtRuntime") &&
1037 (i_sysCfgJsonObj["frus"][i_vpdFruPath].at(
1038 0)["replaceableAtRuntime"]));
1039 }
1040 catch (const std::exception& l_error)
1041 {
1042 // TODO: Log PEL
1043 logging::logMessage(l_error.what());
1044 }
1045
1046 return false;
1047}
1048
1049/**
1050 * @brief API which tells if the FRU is replaceable at standby
1051 *
1052 * @param[in] i_sysCfgJsonObj - System config JSON object.
1053 * @param[in] i_vpdFruPath - EEPROM path.
1054 *
1055 * @return true if FRU is replaceable at standby. false otherwise.
1056 */
1057inline bool isFruReplaceableAtStandby(const nlohmann::json& i_sysCfgJsonObj,
1058 const std::string& i_vpdFruPath)
1059{
1060 try
1061 {
1062 if (i_vpdFruPath.empty())
1063 {
1064 throw std::runtime_error("Given FRU path is empty.");
1065 }
1066
1067 if (i_sysCfgJsonObj.empty() || (!i_sysCfgJsonObj.contains("frus")))
1068 {
1069 throw std::runtime_error("Invalid system config JSON object.");
1070 }
1071
1072 return ((i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0))
1073 .contains("replaceableAtStandby") &&
1074 (i_sysCfgJsonObj["frus"][i_vpdFruPath].at(
1075 0)["replaceableAtStandby"]));
1076 }
1077 catch (const std::exception& l_error)
1078 {
1079 // TODO: Log PEL
1080 logging::logMessage(l_error.what());
1081 }
1082
1083 return false;
1084}
1085
1086/**
1087 * @brief API to get list of FRUs replaceable at standby from JSON.
1088 *
1089 * The API will return a vector of FRUs inventory path which are replaceable at
1090 * standby.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001091 *
1092 * @param[in] i_sysCfgJsonObj - System config JSON object.
1093 *
RekhaAparna017fea9f52025-02-17 04:14:02 -06001094 * @return - On success, list of FRUs replaceable at standby. On failure, empty
1095 * vector.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001096 */
Patrick Williams43fedab2025-02-03 14:28:05 -05001097inline std::vector<std::string> getListOfFrusReplaceableAtStandby(
RekhaAparna017fea9f52025-02-17 04:14:02 -06001098 const nlohmann::json& i_sysCfgJsonObj) noexcept
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001099{
1100 std::vector<std::string> l_frusReplaceableAtStandby;
1101
RekhaAparna017fea9f52025-02-17 04:14:02 -06001102 try
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001103 {
RekhaAparna017fea9f52025-02-17 04:14:02 -06001104 if (!i_sysCfgJsonObj.contains("frus"))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001105 {
RekhaAparna017fea9f52025-02-17 04:14:02 -06001106 throw std::runtime_error("Missing frus tag in system config JSON.");
1107 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001108
RekhaAparna017fea9f52025-02-17 04:14:02 -06001109 const nlohmann::json& l_fruList =
1110 i_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
1111
1112 for (const auto& l_fru : l_fruList.items())
1113 {
1114 if (i_sysCfgJsonObj["frus"][l_fru.key()].at(0).value(
1115 "replaceableAtStandby", false))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001116 {
RekhaAparna017fea9f52025-02-17 04:14:02 -06001117 const std::string& l_inventoryObjectPath =
1118 i_sysCfgJsonObj["frus"][l_fru.key()].at(0).value(
1119 "inventoryPath", "");
1120
1121 if (!l_inventoryObjectPath.empty())
1122 {
1123 l_frusReplaceableAtStandby.emplace_back(
1124 l_inventoryObjectPath);
1125 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001126 }
1127 }
1128 }
RekhaAparna017fea9f52025-02-17 04:14:02 -06001129 catch (const std::exception& l_ex)
1130 {
1131 logging::logMessage(
1132 "Failed to get list of FRUs replaceable at standby, error: " +
1133 std::string(l_ex.what()));
1134 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001135
1136 return l_frusReplaceableAtStandby;
1137}
1138
Sunny Srivastava022112b2025-02-19 19:53:29 +05301139/**
1140 * @brief API to select powerVS JSON based on system IM.
1141 *
1142 * The API selects respective JSON based on system IM, parse it and return the
1143 * JSON object. Empty JSON will be returned in case of any error. Caller needs
1144 * to handle empty value.
1145 *
1146 * @param[in] i_imValue - IM value of the system.
1147 * @return Parsed JSON object, empty JSON otherwise.
1148 */
1149inline nlohmann::json getPowerVsJson(const types::BinaryVector& i_imValue)
1150{
1151 try
1152 {
Rekha Aparnaca9a0862025-08-29 04:08:33 -05001153 uint16_t l_errCode = 0;
Sunny Srivastava022112b2025-02-19 19:53:29 +05301154 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_30))
1157 {
Rekha Aparnaca9a0862025-08-29 04:08:33 -05001158 nlohmann::json l_parsedJson = jsonUtility::getParsedJson(
1159 constants::power_vs_50003_json, l_errCode);
1160
1161 if (l_errCode)
1162 {
1163 logging::logMessage(
1164 "Failed to parse JSON file [ " +
1165 std::string(constants::power_vs_50003_json) +
1166 " ], error : " +
1167 vpdSpecificUtility::getErrCodeMsg(l_errCode));
1168 }
1169
1170 return l_parsedJson;
Sunny Srivastava022112b2025-02-19 19:53:29 +05301171 }
1172 else if (i_imValue.at(0) == constants::HEX_VALUE_50 &&
1173 (i_imValue.at(1) == constants::HEX_VALUE_00) &&
1174 (i_imValue.at(2) == constants::HEX_VALUE_10))
1175 {
Rekha Aparnaca9a0862025-08-29 04:08:33 -05001176 nlohmann::json l_parsedJson = jsonUtility::getParsedJson(
1177 constants::power_vs_50001_json, l_errCode);
1178
1179 if (l_errCode)
1180 {
1181 logging::logMessage(
1182 "Failed to parse JSON file [ " +
1183 std::string(constants::power_vs_50001_json) +
1184 " ], error : " +
1185 vpdSpecificUtility::getErrCodeMsg(l_errCode));
1186 }
1187
1188 return l_parsedJson;
Sunny Srivastava022112b2025-02-19 19:53:29 +05301189 }
1190 return nlohmann::json{};
1191 }
1192 catch (const std::exception& l_ex)
1193 {
1194 return nlohmann::json{};
1195 }
1196}
Souvik Roy495eedd2025-07-02 02:13:43 -05001197
1198/**
1199 * @brief API to get list of FRUs for which "monitorPresence" is true.
1200 *
1201 * @param[in] i_sysCfgJsonObj - System config JSON object.
Rekha Aparna2362bed2025-09-01 13:18:40 -05001202 * @param[out] o_errCode - To set error code in case of error.
Souvik Roy495eedd2025-07-02 02:13:43 -05001203 *
1204 * @return On success, returns list of FRUs for which "monitorPresence" is true,
1205 * empty list on error.
1206 */
1207inline std::vector<types::Path> getFrusWithPresenceMonitoring(
Rekha Aparna2362bed2025-09-01 13:18:40 -05001208 const nlohmann::json& i_sysCfgJsonObj, uint16_t& o_errCode)
Souvik Roy495eedd2025-07-02 02:13:43 -05001209{
1210 std::vector<types::Path> l_frusWithPresenceMonitoring;
Rekha Aparna2362bed2025-09-01 13:18:40 -05001211
1212 if (!i_sysCfgJsonObj.contains("frus"))
Souvik Roy495eedd2025-07-02 02:13:43 -05001213 {
Rekha Aparna2362bed2025-09-01 13:18:40 -05001214 o_errCode = error_code::INVALID_JSON;
1215 return l_frusWithPresenceMonitoring;
1216 }
Souvik Roy495eedd2025-07-02 02:13:43 -05001217
Rekha Aparna2362bed2025-09-01 13:18:40 -05001218 const nlohmann::json& l_listOfFrus =
1219 i_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
Souvik Roy495eedd2025-07-02 02:13:43 -05001220
Rekha Aparna2362bed2025-09-01 13:18:40 -05001221 for (const auto& l_aFru : l_listOfFrus)
1222 {
1223 if (l_aFru.at(0).value("monitorPresence", false))
Souvik Roy495eedd2025-07-02 02:13:43 -05001224 {
Rekha Aparna2362bed2025-09-01 13:18:40 -05001225 l_frusWithPresenceMonitoring.emplace_back(
1226 l_aFru.at(0).value("inventoryPath", ""));
Souvik Roy495eedd2025-07-02 02:13:43 -05001227 }
1228 }
Rekha Aparna2362bed2025-09-01 13:18:40 -05001229
Souvik Roy495eedd2025-07-02 02:13:43 -05001230 return l_frusWithPresenceMonitoring;
1231}
Souvik Roye9120152025-07-02 08:24:38 -05001232
1233/**
1234 * @brief API which tells if the FRU's presence is handled
1235 *
1236 * For a given FRU, this API checks if it's presence is handled by vpd-manager
1237 * by checking the "handlePresence" tag.
1238 *
1239 * @param[in] i_sysCfgJsonObj - System config JSON object.
1240 * @param[in] i_vpdFruPath - EEPROM path.
Rekha Aparnaa1187a52025-09-01 12:42:19 -05001241 * @param[out] o_errCode - To set error code in case of failure.
Souvik Roye9120152025-07-02 08:24:38 -05001242 *
1243 * @return true if FRU presence is handled, false otherwise.
1244 */
1245inline bool isFruPresenceHandled(const nlohmann::json& i_sysCfgJsonObj,
Rekha Aparnaa1187a52025-09-01 12:42:19 -05001246 const std::string& i_vpdFruPath,
1247 uint16_t& o_errCode)
Souvik Roye9120152025-07-02 08:24:38 -05001248{
Rekha Aparnaa1187a52025-09-01 12:42:19 -05001249 if (i_vpdFruPath.empty())
Souvik Roye9120152025-07-02 08:24:38 -05001250 {
Rekha Aparnaa1187a52025-09-01 12:42:19 -05001251 o_errCode = error_code::INVALID_INPUT_PARAMETER;
1252 return false;
Souvik Roye9120152025-07-02 08:24:38 -05001253 }
1254
Rekha Aparnaa1187a52025-09-01 12:42:19 -05001255 if (!i_sysCfgJsonObj.contains("frus"))
1256 {
1257 o_errCode = error_code::INVALID_JSON;
1258 return false;
1259 }
1260
1261 if (!i_sysCfgJsonObj["frus"].contains(i_vpdFruPath))
1262 {
1263 o_errCode = error_code::FRU_PATH_NOT_FOUND;
1264 return false;
1265 }
1266
1267 return i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0).value(
1268 "handlePresence", true);
Souvik Roye9120152025-07-02 08:24:38 -05001269}
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001270} // namespace jsonUtility
1271} // namespace vpd