blob: 8e7be98bd1bdc56ec7b371cadb41a3fd4cf3bd0d [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.
Sunny Srivastava84c3d232025-09-03 00:47:10 -050024bool processSystemCmdTag(
25 const nlohmann::json& i_parsedConfigJson, const std::string& i_vpdFilePath,
26 const std::string& i_baseAction, const std::string& i_flagToProcess,
27 uint16_t& o_errCode);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050028
29// forward declaration of API for function map.
30bool processGpioPresenceTag(
31 const nlohmann::json& i_parsedConfigJson, const std::string& i_vpdFilePath,
Sunny Srivastava84c3d232025-09-03 00:47:10 -050032 const std::string& i_baseAction, const std::string& i_flagToProcess,
33 uint16_t& o_errCode);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050034
35// forward declaration of API for function map.
36bool procesSetGpioTag(const nlohmann::json& i_parsedConfigJson,
37 const std::string& i_vpdFilePath,
38 const std::string& i_baseAction,
Sunny Srivastava84c3d232025-09-03 00:47:10 -050039 const std::string& i_flagToProcess, uint16_t& o_errCode);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050040
41// Function pointers to process tags from config JSON.
42typedef bool (*functionPtr)(
43 const nlohmann::json& i_parsedConfigJson, const std::string& i_vpdFilePath,
Sunny Srivastava84c3d232025-09-03 00:47:10 -050044 const std::string& i_baseAction, const std::string& i_flagToProcess,
45 uint16_t& o_errCode);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050046
47inline std::unordered_map<std::string, functionPtr> funcionMap{
48 {"gpioPresence", processGpioPresenceTag},
49 {"setGpio", procesSetGpioTag},
50 {"systemCmd", processSystemCmdTag}};
51
52/**
53 * @brief API to read VPD offset from JSON file.
54 *
55 * @param[in] i_sysCfgJsonObj - Parsed system config JSON object.
56 * @param[in] i_vpdFilePath - VPD file path.
Rekha Aparna017567a2025-08-13 02:07:06 -050057 * @param[in] o_errCode - To set error code in case of error.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050058 * @return VPD offset if found in JSON, 0 otherwise.
59 */
60inline size_t getVPDOffset(const nlohmann::json& i_sysCfgJsonObj,
Rekha Aparna017567a2025-08-13 02:07:06 -050061 const std::string& i_vpdFilePath,
62 uint16_t& o_errCode)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050063{
64 if (i_vpdFilePath.empty() || (i_sysCfgJsonObj.empty()) ||
65 (!i_sysCfgJsonObj.contains("frus")))
66 {
Rekha Aparna017567a2025-08-13 02:07:06 -050067 o_errCode = error_code::INVALID_INPUT_PARAMETER;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050068 return 0;
69 }
70
71 if (i_sysCfgJsonObj["frus"].contains(i_vpdFilePath))
72 {
73 return i_sysCfgJsonObj["frus"][i_vpdFilePath].at(0).value("offset", 0);
74 }
75
76 const nlohmann::json& l_fruList =
77 i_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
78
79 for (const auto& l_fru : l_fruList.items())
80 {
81 const auto l_fruPath = l_fru.key();
82
83 // check if given path is redundant FRU path
84 if (i_vpdFilePath == i_sysCfgJsonObj["frus"][l_fruPath].at(0).value(
85 "redundantEeprom", ""))
86 {
87 // Return the offset of redundant EEPROM taken from JSON.
88 return i_sysCfgJsonObj["frus"][l_fruPath].at(0).value("offset", 0);
89 }
90 }
91
92 return 0;
93}
94
95/**
96 * @brief API to parse respective JSON.
97 *
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050098 * @param[in] pathToJson - Path to JSON.
Rekha Aparnaca9a0862025-08-29 04:08:33 -050099 * @param[out] o_errCode - To set error code in case of error.
RekhaAparna011ef21002025-02-18 23:47:36 -0600100 * @return on success parsed JSON. On failure empty JSON object.
101 *
102 * Note: Caller has to handle it in case an empty JSON object is received.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500103 */
Rekha Aparnaca9a0862025-08-29 04:08:33 -0500104inline nlohmann::json getParsedJson(const std::string& pathToJson,
105 uint16_t& o_errCode) noexcept
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500106{
Rekha Aparnaca9a0862025-08-29 04:08:33 -0500107 if (pathToJson.empty())
108 {
109 o_errCode = error_code::INVALID_INPUT_PARAMETER;
110 return nlohmann::json{};
111 }
112
113 if (!std::filesystem::exists(pathToJson))
114 {
115 o_errCode = error_code::FILE_NOT_FOUND;
116 return nlohmann::json{};
117 }
118
119 if (std::filesystem::is_empty(pathToJson))
120 {
121 o_errCode = error_code::EMPTY_FILE;
122 return nlohmann::json{};
123 }
124
125 std::ifstream l_jsonFile(pathToJson);
126 if (!l_jsonFile)
127 {
128 o_errCode = error_code::FILE_ACCESS_ERROR;
129 return nlohmann::json{};
130 }
131
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500132 try
133 {
RekhaAparna011ef21002025-02-18 23:47:36 -0600134 return nlohmann::json::parse(l_jsonFile);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500135 }
RekhaAparna011ef21002025-02-18 23:47:36 -0600136 catch (const std::exception& l_ex)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500137 {
Rekha Aparnaca9a0862025-08-29 04:08:33 -0500138 o_errCode = error_code::JSON_PARSE_ERROR;
139 return nlohmann::json{};
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500140 }
141}
142
143/**
144 * @brief Get inventory object path from system config JSON.
145 *
146 * Given either D-bus inventory path/FRU EEPROM path/redundant EEPROM path,
147 * this API returns D-bus inventory path if present in JSON.
148 *
149 * @param[in] i_sysCfgJsonObj - System config JSON object
150 * @param[in] i_vpdPath - Path to where VPD is stored.
Rekha Aparna017567a2025-08-13 02:07:06 -0500151 * @param[in] o_errCode - To set error code in case of error.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500152 *
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500153 * @return On success a valid path is returned, on failure an empty string is
RekhaAparna011ef21002025-02-18 23:47:36 -0600154 * returned.
155 *
156 * Note: Caller has to handle it in case an empty string is received.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500157 */
158inline std::string getInventoryObjPathFromJson(
Rekha Aparna017567a2025-08-13 02:07:06 -0500159 const nlohmann::json& i_sysCfgJsonObj, const std::string& i_vpdPath,
160 uint16_t& o_errCode) noexcept
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500161{
Rekha Aparna017567a2025-08-13 02:07:06 -0500162 if (i_vpdPath.empty())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500163 {
Rekha Aparna017567a2025-08-13 02:07:06 -0500164 o_errCode = error_code::INVALID_INPUT_PARAMETER;
165 return std::string{};
RekhaAparna011ef21002025-02-18 23:47:36 -0600166 }
167
Rekha Aparna017567a2025-08-13 02:07:06 -0500168 if (!i_sysCfgJsonObj.contains("frus"))
169 {
170 o_errCode = error_code::INVALID_JSON;
171 return std::string{};
172 }
173
174 // check if given path is FRU path
175 if (i_sysCfgJsonObj["frus"].contains(i_vpdPath))
176 {
177 return i_sysCfgJsonObj["frus"][i_vpdPath].at(0).value(
178 "inventoryPath", "");
179 }
180
181 const nlohmann::json& l_fruList =
182 i_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
183
184 for (const auto& l_fru : l_fruList.items())
185 {
186 const auto l_fruPath = l_fru.key();
187 const auto l_invObjPath =
188 i_sysCfgJsonObj["frus"][l_fruPath].at(0).value("inventoryPath", "");
189
190 // check if given path is redundant FRU path or inventory path
191 if (i_vpdPath == i_sysCfgJsonObj["frus"][l_fruPath].at(0).value(
192 "redundantEeprom", "") ||
193 (i_vpdPath == l_invObjPath))
194 {
195 return l_invObjPath;
196 }
197 }
198
199 return std::string{};
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500200}
201
202/**
203 * @brief Process "PostFailAction" defined in config JSON.
204 *
205 * In case there is some error in the processing of "preAction" execution and a
206 * set of procedure needs to be done as a part of post fail action. This base
207 * action can be defined in the config JSON for that FRU and it will be handled
208 * under this API.
209 *
210 * @param[in] i_parsedConfigJson - config JSON
211 * @param[in] i_vpdFilePath - EEPROM file path
212 * @param[in] i_flagToProcess - To identify which flag(s) needs to be processed
Rekha Aparnaff7d7992025-09-01 11:08:53 -0500213 * @param[out] o_errCode - To set error code in case of error
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500214 * under PostFailAction tag of config JSON.
215 * @return - success or failure
216 */
Rekha Aparnaff7d7992025-09-01 11:08:53 -0500217inline bool executePostFailAction(
218 const nlohmann::json& i_parsedConfigJson, const std::string& i_vpdFilePath,
219 const std::string& i_flagToProcess, uint16_t& o_errCode)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500220{
Rekha Aparnaff7d7992025-09-01 11:08:53 -0500221 if (i_parsedConfigJson.empty() || i_vpdFilePath.empty() ||
222 i_flagToProcess.empty())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500223 {
Rekha Aparnaff7d7992025-09-01 11:08:53 -0500224 o_errCode = error_code::INVALID_INPUT_PARAMETER;
225 return false;
226 }
RekhaAparna01c11e8b62025-02-20 00:34:35 -0600227
Rekha Aparna41f47e72025-09-18 01:44:09 -0500228 if (!i_parsedConfigJson.contains("frus"))
229 {
230 o_errCode = error_code::INVALID_JSON;
231 return false;
232 }
233
234 if (!i_parsedConfigJson["frus"].contains(i_vpdFilePath))
235 {
236 o_errCode = error_code::FRU_PATH_NOT_FOUND;
237 return false;
238 }
239
240 if (!i_parsedConfigJson["frus"][i_vpdFilePath].at(0).contains(
241 "postFailAction"))
242 {
243 o_errCode = error_code::MISSING_ACTION_TAG;
244 return false;
245 }
246
Rekha Aparnaff7d7992025-09-01 11:08:53 -0500247 if (!(i_parsedConfigJson["frus"][i_vpdFilePath].at(0))["postFailAction"]
248 .contains(i_flagToProcess))
249 {
250 o_errCode = error_code::MISSING_FLAG;
251 return false;
252 }
RekhaAparna01c11e8b62025-02-20 00:34:35 -0600253
Rekha Aparnaff7d7992025-09-01 11:08:53 -0500254 for (const auto& l_tags : (i_parsedConfigJson["frus"][i_vpdFilePath].at(
255 0))["postFailAction"][i_flagToProcess]
256 .items())
257 {
258 auto itrToFunction = funcionMap.find(l_tags.key());
259 if (itrToFunction != funcionMap.end())
RekhaAparna01c11e8b62025-02-20 00:34:35 -0600260 {
Rekha Aparnaff7d7992025-09-01 11:08:53 -0500261 if (!itrToFunction->second(i_parsedConfigJson, i_vpdFilePath,
Sunny Srivastava84c3d232025-09-03 00:47:10 -0500262 "postFailAction", i_flagToProcess,
263 o_errCode))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500264 {
Sunny Srivastava84c3d232025-09-03 00:47:10 -0500265 if (o_errCode)
266 {
267 logging::logMessage(
268 l_tags.key() + " failed for [" + i_vpdFilePath +
269 "]. Reason " +
270 vpdSpecificUtility::getErrCodeMsg(o_errCode));
271 }
Rekha Aparnaff7d7992025-09-01 11:08:53 -0500272 return false;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500273 }
274 }
275 }
276
277 return true;
278}
279
280/**
281 * @brief Process "systemCmd" tag for a given FRU.
282 *
283 * The API will process "systemCmd" tag if it is defined in the config
284 * JSON for the given FRU.
285 *
286 * @param[in] i_parsedConfigJson - config JSON
287 * @param[in] i_vpdFilePath - EEPROM file path
288 * @param[in] i_baseAction - Base action for which this tag has been called.
289 * @param[in] i_flagToProcess - Flag nested under the base action for which this
290 * tag has been called.
Sunny Srivastava84c3d232025-09-03 00:47:10 -0500291 * @param[out] o_errCode - To set error code in case of error.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500292 * @return Execution status.
293 */
294inline bool processSystemCmdTag(
295 const nlohmann::json& i_parsedConfigJson, const std::string& i_vpdFilePath,
Sunny Srivastava84c3d232025-09-03 00:47:10 -0500296 const std::string& i_baseAction, const std::string& i_flagToProcess,
297 uint16_t& o_errCode)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500298{
Sunny Srivastava84c3d232025-09-03 00:47:10 -0500299 if (i_vpdFilePath.empty() || i_parsedConfigJson.empty() ||
300 i_baseAction.empty() || i_flagToProcess.empty())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500301 {
Sunny Srivastava84c3d232025-09-03 00:47:10 -0500302 o_errCode = error_code::INVALID_INPUT_PARAMETER;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500303 return false;
304 }
Sunny Srivastava84c3d232025-09-03 00:47:10 -0500305
Rekha Aparna41f47e72025-09-18 01:44:09 -0500306 try
Sunny Srivastava84c3d232025-09-03 00:47:10 -0500307 {
Rekha Aparna41f47e72025-09-18 01:44:09 -0500308 if (!((i_parsedConfigJson["frus"][i_vpdFilePath].at(
309 0)[i_baseAction][i_flagToProcess]["systemCmd"])
310 .contains("cmd")))
311 {
312 o_errCode = error_code::MISSING_FLAG;
313 return false;
314 }
315
316 const std::string& l_systemCommand =
317 i_parsedConfigJson["frus"][i_vpdFilePath].at(
318 0)[i_baseAction][i_flagToProcess]["systemCmd"]["cmd"];
319
320 commonUtility::executeCmd(l_systemCommand);
321 }
322 catch (const std::exception& l_ex)
323 {
324 o_errCode = error_code::ERROR_PROCESSING_SYSTEM_CMD;
Sunny Srivastava84c3d232025-09-03 00:47:10 -0500325 return false;
326 }
Sunny Srivastava84c3d232025-09-03 00:47:10 -0500327 return true;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500328}
329
330/**
331 * @brief Checks for presence of a given FRU using GPIO line.
332 *
333 * This API returns the presence information of the FRU corresponding to the
334 * given VPD file path by setting the presence pin.
335 *
336 * @param[in] i_parsedConfigJson - config JSON
337 * @param[in] i_vpdFilePath - EEPROM file path
338 * @param[in] i_baseAction - Base action for which this tag has been called.
339 * @param[in] i_flagToProcess - Flag nested under the base action for which this
340 * tag has been called.
Sunny Srivastava84c3d232025-09-03 00:47:10 -0500341 * @param[out] o_errCode - To set error code in case of error
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500342 * @return Execution status.
343 */
344inline bool processGpioPresenceTag(
345 const nlohmann::json& i_parsedConfigJson, const std::string& i_vpdFilePath,
Sunny Srivastava84c3d232025-09-03 00:47:10 -0500346 const std::string& i_baseAction, const std::string& i_flagToProcess,
347 uint16_t& o_errCode)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500348{
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530349 std::string l_presencePinName;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500350 try
351 {
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530352 if (i_vpdFilePath.empty() || i_parsedConfigJson.empty() ||
353 i_baseAction.empty() || i_flagToProcess.empty())
354 {
Sunny Srivastava84c3d232025-09-03 00:47:10 -0500355 o_errCode = error_code::INVALID_INPUT_PARAMETER;
356 return false;
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530357 }
358
359 if (!(((i_parsedConfigJson["frus"][i_vpdFilePath].at(
360 0)[i_baseAction][i_flagToProcess]["gpioPresence"])
361 .contains("pin")) &&
362 ((i_parsedConfigJson["frus"][i_vpdFilePath].at(
363 0)[i_baseAction][i_flagToProcess]["gpioPresence"])
364 .contains("value"))))
365 {
Sunny Srivastava84c3d232025-09-03 00:47:10 -0500366 o_errCode = error_code::JSON_MISSING_GPIO_INFO;
367 return false;
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530368 }
369
370 // get the pin name
371 l_presencePinName = i_parsedConfigJson["frus"][i_vpdFilePath].at(
372 0)[i_baseAction][i_flagToProcess]["gpioPresence"]["pin"];
373
374 // get the pin value
375 uint8_t l_presencePinValue =
376 i_parsedConfigJson["frus"][i_vpdFilePath].at(
377 0)[i_baseAction][i_flagToProcess]["gpioPresence"]["value"];
378
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500379 gpiod::line l_presenceLine = gpiod::find_line(l_presencePinName);
380
381 if (!l_presenceLine)
382 {
Sunny Srivastava84c3d232025-09-03 00:47:10 -0500383 o_errCode = error_code::DEVICE_PRESENCE_UNKNOWN;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500384 throw GpioException("Couldn't find the GPIO line.");
385 }
386
387 l_presenceLine.request({"Read the presence line",
388 gpiod::line_request::DIRECTION_INPUT, 0});
389
Sunny Srivastava84c3d232025-09-03 00:47:10 -0500390 if (l_presencePinValue != l_presenceLine.get_value())
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530391 {
Sunny Srivastava84c3d232025-09-03 00:47:10 -0500392 // As false is being returned in this case, caller needs to know
393 // that it is not due to some exception. It is because the pin was
394 // read correctly but was not having expected value.
395 o_errCode = error_code::DEVICE_NOT_PRESENT;
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530396 return false;
397 }
398
Sunny Srivastava84c3d232025-09-03 00:47:10 -0500399 return true;
400 }
401 catch (const std::exception& l_ex)
402 {
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500403 std::string l_errMsg = "Exception on GPIO line: ";
404 l_errMsg += l_presencePinName;
405 l_errMsg += " Reason: ";
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530406 l_errMsg += l_ex.what();
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500407 l_errMsg += " File: " + i_vpdFilePath + " Pel Logged";
408
Rekha Aparna017567a2025-08-13 02:07:06 -0500409 uint16_t l_errCode = 0;
410
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500411 // ToDo -- Update Internal Rc code.
412 EventLogger::createAsyncPelWithInventoryCallout(
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530413 EventLogger::getErrorType(l_ex), types::SeverityType::Informational,
Rekha Aparna017567a2025-08-13 02:07:06 -0500414 {{getInventoryObjPathFromJson(i_parsedConfigJson, i_vpdFilePath,
415 l_errCode),
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500416 types::CalloutPriority::High}},
417 std::source_location::current().file_name(),
418 std::source_location::current().function_name(), 0, l_errMsg,
419 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
420
421 logging::logMessage(l_errMsg);
422
423 // Except when GPIO pin value is false, we go and try collecting the
424 // FRU VPD as we couldn't able to read GPIO pin value due to some
425 // error/exception. So returning true in error scenario.
426 return true;
427 }
428}
429
430/**
431 * @brief Process "setGpio" tag for a given FRU.
432 *
433 * This API enables the GPIO line.
434 *
435 * @param[in] i_parsedConfigJson - config JSON
436 * @param[in] i_vpdFilePath - EEPROM file path
437 * @param[in] i_baseAction - Base action for which this tag has been called.
438 * @param[in] i_flagToProcess - Flag nested under the base action for which this
439 * tag has been called.
Sunny Srivastava84c3d232025-09-03 00:47:10 -0500440 * @param[out] o_errCode - To set error code in case of error
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500441 * @return Execution status.
442 */
443inline bool procesSetGpioTag(
444 const nlohmann::json& i_parsedConfigJson, const std::string& i_vpdFilePath,
Sunny Srivastava84c3d232025-09-03 00:47:10 -0500445 const std::string& i_baseAction, const std::string& i_flagToProcess,
446 uint16_t& o_errCode)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500447{
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530448 std::string l_pinName;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500449 try
450 {
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530451 if (i_vpdFilePath.empty() || i_parsedConfigJson.empty() ||
452 i_baseAction.empty() || i_flagToProcess.empty())
453 {
Sunny Srivastava84c3d232025-09-03 00:47:10 -0500454 o_errCode = error_code::INVALID_INPUT_PARAMETER;
455 return false;
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530456 }
457
458 if (!(((i_parsedConfigJson["frus"][i_vpdFilePath].at(
459 0)[i_baseAction][i_flagToProcess]["setGpio"])
460 .contains("pin")) &&
461 ((i_parsedConfigJson["frus"][i_vpdFilePath].at(
462 0)[i_baseAction][i_flagToProcess]["setGpio"])
463 .contains("value"))))
464 {
Sunny Srivastava84c3d232025-09-03 00:47:10 -0500465 o_errCode = error_code::JSON_MISSING_GPIO_INFO;
466 return false;
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530467 }
468
469 l_pinName = i_parsedConfigJson["frus"][i_vpdFilePath].at(
470 0)[i_baseAction][i_flagToProcess]["setGpio"]["pin"];
471
472 // Get the value to set
473 uint8_t l_pinValue = i_parsedConfigJson["frus"][i_vpdFilePath].at(
474 0)[i_baseAction][i_flagToProcess]["setGpio"]["value"];
475
476 logging::logMessage(
477 "Setting GPIO: " + l_pinName + " to " + std::to_string(l_pinValue));
478
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500479 gpiod::line l_outputLine = gpiod::find_line(l_pinName);
480
481 if (!l_outputLine)
482 {
Sunny Srivastava84c3d232025-09-03 00:47:10 -0500483 o_errCode = error_code::GPIO_LINE_EXCEPTION;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500484 throw GpioException("Couldn't find GPIO line.");
485 }
486
487 l_outputLine.request(
488 {"FRU Action", ::gpiod::line_request::DIRECTION_OUTPUT, 0},
489 l_pinValue);
490 return true;
491 }
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530492 catch (const std::exception& l_ex)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500493 {
Sunny Srivastava84c3d232025-09-03 00:47:10 -0500494 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
Sunny Srivastava84c3d232025-09-03 00:47:10 -0500500 uint16_t l_errCode = 0;
Rekha Aparna017567a2025-08-13 02:07:06 -0500501
Sunny Srivastava84c3d232025-09-03 00:47:10 -0500502 // ToDo -- Update Internal RC code
503 EventLogger::createAsyncPelWithInventoryCallout(
504 EventLogger::getErrorType(l_ex), types::SeverityType::Informational,
505 {{getInventoryObjPathFromJson(i_parsedConfigJson, i_vpdFilePath,
506 l_errCode),
507 types::CalloutPriority::High}},
508 std::source_location::current().file_name(),
509 std::source_location::current().function_name(), 0, l_errMsg,
510 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500511
Sunny Srivastava84c3d232025-09-03 00:47:10 -0500512 logging::logMessage(l_errMsg);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500513
514 return false;
515 }
516}
517
518/**
519 * @brief Process any action, if defined in config JSON.
520 *
521 * If any FRU(s) requires any special handling, then this base action can be
522 * defined for that FRU in the config JSON, processing of which will be handled
523 * in this API.
524 * Examples of action - preAction, PostAction etc.
525 *
526 * @param[in] i_parsedConfigJson - config JSON
527 * @param[in] i_action - Base action to be performed.
528 * @param[in] i_vpdFilePath - EEPROM file path
529 * @param[in] i_flagToProcess - To identify which flag(s) needs to be processed
530 * under PreAction tag of config JSON.
Sunny Srivastava4f053df2025-09-03 02:27:37 -0500531 * @param[out] o_errCode - To set error code in case of error.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500532 * @return - success or failure
533 */
534inline bool executeBaseAction(
535 const nlohmann::json& i_parsedConfigJson, const std::string& i_action,
Sunny Srivastava4f053df2025-09-03 02:27:37 -0500536 const std::string& i_vpdFilePath, const std::string& i_flagToProcess,
537 uint16_t& o_errCode)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500538{
Sunny Srivastava4f053df2025-09-03 02:27:37 -0500539 if (i_flagToProcess.empty() || i_action.empty() || i_vpdFilePath.empty() ||
540 !i_parsedConfigJson.contains("frus"))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500541 {
Sunny Srivastava4f053df2025-09-03 02:27:37 -0500542 o_errCode = error_code::INVALID_INPUT_PARAMETER;
543 return false;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500544 }
Sunny Srivastava4f053df2025-09-03 02:27:37 -0500545 if (!i_parsedConfigJson["frus"].contains(i_vpdFilePath))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500546 {
Sunny Srivastava4f053df2025-09-03 02:27:37 -0500547 o_errCode = error_code::FILE_NOT_FOUND;
548 return false;
549 }
550 if (!i_parsedConfigJson["frus"][i_vpdFilePath].at(0).contains(i_action))
551 {
552 o_errCode = error_code::MISSING_ACTION_TAG;
553 return false;
554 }
555
556 if (!(i_parsedConfigJson["frus"][i_vpdFilePath].at(0))[i_action].contains(
557 i_flagToProcess))
558 {
559 o_errCode = error_code::MISSING_FLAG;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500560 return false;
561 }
562
563 const nlohmann::json& l_tagsJson =
564 (i_parsedConfigJson["frus"][i_vpdFilePath].at(
565 0))[i_action][i_flagToProcess];
566
567 for (const auto& l_tag : l_tagsJson.items())
568 {
569 auto itrToFunction = funcionMap.find(l_tag.key());
570 if (itrToFunction != funcionMap.end())
571 {
572 if (!itrToFunction->second(i_parsedConfigJson, i_vpdFilePath,
Sunny Srivastava84c3d232025-09-03 00:47:10 -0500573 i_action, i_flagToProcess, o_errCode))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500574 {
575 // In case any of the tag fails to execute. Mark action
576 // as failed for that flag.
Sunny Srivastava84c3d232025-09-03 00:47:10 -0500577 if (o_errCode)
578 {
579 logging::logMessage(
580 l_tag.key() + " failed for [" + i_vpdFilePath +
581 "]. Reason " +
582 vpdSpecificUtility::getErrCodeMsg(o_errCode));
583 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500584 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.
Rekha Aparnabb52af42025-09-02 04:05:18 -0500601 * @param[out] o_errCode - To set error code in case of error.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500602 *
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500603 * @return On success return valid path, on failure return empty string.
604 */
605inline std::string getRedundantEepromPathFromJson(
Rekha Aparnabb52af42025-09-02 04:05:18 -0500606 const nlohmann::json& i_sysCfgJsonObj, const std::string& i_vpdPath,
607 uint16_t& o_errCode)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500608{
Rekha Aparnabb52af42025-09-02 04:05:18 -0500609 if (i_vpdPath.empty())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500610 {
Rekha Aparnabb52af42025-09-02 04:05:18 -0500611 o_errCode = error_code::INVALID_INPUT_PARAMETER;
612 return std::string{};
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500613 }
Rekha Aparnabb52af42025-09-02 04:05:18 -0500614
615 if (!i_sysCfgJsonObj.contains("frus"))
RekhaAparna017fea9f52025-02-17 04:14:02 -0600616 {
Rekha Aparnabb52af42025-09-02 04:05:18 -0500617 o_errCode = error_code::INVALID_JSON;
618 return std::string{};
619 }
620
621 // check if given path is FRU path
622 if (i_sysCfgJsonObj["frus"].contains(i_vpdPath))
623 {
624 return i_sysCfgJsonObj["frus"][i_vpdPath].at(0).value(
625 "redundantEeprom", "");
626 }
627
628 const nlohmann::json& l_fruList =
629 i_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
630
631 for (const auto& l_fru : l_fruList.items())
632 {
633 const std::string& l_fruPath = l_fru.key();
634 const std::string& l_redundantFruPath =
635 i_sysCfgJsonObj["frus"][l_fruPath].at(0).value("redundantEeprom",
636 "");
637
638 // check if given path is inventory path or redundant FRU path
639 if ((i_sysCfgJsonObj["frus"][l_fruPath].at(0).value("inventoryPath",
640 "") == i_vpdPath) ||
641 (l_redundantFruPath == i_vpdPath))
642 {
643 return l_redundantFruPath;
644 }
RekhaAparna017fea9f52025-02-17 04:14:02 -0600645 }
646
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500647 return std::string();
648}
649
650/**
651 * @brief Get FRU EEPROM path from system config JSON
652 *
653 * Given either D-bus inventory path/FRU EEPROM path/redundant EEPROM path,
654 * this API returns FRU EEPROM path if present in JSON.
655 *
656 * @param[in] i_sysCfgJsonObj - System config JSON object
657 * @param[in] i_vpdPath - Path to where VPD is stored.
Rekha Aparna0578dd22025-09-02 08:20:21 -0500658 * @param[out] o_errCode - To set error code in case of error.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500659 *
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500660 * @return On success return valid path, on failure return empty string.
661 */
662inline std::string getFruPathFromJson(const nlohmann::json& i_sysCfgJsonObj,
Rekha Aparna0578dd22025-09-02 08:20:21 -0500663 const std::string& i_vpdPath,
664 uint16_t& o_errCode)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500665{
Rekha Aparna0578dd22025-09-02 08:20:21 -0500666 if (i_vpdPath.empty())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500667 {
Rekha Aparna0578dd22025-09-02 08:20:21 -0500668 o_errCode = error_code::INVALID_INPUT_PARAMETER;
669 return std::string{};
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500670 }
Rekha Aparna0578dd22025-09-02 08:20:21 -0500671
672 if (!i_sysCfgJsonObj.contains("frus"))
RekhaAparna017fea9f52025-02-17 04:14:02 -0600673 {
Rekha Aparna0578dd22025-09-02 08:20:21 -0500674 o_errCode = error_code::INVALID_JSON;
675 return std::string{};
676 }
677
678 // check if given path is FRU path
679 if (i_sysCfgJsonObj["frus"].contains(i_vpdPath))
680 {
681 return i_vpdPath;
682 }
683
684 const nlohmann::json& l_fruList =
685 i_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
686
687 for (const auto& l_fru : l_fruList.items())
688 {
689 const auto l_fruPath = l_fru.key();
690
691 // check if given path is redundant FRU path or inventory path
692 if (i_vpdPath == i_sysCfgJsonObj["frus"][l_fruPath].at(0).value(
693 "redundantEeprom", "") ||
694 (i_vpdPath == i_sysCfgJsonObj["frus"][l_fruPath].at(0).value(
695 "inventoryPath", "")))
696 {
697 return l_fruPath;
698 }
RekhaAparna017fea9f52025-02-17 04:14:02 -0600699 }
700
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500701 return std::string();
702}
703
704/**
705 * @brief An API to check backup and restore VPD is required.
706 *
707 * The API checks if there is provision for backup and restore mentioned in the
708 * system config JSON, by looking "backupRestoreConfigPath" tag.
709 * Checks if the path mentioned is a hardware path, by checking if the file path
710 * exists and size of contents in the path.
711 *
712 * @param[in] i_sysCfgJsonObj - System config JSON object.
Rekha Aparna196e3082025-09-08 20:40:35 -0500713 * @param[out] o_errCode - To set error code in case of error.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500714 *
715 * @return true if backup and restore is required, false otherwise.
716 */
Rekha Aparna196e3082025-09-08 20:40:35 -0500717inline bool isBackupAndRestoreRequired(const nlohmann::json& i_sysCfgJsonObj,
718 uint16_t& o_errCode)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500719{
Rekha Aparna196e3082025-09-08 20:40:35 -0500720 if (i_sysCfgJsonObj.empty())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500721 {
Rekha Aparna196e3082025-09-08 20:40:35 -0500722 o_errCode = error_code::INVALID_INPUT_PARAMETER;
723 return false;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500724 }
Rekha Aparna196e3082025-09-08 20:40:35 -0500725
726 const std::string& l_backupAndRestoreCfgFilePath =
727 i_sysCfgJsonObj.value("backupRestoreConfigPath", "");
728
729 if (!l_backupAndRestoreCfgFilePath.empty() &&
730 std::filesystem::exists(l_backupAndRestoreCfgFilePath) &&
731 !std::filesystem::is_empty(l_backupAndRestoreCfgFilePath))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500732 {
Rekha Aparna196e3082025-09-08 20:40:35 -0500733 return true;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500734 }
Rekha Aparna196e3082025-09-08 20:40:35 -0500735
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500736 return false;
737}
738
739/** @brief API to check if an action is required for given EEPROM path.
740 *
741 * System config JSON can contain pre-action, post-action etc. like actions
742 * defined for an EEPROM path. The API will check if any such action is defined
743 * for the EEPROM.
744 *
745 * @param[in] i_sysCfgJsonObj - System config JSON object.
746 * @param[in] i_vpdFruPath - EEPROM path.
747 * @param[in] i_action - Action to be checked.
748 * @param[in] i_flowFlag - Denotes the flow w.r.t which the action should be
749 * triggered.
Rekha Aparnab50bf0e2025-09-02 21:13:26 -0500750 * @param[out] o_errCode - To set error code in case of error.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500751 * @return - True if action is defined for the flow, false otherwise.
752 */
Rekha Aparnab50bf0e2025-09-02 21:13:26 -0500753inline bool isActionRequired(const nlohmann::json& i_sysCfgJsonObj,
754 const std::string& i_vpdFruPath,
755 const std::string& i_action,
756 const std::string& i_flowFlag, uint16_t& o_errCode)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500757{
758 if (i_vpdFruPath.empty() || i_action.empty() || i_flowFlag.empty())
759 {
Rekha Aparnab50bf0e2025-09-02 21:13:26 -0500760 o_errCode = error_code::INVALID_INPUT_PARAMETER;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500761 return false;
762 }
763
764 if (!i_sysCfgJsonObj.contains("frus"))
765 {
Rekha Aparnab50bf0e2025-09-02 21:13:26 -0500766 o_errCode = error_code::INVALID_JSON;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500767 return false;
768 }
769
770 if (!i_sysCfgJsonObj["frus"].contains(i_vpdFruPath))
771 {
Rekha Aparnab50bf0e2025-09-02 21:13:26 -0500772 o_errCode = error_code::FRU_PATH_NOT_FOUND;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500773 return false;
774 }
775
776 if ((i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0)).contains(i_action))
777 {
778 if ((i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0))[i_action].contains(
779 i_flowFlag))
780 {
781 return true;
782 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500783 }
784 return false;
785}
786
787/**
788 * @brief An API to return list of FRUs that needs GPIO polling.
789 *
790 * An API that checks for the FRUs that requires GPIO polling and returns
791 * a list of FRUs that needs polling. Returns an empty list if there are
792 * no FRUs that requires polling.
793 *
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500794 * @param[in] i_sysCfgJsonObj - System config JSON object.
Rekha Aparnadc47adb2025-09-08 11:29:58 -0500795 * @param[out] o_errCode - To set error codes in case of error.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500796 *
RekhaAparna017fea9f52025-02-17 04:14:02 -0600797 * @return On success list of FRUs parameters that needs polling. On failure,
798 * empty list.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500799 */
Patrick Williams43fedab2025-02-03 14:28:05 -0500800inline std::vector<std::string> getListOfGpioPollingFrus(
Rekha Aparnadc47adb2025-09-08 11:29:58 -0500801 const nlohmann::json& i_sysCfgJsonObj, uint16_t& o_errCode)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500802{
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500803 std::vector<std::string> l_gpioPollingRequiredFrusList;
804
Rekha Aparnadc47adb2025-09-08 11:29:58 -0500805 if (i_sysCfgJsonObj.empty())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500806 {
Rekha Aparnadc47adb2025-09-08 11:29:58 -0500807 o_errCode = error_code::INVALID_INPUT_PARAMETER;
808 return l_gpioPollingRequiredFrusList;
RekhaAparna017fea9f52025-02-17 04:14:02 -0600809 }
Rekha Aparnadc47adb2025-09-08 11:29:58 -0500810
811 if (!i_sysCfgJsonObj.contains("frus"))
RekhaAparna017fea9f52025-02-17 04:14:02 -0600812 {
Rekha Aparnadc47adb2025-09-08 11:29:58 -0500813 o_errCode = error_code::INVALID_JSON;
814 return l_gpioPollingRequiredFrusList;
815 }
816
817 for (const auto& l_fru : i_sysCfgJsonObj["frus"].items())
818 {
819 const auto l_fruPath = l_fru.key();
820
821 bool l_isHotPluggableFru =
822 isActionRequired(i_sysCfgJsonObj, l_fruPath, "pollingRequired",
823 "hotPlugging", o_errCode);
824
825 if (o_errCode)
826 {
827 logging::logMessage(
828 "Error while checking if action required for FRU [" +
829 std::string(l_fruPath) +
830 "], error : " + vpdSpecificUtility::getErrCodeMsg(o_errCode));
831
832 return l_gpioPollingRequiredFrusList;
833 }
834
835 if (l_isHotPluggableFru)
836 {
837 if (i_sysCfgJsonObj["frus"][l_fruPath]
838 .at(0)["pollingRequired"]["hotPlugging"]
839 .contains("gpioPresence"))
840 {
841 l_gpioPollingRequiredFrusList.push_back(l_fruPath);
842 }
843 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500844 }
845
846 return l_gpioPollingRequiredFrusList;
847}
848
849/**
850 * @brief Get all related path(s) to update keyword value.
851 *
852 * Given FRU EEPROM path/Inventory path needs keyword's value update, this API
853 * returns tuple of FRU EEPROM path, inventory path and redundant EEPROM path if
854 * exists in the system config JSON.
855 *
856 * Note: If the inventory object path or redundant EEPROM path(s) are not found
857 * in the system config JSON, corresponding fields will have empty value in the
858 * returning tuple.
859 *
860 * @param[in] i_sysCfgJsonObj - System config JSON object.
861 * @param[in,out] io_vpdPath - Inventory object path or FRU EEPROM path.
Rekha Aparna2d6f0712025-09-02 03:52:57 -0500862 * @param[out] o_errCode - To set error code in case of error.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500863 *
864 * @return On success returns tuple of EEPROM path, inventory path & redundant
865 * path, on failure returns tuple with given input path alone.
866 */
867inline std::tuple<std::string, std::string, std::string>
868 getAllPathsToUpdateKeyword(const nlohmann::json& i_sysCfgJsonObj,
Rekha Aparna2d6f0712025-09-02 03:52:57 -0500869 std::string io_vpdPath, uint16_t& o_errCode)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500870{
871 types::Path l_inventoryObjPath;
872 types::Path l_redundantFruPath;
Rekha Aparna2d6f0712025-09-02 03:52:57 -0500873 o_errCode = 0;
874
875 if (i_sysCfgJsonObj.empty() || io_vpdPath.empty())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500876 {
Rekha Aparna2d6f0712025-09-02 03:52:57 -0500877 o_errCode = error_code::INVALID_INPUT_PARAMETER;
878 return std::make_tuple(io_vpdPath, l_inventoryObjPath,
879 l_redundantFruPath);
880 }
Rekha Aparna0578dd22025-09-02 08:20:21 -0500881
Rekha Aparna2d6f0712025-09-02 03:52:57 -0500882 // Get hardware path from system config JSON.
883 const types::Path l_fruPath =
884 jsonUtility::getFruPathFromJson(i_sysCfgJsonObj, io_vpdPath, o_errCode);
885
886 if (!l_fruPath.empty())
887 {
888 io_vpdPath = l_fruPath;
889
890 // Get inventory object path from system config JSON
891 l_inventoryObjPath = jsonUtility::getInventoryObjPathFromJson(
892 i_sysCfgJsonObj, l_fruPath, o_errCode);
893
894 if (l_inventoryObjPath.empty())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500895 {
Rekha Aparna2d6f0712025-09-02 03:52:57 -0500896 if (o_errCode)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500897 {
Rekha Aparna2d6f0712025-09-02 03:52:57 -0500898 logging::logMessage(
899 "Failed to get inventory path from JSON for [" +
900 io_vpdPath + "], error : " +
901 vpdSpecificUtility::getErrCodeMsg(o_errCode));
902 }
903 else
904 {
905 o_errCode = error_code::FRU_PATH_NOT_FOUND;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500906 }
Rekha Aparna0578dd22025-09-02 08:20:21 -0500907
Rekha Aparna2d6f0712025-09-02 03:52:57 -0500908 return std::make_tuple(io_vpdPath, l_inventoryObjPath,
909 l_redundantFruPath);
910 }
911
912 // Get redundant hardware path if present in system config JSON
913 l_redundantFruPath = jsonUtility::getRedundantEepromPathFromJson(
914 i_sysCfgJsonObj, l_fruPath, o_errCode);
915
916 if (l_redundantFruPath.empty())
917 {
918 if (o_errCode)
919 {
920 logging::logMessage(
921 "Failed to get redundant EEPROM path for FRU [" +
922 l_fruPath + "], error : " +
923 vpdSpecificUtility::getErrCodeMsg(o_errCode));
924
925 o_errCode = error_code::ERROR_GETTING_REDUNDANT_PATH;
926 }
927 else
928 {
929 o_errCode = error_code::REDUNDANT_PATH_NOT_FOUND;
930 }
Rekha Aparna0578dd22025-09-02 08:20:21 -0500931
932 return std::make_tuple(io_vpdPath, l_inventoryObjPath,
933 l_redundantFruPath);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500934 }
935 }
Rekha Aparna2d6f0712025-09-02 03:52:57 -0500936 else if (o_errCode)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500937 {
938 logging::logMessage(
Rekha Aparna2d6f0712025-09-02 03:52:57 -0500939 "Failed to get FRU path from JSON for [" + io_vpdPath +
940 "], error : " + vpdSpecificUtility::getErrCodeMsg(o_errCode));
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500941 }
Rekha Aparna2d6f0712025-09-02 03:52:57 -0500942 else
943 {
944 o_errCode = error_code::NO_EEPROM_PATH;
945 }
946
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500947 return std::make_tuple(io_vpdPath, l_inventoryObjPath, l_redundantFruPath);
948}
949
950/**
951 * @brief An API to get DBus service name.
952 *
953 * Given DBus inventory path, this API returns DBus service name if present in
954 * the JSON.
955 *
956 * @param[in] i_sysCfgJsonObj - System config JSON object.
957 * @param[in] l_inventoryPath - DBus inventory path.
Rekha Aparnae0d24c02025-09-02 00:15:06 -0500958 * @param[out] o_errCode - To set error code in case of error.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500959 *
960 * @return On success returns the service name present in the system config
961 * JSON, otherwise empty string.
962 *
963 * Note: Caller has to handle in case of empty string received.
964 */
965inline std::string getServiceName(const nlohmann::json& i_sysCfgJsonObj,
Rekha Aparnae0d24c02025-09-02 00:15:06 -0500966 const std::string& l_inventoryPath,
967 uint16_t& o_errCode)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500968{
Rekha Aparnae0d24c02025-09-02 00:15:06 -0500969 if (l_inventoryPath.empty())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500970 {
Rekha Aparnae0d24c02025-09-02 00:15:06 -0500971 o_errCode = error_code::INVALID_INPUT_PARAMETER;
972 return std::string{};
973 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500974
Rekha Aparnae0d24c02025-09-02 00:15:06 -0500975 if (!i_sysCfgJsonObj.contains("frus"))
976 {
977 o_errCode = error_code::INVALID_JSON;
978 return std::string{};
979 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500980
Rekha Aparnae0d24c02025-09-02 00:15:06 -0500981 const nlohmann::json& l_listOfFrus =
982 i_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500983
Rekha Aparnae0d24c02025-09-02 00:15:06 -0500984 for (const auto& l_frus : l_listOfFrus.items())
985 {
986 for (const auto& l_inventoryItem : l_frus.value())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500987 {
Rekha Aparnae0d24c02025-09-02 00:15:06 -0500988 if (l_inventoryPath.compare(l_inventoryItem["inventoryPath"]) ==
989 constants::STR_CMP_SUCCESS)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500990 {
Rekha Aparnae0d24c02025-09-02 00:15:06 -0500991 if (l_inventoryItem.contains("serviceName"))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500992 {
Rekha Aparnae0d24c02025-09-02 00:15:06 -0500993 return l_inventoryItem.value("serviceName", "");
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500994 }
Rekha Aparnae0d24c02025-09-02 00:15:06 -0500995
996 o_errCode = error_code::JSON_MISSING_SERVICE_NAME;
997 return std::string{};
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500998 }
999 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001000 }
Rekha Aparnae0d24c02025-09-02 00:15:06 -05001001
1002 o_errCode = error_code::FRU_PATH_NOT_FOUND;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001003 return std::string{};
1004}
1005
1006/**
1007 * @brief An API to check if a FRU is tagged as "powerOffOnly"
1008 *
1009 * Given the system config JSON and VPD FRU path, this API checks if the FRU
1010 * VPD can be collected at Chassis Power Off state only.
1011 *
1012 * @param[in] i_sysCfgJsonObj - System config JSON object.
1013 * @param[in] i_vpdFruPath - EEPROM path.
Rekha Aparna52041882025-09-01 20:48:07 -05001014 * @param[out] o_errCode - To set error code for the error.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001015 * @return - True if FRU VPD can be collected at Chassis Power Off state only.
1016 * False otherwise
1017 */
1018inline bool isFruPowerOffOnly(const nlohmann::json& i_sysCfgJsonObj,
Rekha Aparna52041882025-09-01 20:48:07 -05001019 const std::string& i_vpdFruPath,
1020 uint16_t& o_errCode)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001021{
1022 if (i_vpdFruPath.empty())
1023 {
Rekha Aparna52041882025-09-01 20:48:07 -05001024 o_errCode = error_code::INVALID_INPUT_PARAMETER;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001025 return false;
1026 }
1027
1028 if (!i_sysCfgJsonObj.contains("frus"))
1029 {
Rekha Aparna52041882025-09-01 20:48:07 -05001030 o_errCode = error_code::INVALID_JSON;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001031 return false;
1032 }
1033
1034 if (!i_sysCfgJsonObj["frus"].contains(i_vpdFruPath))
1035 {
Rekha Aparna52041882025-09-01 20:48:07 -05001036 o_errCode = error_code::FRU_PATH_NOT_FOUND;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001037 return false;
1038 }
1039
1040 return ((i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0))
1041 .contains("powerOffOnly") &&
1042 (i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0)["powerOffOnly"]));
1043}
1044
1045/**
1046 * @brief API which tells if the FRU is replaceable at runtime
1047 *
1048 * @param[in] i_sysCfgJsonObj - System config JSON object.
1049 * @param[in] i_vpdFruPath - EEPROM path.
Rekha Aparnaad0db9e2025-09-01 20:29:18 -05001050 * @param[out] o_errCode - to set error code in case of error.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001051 *
1052 * @return true if FRU is replaceable at runtime. false otherwise.
1053 */
1054inline bool isFruReplaceableAtRuntime(const nlohmann::json& i_sysCfgJsonObj,
Rekha Aparnaad0db9e2025-09-01 20:29:18 -05001055 const std::string& i_vpdFruPath,
1056 uint16_t& o_errCode)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001057{
Rekha Aparnaad0db9e2025-09-01 20:29:18 -05001058 if (i_vpdFruPath.empty())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001059 {
Rekha Aparnaad0db9e2025-09-01 20:29:18 -05001060 o_errCode = error_code::INVALID_INPUT_PARAMETER;
1061 return false;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001062 }
Rekha Aparnaad0db9e2025-09-01 20:29:18 -05001063
1064 if (i_sysCfgJsonObj.empty() || (!i_sysCfgJsonObj.contains("frus")))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001065 {
Rekha Aparnaad0db9e2025-09-01 20:29:18 -05001066 o_errCode = error_code::INVALID_JSON;
1067 return false;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001068 }
1069
Rekha Aparna41f47e72025-09-18 01:44:09 -05001070 if (!i_sysCfgJsonObj["frus"].contains(i_vpdFruPath))
1071 {
1072 o_errCode = error_code::FRU_PATH_NOT_FOUND;
1073 return false;
1074 }
1075
Rekha Aparnaad0db9e2025-09-01 20:29:18 -05001076 return (
1077 (i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0))
1078 .contains("replaceableAtRuntime") &&
1079 (i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0)["replaceableAtRuntime"]));
1080
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001081 return false;
1082}
1083
1084/**
1085 * @brief API which tells if the FRU is replaceable at standby
1086 *
1087 * @param[in] i_sysCfgJsonObj - System config JSON object.
1088 * @param[in] i_vpdFruPath - EEPROM path.
Rekha Aparna40845612025-09-01 19:58:56 -05001089 * @param[out] o_errCode - set error code in case of error.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001090 *
1091 * @return true if FRU is replaceable at standby. false otherwise.
1092 */
1093inline bool isFruReplaceableAtStandby(const nlohmann::json& i_sysCfgJsonObj,
Rekha Aparna40845612025-09-01 19:58:56 -05001094 const std::string& i_vpdFruPath,
1095 uint16_t& o_errCode)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001096{
Rekha Aparna40845612025-09-01 19:58:56 -05001097 if (i_vpdFruPath.empty())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001098 {
Rekha Aparna40845612025-09-01 19:58:56 -05001099 o_errCode = error_code::INVALID_INPUT_PARAMETER;
1100 return false;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001101 }
Rekha Aparna40845612025-09-01 19:58:56 -05001102
1103 if (i_sysCfgJsonObj.empty() || (!i_sysCfgJsonObj.contains("frus")))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001104 {
Rekha Aparna40845612025-09-01 19:58:56 -05001105 o_errCode = error_code::INVALID_JSON;
Rekha Aparna41f47e72025-09-18 01:44:09 -05001106 return false;
1107 }
1108
1109 if (!i_sysCfgJsonObj["frus"].contains(i_vpdFruPath))
1110 {
1111 o_errCode = error_code::FRU_PATH_NOT_FOUND;
1112 return false;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001113 }
1114
Rekha Aparna40845612025-09-01 19:58:56 -05001115 return (
1116 (i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0))
1117 .contains("replaceableAtStandby") &&
1118 (i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0)["replaceableAtStandby"]));
1119
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001120 return false;
1121}
1122
1123/**
1124 * @brief API to get list of FRUs replaceable at standby from JSON.
1125 *
1126 * The API will return a vector of FRUs inventory path which are replaceable at
1127 * standby.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001128 *
1129 * @param[in] i_sysCfgJsonObj - System config JSON object.
Rekha Aparna88d53302025-09-01 18:16:55 -05001130 * @param[out] o_errCode - To set error code in case of error.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001131 *
RekhaAparna017fea9f52025-02-17 04:14:02 -06001132 * @return - On success, list of FRUs replaceable at standby. On failure, empty
1133 * vector.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001134 */
Patrick Williams43fedab2025-02-03 14:28:05 -05001135inline std::vector<std::string> getListOfFrusReplaceableAtStandby(
Rekha Aparna88d53302025-09-01 18:16:55 -05001136 const nlohmann::json& i_sysCfgJsonObj, uint16_t& o_errCode)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001137{
1138 std::vector<std::string> l_frusReplaceableAtStandby;
1139
Rekha Aparna88d53302025-09-01 18:16:55 -05001140 if (!i_sysCfgJsonObj.contains("frus"))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001141 {
Rekha Aparna88d53302025-09-01 18:16:55 -05001142 o_errCode = error_code::INVALID_JSON;
1143 return l_frusReplaceableAtStandby;
1144 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001145
Rekha Aparna88d53302025-09-01 18:16:55 -05001146 const nlohmann::json& l_fruList =
1147 i_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
RekhaAparna017fea9f52025-02-17 04:14:02 -06001148
Rekha Aparna88d53302025-09-01 18:16:55 -05001149 for (const auto& l_fru : l_fruList.items())
1150 {
1151 if (i_sysCfgJsonObj["frus"][l_fru.key()].at(0).value(
1152 "replaceableAtStandby", false))
RekhaAparna017fea9f52025-02-17 04:14:02 -06001153 {
Rekha Aparna88d53302025-09-01 18:16:55 -05001154 const std::string& l_inventoryObjectPath =
1155 i_sysCfgJsonObj["frus"][l_fru.key()].at(0).value(
1156 "inventoryPath", "");
1157
1158 if (!l_inventoryObjectPath.empty())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001159 {
Rekha Aparna88d53302025-09-01 18:16:55 -05001160 l_frusReplaceableAtStandby.emplace_back(l_inventoryObjectPath);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001161 }
1162 }
1163 }
1164
1165 return l_frusReplaceableAtStandby;
1166}
1167
Sunny Srivastava022112b2025-02-19 19:53:29 +05301168/**
1169 * @brief API to select powerVS JSON based on system IM.
1170 *
1171 * The API selects respective JSON based on system IM, parse it and return the
1172 * JSON object. Empty JSON will be returned in case of any error. Caller needs
1173 * to handle empty value.
1174 *
1175 * @param[in] i_imValue - IM value of the system.
Rekha Aparnaadf85262025-09-09 00:41:00 -05001176 * @param[out] o_errCode - to set error code in case of error.
Sunny Srivastava022112b2025-02-19 19:53:29 +05301177 * @return Parsed JSON object, empty JSON otherwise.
1178 */
Rekha Aparnaadf85262025-09-09 00:41:00 -05001179inline nlohmann::json getPowerVsJson(const types::BinaryVector& i_imValue,
1180 uint16_t& o_errCode)
Sunny Srivastava022112b2025-02-19 19:53:29 +05301181{
Rekha Aparnaadf85262025-09-09 00:41:00 -05001182 if (i_imValue.empty() || i_imValue.size() < 4)
Sunny Srivastava022112b2025-02-19 19:53:29 +05301183 {
Rekha Aparnaadf85262025-09-09 00:41:00 -05001184 o_errCode = error_code::INVALID_INPUT_PARAMETER;
Sunny Srivastava022112b2025-02-19 19:53:29 +05301185 return nlohmann::json{};
1186 }
Rekha Aparnaadf85262025-09-09 00:41:00 -05001187
1188 o_errCode = 0;
1189 if ((i_imValue.at(0) == constants::HEX_VALUE_50) &&
1190 (i_imValue.at(1) == constants::HEX_VALUE_00) &&
1191 (i_imValue.at(2) == constants::HEX_VALUE_30))
Sunny Srivastava022112b2025-02-19 19:53:29 +05301192 {
Rekha Aparnaadf85262025-09-09 00:41:00 -05001193 nlohmann::json l_parsedJson = jsonUtility::getParsedJson(
1194 constants::power_vs_50003_json, o_errCode);
1195
1196 if (o_errCode)
1197 {
1198 logging::logMessage(
1199 "Failed to parse JSON file [ " +
1200 std::string(constants::power_vs_50003_json) +
1201 " ], error : " + vpdSpecificUtility::getErrCodeMsg(o_errCode));
1202 }
1203
1204 return l_parsedJson;
Sunny Srivastava022112b2025-02-19 19:53:29 +05301205 }
Rekha Aparnaadf85262025-09-09 00:41:00 -05001206 else if (i_imValue.at(0) == constants::HEX_VALUE_50 &&
1207 (i_imValue.at(1) == constants::HEX_VALUE_00) &&
1208 (i_imValue.at(2) == constants::HEX_VALUE_10))
1209 {
1210 nlohmann::json l_parsedJson = jsonUtility::getParsedJson(
1211 constants::power_vs_50001_json, o_errCode);
1212
1213 if (o_errCode)
1214 {
1215 logging::logMessage(
1216 "Failed to parse JSON file [ " +
1217 std::string(constants::power_vs_50001_json) +
1218 " ], error : " + vpdSpecificUtility::getErrCodeMsg(o_errCode));
1219 }
1220
1221 return l_parsedJson;
1222 }
1223 return nlohmann::json{};
Sunny Srivastava022112b2025-02-19 19:53:29 +05301224}
Souvik Roy495eedd2025-07-02 02:13:43 -05001225
1226/**
1227 * @brief API to get list of FRUs for which "monitorPresence" is true.
1228 *
1229 * @param[in] i_sysCfgJsonObj - System config JSON object.
Rekha Aparna2362bed2025-09-01 13:18:40 -05001230 * @param[out] o_errCode - To set error code in case of error.
Souvik Roy495eedd2025-07-02 02:13:43 -05001231 *
1232 * @return On success, returns list of FRUs for which "monitorPresence" is true,
1233 * empty list on error.
1234 */
1235inline std::vector<types::Path> getFrusWithPresenceMonitoring(
Rekha Aparna2362bed2025-09-01 13:18:40 -05001236 const nlohmann::json& i_sysCfgJsonObj, uint16_t& o_errCode)
Souvik Roy495eedd2025-07-02 02:13:43 -05001237{
1238 std::vector<types::Path> l_frusWithPresenceMonitoring;
Rekha Aparna2362bed2025-09-01 13:18:40 -05001239
1240 if (!i_sysCfgJsonObj.contains("frus"))
Souvik Roy495eedd2025-07-02 02:13:43 -05001241 {
Rekha Aparna2362bed2025-09-01 13:18:40 -05001242 o_errCode = error_code::INVALID_JSON;
1243 return l_frusWithPresenceMonitoring;
1244 }
Souvik Roy495eedd2025-07-02 02:13:43 -05001245
Rekha Aparna2362bed2025-09-01 13:18:40 -05001246 const nlohmann::json& l_listOfFrus =
1247 i_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
Souvik Roy495eedd2025-07-02 02:13:43 -05001248
Rekha Aparna2362bed2025-09-01 13:18:40 -05001249 for (const auto& l_aFru : l_listOfFrus)
1250 {
1251 if (l_aFru.at(0).value("monitorPresence", false))
Souvik Roy495eedd2025-07-02 02:13:43 -05001252 {
Rekha Aparna2362bed2025-09-01 13:18:40 -05001253 l_frusWithPresenceMonitoring.emplace_back(
1254 l_aFru.at(0).value("inventoryPath", ""));
Souvik Roy495eedd2025-07-02 02:13:43 -05001255 }
1256 }
Rekha Aparna2362bed2025-09-01 13:18:40 -05001257
Souvik Roy495eedd2025-07-02 02:13:43 -05001258 return l_frusWithPresenceMonitoring;
1259}
Souvik Roye9120152025-07-02 08:24:38 -05001260
1261/**
1262 * @brief API which tells if the FRU's presence is handled
1263 *
1264 * For a given FRU, this API checks if it's presence is handled by vpd-manager
1265 * by checking the "handlePresence" tag.
1266 *
1267 * @param[in] i_sysCfgJsonObj - System config JSON object.
1268 * @param[in] i_vpdFruPath - EEPROM path.
Rekha Aparnaa1187a52025-09-01 12:42:19 -05001269 * @param[out] o_errCode - To set error code in case of failure.
Souvik Roye9120152025-07-02 08:24:38 -05001270 *
1271 * @return true if FRU presence is handled, false otherwise.
1272 */
1273inline bool isFruPresenceHandled(const nlohmann::json& i_sysCfgJsonObj,
Rekha Aparnaa1187a52025-09-01 12:42:19 -05001274 const std::string& i_vpdFruPath,
1275 uint16_t& o_errCode)
Souvik Roye9120152025-07-02 08:24:38 -05001276{
Rekha Aparnaa1187a52025-09-01 12:42:19 -05001277 if (i_vpdFruPath.empty())
Souvik Roye9120152025-07-02 08:24:38 -05001278 {
Rekha Aparnaa1187a52025-09-01 12:42:19 -05001279 o_errCode = error_code::INVALID_INPUT_PARAMETER;
1280 return false;
Souvik Roye9120152025-07-02 08:24:38 -05001281 }
1282
Rekha Aparnaa1187a52025-09-01 12:42:19 -05001283 if (!i_sysCfgJsonObj.contains("frus"))
1284 {
1285 o_errCode = error_code::INVALID_JSON;
1286 return false;
1287 }
1288
1289 if (!i_sysCfgJsonObj["frus"].contains(i_vpdFruPath))
1290 {
1291 o_errCode = error_code::FRU_PATH_NOT_FOUND;
1292 return false;
1293 }
1294
1295 return i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0).value(
1296 "handlePresence", true);
Souvik Roye9120152025-07-02 08:24:38 -05001297}
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001298} // namespace jsonUtility
1299} // namespace vpd