blob: 8de6f7c2bf04954c77c6355a9e823d825daa17cd [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 Aparnaff7d7992025-09-01 11:08:53 -0500228 if (!(i_parsedConfigJson["frus"][i_vpdFilePath].at(0))["postFailAction"]
229 .contains(i_flagToProcess))
230 {
231 o_errCode = error_code::MISSING_FLAG;
232 return false;
233 }
RekhaAparna01c11e8b62025-02-20 00:34:35 -0600234
Rekha Aparnaff7d7992025-09-01 11:08:53 -0500235 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())
RekhaAparna01c11e8b62025-02-20 00:34:35 -0600241 {
Rekha Aparnaff7d7992025-09-01 11:08:53 -0500242 if (!itrToFunction->second(i_parsedConfigJson, i_vpdFilePath,
Sunny Srivastava84c3d232025-09-03 00:47:10 -0500243 "postFailAction", i_flagToProcess,
244 o_errCode))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500245 {
Sunny Srivastava84c3d232025-09-03 00:47:10 -0500246 if (o_errCode)
247 {
248 logging::logMessage(
249 l_tags.key() + " failed for [" + i_vpdFilePath +
250 "]. Reason " +
251 vpdSpecificUtility::getErrCodeMsg(o_errCode));
252 }
Rekha Aparnaff7d7992025-09-01 11:08:53 -0500253 return false;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500254 }
255 }
256 }
257
258 return true;
259}
260
261/**
262 * @brief Process "systemCmd" tag for a given FRU.
263 *
264 * The API will process "systemCmd" tag if it is defined in the config
265 * JSON for the given FRU.
266 *
267 * @param[in] i_parsedConfigJson - config JSON
268 * @param[in] i_vpdFilePath - EEPROM file path
269 * @param[in] i_baseAction - Base action for which this tag has been called.
270 * @param[in] i_flagToProcess - Flag nested under the base action for which this
271 * tag has been called.
Sunny Srivastava84c3d232025-09-03 00:47:10 -0500272 * @param[out] o_errCode - To set error code in case of error.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500273 * @return Execution status.
274 */
275inline bool processSystemCmdTag(
276 const nlohmann::json& i_parsedConfigJson, const std::string& i_vpdFilePath,
Sunny Srivastava84c3d232025-09-03 00:47:10 -0500277 const std::string& i_baseAction, const std::string& i_flagToProcess,
278 uint16_t& o_errCode)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500279{
Sunny Srivastava84c3d232025-09-03 00:47:10 -0500280 if (i_vpdFilePath.empty() || i_parsedConfigJson.empty() ||
281 i_baseAction.empty() || i_flagToProcess.empty())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500282 {
Sunny Srivastava84c3d232025-09-03 00:47:10 -0500283 o_errCode = error_code::INVALID_INPUT_PARAMETER;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500284 return false;
285 }
Sunny Srivastava84c3d232025-09-03 00:47:10 -0500286
287 if (!((i_parsedConfigJson["frus"][i_vpdFilePath].at(
288 0)[i_baseAction][i_flagToProcess]["systemCmd"])
289 .contains("cmd")))
290 {
291 o_errCode = error_code::MISSING_FLAG;
292 return false;
293 }
294
295 const std::string& l_systemCommand =
296 i_parsedConfigJson["frus"][i_vpdFilePath].at(
297 0)[i_baseAction][i_flagToProcess]["systemCmd"]["cmd"];
298
299 commonUtility::executeCmd(l_systemCommand);
300 return true;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500301}
302
303/**
304 * @brief Checks for presence of a given FRU using GPIO line.
305 *
306 * This API returns the presence information of the FRU corresponding to the
307 * given VPD file path by setting the presence pin.
308 *
309 * @param[in] i_parsedConfigJson - config JSON
310 * @param[in] i_vpdFilePath - EEPROM file path
311 * @param[in] i_baseAction - Base action for which this tag has been called.
312 * @param[in] i_flagToProcess - Flag nested under the base action for which this
313 * tag has been called.
Sunny Srivastava84c3d232025-09-03 00:47:10 -0500314 * @param[out] o_errCode - To set error code in case of error
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500315 * @return Execution status.
316 */
317inline bool processGpioPresenceTag(
318 const nlohmann::json& i_parsedConfigJson, const std::string& i_vpdFilePath,
Sunny Srivastava84c3d232025-09-03 00:47:10 -0500319 const std::string& i_baseAction, const std::string& i_flagToProcess,
320 uint16_t& o_errCode)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500321{
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530322 std::string l_presencePinName;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500323 try
324 {
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530325 if (i_vpdFilePath.empty() || i_parsedConfigJson.empty() ||
326 i_baseAction.empty() || i_flagToProcess.empty())
327 {
Sunny Srivastava84c3d232025-09-03 00:47:10 -0500328 o_errCode = error_code::INVALID_INPUT_PARAMETER;
329 return false;
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530330 }
331
332 if (!(((i_parsedConfigJson["frus"][i_vpdFilePath].at(
333 0)[i_baseAction][i_flagToProcess]["gpioPresence"])
334 .contains("pin")) &&
335 ((i_parsedConfigJson["frus"][i_vpdFilePath].at(
336 0)[i_baseAction][i_flagToProcess]["gpioPresence"])
337 .contains("value"))))
338 {
Sunny Srivastava84c3d232025-09-03 00:47:10 -0500339 o_errCode = error_code::JSON_MISSING_GPIO_INFO;
340 return false;
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530341 }
342
343 // get the pin name
344 l_presencePinName = i_parsedConfigJson["frus"][i_vpdFilePath].at(
345 0)[i_baseAction][i_flagToProcess]["gpioPresence"]["pin"];
346
347 // get the pin value
348 uint8_t l_presencePinValue =
349 i_parsedConfigJson["frus"][i_vpdFilePath].at(
350 0)[i_baseAction][i_flagToProcess]["gpioPresence"]["value"];
351
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500352 gpiod::line l_presenceLine = gpiod::find_line(l_presencePinName);
353
354 if (!l_presenceLine)
355 {
Sunny Srivastava84c3d232025-09-03 00:47:10 -0500356 o_errCode = error_code::DEVICE_PRESENCE_UNKNOWN;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500357 throw GpioException("Couldn't find the GPIO line.");
358 }
359
360 l_presenceLine.request({"Read the presence line",
361 gpiod::line_request::DIRECTION_INPUT, 0});
362
Sunny Srivastava84c3d232025-09-03 00:47:10 -0500363 if (l_presencePinValue != l_presenceLine.get_value())
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530364 {
Sunny Srivastava84c3d232025-09-03 00:47:10 -0500365 // As false is being returned in this case, caller needs to know
366 // that it is not due to some exception. It is because the pin was
367 // read correctly but was not having expected value.
368 o_errCode = error_code::DEVICE_NOT_PRESENT;
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530369 return false;
370 }
371
Sunny Srivastava84c3d232025-09-03 00:47:10 -0500372 return true;
373 }
374 catch (const std::exception& l_ex)
375 {
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500376 std::string l_errMsg = "Exception on GPIO line: ";
377 l_errMsg += l_presencePinName;
378 l_errMsg += " Reason: ";
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530379 l_errMsg += l_ex.what();
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500380 l_errMsg += " File: " + i_vpdFilePath + " Pel Logged";
381
Rekha Aparna017567a2025-08-13 02:07:06 -0500382 uint16_t l_errCode = 0;
383
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500384 // ToDo -- Update Internal Rc code.
385 EventLogger::createAsyncPelWithInventoryCallout(
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530386 EventLogger::getErrorType(l_ex), types::SeverityType::Informational,
Rekha Aparna017567a2025-08-13 02:07:06 -0500387 {{getInventoryObjPathFromJson(i_parsedConfigJson, i_vpdFilePath,
388 l_errCode),
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500389 types::CalloutPriority::High}},
390 std::source_location::current().file_name(),
391 std::source_location::current().function_name(), 0, l_errMsg,
392 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
393
394 logging::logMessage(l_errMsg);
395
396 // Except when GPIO pin value is false, we go and try collecting the
397 // FRU VPD as we couldn't able to read GPIO pin value due to some
398 // error/exception. So returning true in error scenario.
399 return true;
400 }
401}
402
403/**
404 * @brief Process "setGpio" tag for a given FRU.
405 *
406 * This API enables the GPIO line.
407 *
408 * @param[in] i_parsedConfigJson - config JSON
409 * @param[in] i_vpdFilePath - EEPROM file path
410 * @param[in] i_baseAction - Base action for which this tag has been called.
411 * @param[in] i_flagToProcess - Flag nested under the base action for which this
412 * tag has been called.
Sunny Srivastava84c3d232025-09-03 00:47:10 -0500413 * @param[out] o_errCode - To set error code in case of error
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500414 * @return Execution status.
415 */
416inline bool procesSetGpioTag(
417 const nlohmann::json& i_parsedConfigJson, const std::string& i_vpdFilePath,
Sunny Srivastava84c3d232025-09-03 00:47:10 -0500418 const std::string& i_baseAction, const std::string& i_flagToProcess,
419 uint16_t& o_errCode)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500420{
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530421 std::string l_pinName;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500422 try
423 {
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530424 if (i_vpdFilePath.empty() || i_parsedConfigJson.empty() ||
425 i_baseAction.empty() || i_flagToProcess.empty())
426 {
Sunny Srivastava84c3d232025-09-03 00:47:10 -0500427 o_errCode = error_code::INVALID_INPUT_PARAMETER;
428 return false;
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530429 }
430
431 if (!(((i_parsedConfigJson["frus"][i_vpdFilePath].at(
432 0)[i_baseAction][i_flagToProcess]["setGpio"])
433 .contains("pin")) &&
434 ((i_parsedConfigJson["frus"][i_vpdFilePath].at(
435 0)[i_baseAction][i_flagToProcess]["setGpio"])
436 .contains("value"))))
437 {
Sunny Srivastava84c3d232025-09-03 00:47:10 -0500438 o_errCode = error_code::JSON_MISSING_GPIO_INFO;
439 return false;
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530440 }
441
442 l_pinName = i_parsedConfigJson["frus"][i_vpdFilePath].at(
443 0)[i_baseAction][i_flagToProcess]["setGpio"]["pin"];
444
445 // Get the value to set
446 uint8_t l_pinValue = i_parsedConfigJson["frus"][i_vpdFilePath].at(
447 0)[i_baseAction][i_flagToProcess]["setGpio"]["value"];
448
449 logging::logMessage(
450 "Setting GPIO: " + l_pinName + " to " + std::to_string(l_pinValue));
451
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500452 gpiod::line l_outputLine = gpiod::find_line(l_pinName);
453
454 if (!l_outputLine)
455 {
Sunny Srivastava84c3d232025-09-03 00:47:10 -0500456 o_errCode = error_code::GPIO_LINE_EXCEPTION;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500457 throw GpioException("Couldn't find GPIO line.");
458 }
459
460 l_outputLine.request(
461 {"FRU Action", ::gpiod::line_request::DIRECTION_OUTPUT, 0},
462 l_pinValue);
463 return true;
464 }
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530465 catch (const std::exception& l_ex)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500466 {
Sunny Srivastava84c3d232025-09-03 00:47:10 -0500467 std::string l_errMsg = "Exception on GPIO line: ";
468 l_errMsg += l_pinName;
469 l_errMsg += " Reason: ";
470 l_errMsg += l_ex.what();
471 l_errMsg += " File: " + i_vpdFilePath + " Pel Logged";
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500472
Sunny Srivastava84c3d232025-09-03 00:47:10 -0500473 uint16_t l_errCode = 0;
Rekha Aparna017567a2025-08-13 02:07:06 -0500474
Sunny Srivastava84c3d232025-09-03 00:47:10 -0500475 // ToDo -- Update Internal RC code
476 EventLogger::createAsyncPelWithInventoryCallout(
477 EventLogger::getErrorType(l_ex), types::SeverityType::Informational,
478 {{getInventoryObjPathFromJson(i_parsedConfigJson, i_vpdFilePath,
479 l_errCode),
480 types::CalloutPriority::High}},
481 std::source_location::current().file_name(),
482 std::source_location::current().function_name(), 0, l_errMsg,
483 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500484
Sunny Srivastava84c3d232025-09-03 00:47:10 -0500485 logging::logMessage(l_errMsg);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500486
487 return false;
488 }
489}
490
491/**
492 * @brief Process any action, if defined in config JSON.
493 *
494 * If any FRU(s) requires any special handling, then this base action can be
495 * defined for that FRU in the config JSON, processing of which will be handled
496 * in this API.
497 * Examples of action - preAction, PostAction etc.
498 *
499 * @param[in] i_parsedConfigJson - config JSON
500 * @param[in] i_action - Base action to be performed.
501 * @param[in] i_vpdFilePath - EEPROM file path
502 * @param[in] i_flagToProcess - To identify which flag(s) needs to be processed
503 * under PreAction tag of config JSON.
Sunny Srivastava4f053df2025-09-03 02:27:37 -0500504 * @param[out] o_errCode - To set error code in case of error.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500505 * @return - success or failure
506 */
507inline bool executeBaseAction(
508 const nlohmann::json& i_parsedConfigJson, const std::string& i_action,
Sunny Srivastava4f053df2025-09-03 02:27:37 -0500509 const std::string& i_vpdFilePath, const std::string& i_flagToProcess,
510 uint16_t& o_errCode)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500511{
Sunny Srivastava4f053df2025-09-03 02:27:37 -0500512 if (i_flagToProcess.empty() || i_action.empty() || i_vpdFilePath.empty() ||
513 !i_parsedConfigJson.contains("frus"))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500514 {
Sunny Srivastava4f053df2025-09-03 02:27:37 -0500515 o_errCode = error_code::INVALID_INPUT_PARAMETER;
516 return false;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500517 }
Sunny Srivastava4f053df2025-09-03 02:27:37 -0500518 if (!i_parsedConfigJson["frus"].contains(i_vpdFilePath))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500519 {
Sunny Srivastava4f053df2025-09-03 02:27:37 -0500520 o_errCode = error_code::FILE_NOT_FOUND;
521 return false;
522 }
523 if (!i_parsedConfigJson["frus"][i_vpdFilePath].at(0).contains(i_action))
524 {
525 o_errCode = error_code::MISSING_ACTION_TAG;
526 return false;
527 }
528
529 if (!(i_parsedConfigJson["frus"][i_vpdFilePath].at(0))[i_action].contains(
530 i_flagToProcess))
531 {
532 o_errCode = error_code::MISSING_FLAG;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500533 return false;
534 }
535
536 const nlohmann::json& l_tagsJson =
537 (i_parsedConfigJson["frus"][i_vpdFilePath].at(
538 0))[i_action][i_flagToProcess];
539
540 for (const auto& l_tag : l_tagsJson.items())
541 {
542 auto itrToFunction = funcionMap.find(l_tag.key());
543 if (itrToFunction != funcionMap.end())
544 {
545 if (!itrToFunction->second(i_parsedConfigJson, i_vpdFilePath,
Sunny Srivastava84c3d232025-09-03 00:47:10 -0500546 i_action, i_flagToProcess, o_errCode))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500547 {
548 // In case any of the tag fails to execute. Mark action
549 // as failed for that flag.
Sunny Srivastava84c3d232025-09-03 00:47:10 -0500550 if (o_errCode)
551 {
552 logging::logMessage(
553 l_tag.key() + " failed for [" + i_vpdFilePath +
554 "]. Reason " +
555 vpdSpecificUtility::getErrCodeMsg(o_errCode));
556 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500557 return false;
558 }
559 }
560 }
561
562 return true;
563}
564
565/**
566 * @brief Get redundant FRU path from system config JSON
567 *
568 * Given either D-bus inventory path/FRU path/redundant FRU path, this
569 * API returns the redundant FRU path taken from "redundantEeprom" tag from
570 * system config JSON.
571 *
572 * @param[in] i_sysCfgJsonObj - System config JSON object.
573 * @param[in] i_vpdPath - Path to where VPD is stored.
Rekha Aparnabb52af42025-09-02 04:05:18 -0500574 * @param[out] o_errCode - To set error code in case of error.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500575 *
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500576 * @return On success return valid path, on failure return empty string.
577 */
578inline std::string getRedundantEepromPathFromJson(
Rekha Aparnabb52af42025-09-02 04:05:18 -0500579 const nlohmann::json& i_sysCfgJsonObj, const std::string& i_vpdPath,
580 uint16_t& o_errCode)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500581{
Rekha Aparnabb52af42025-09-02 04:05:18 -0500582 if (i_vpdPath.empty())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500583 {
Rekha Aparnabb52af42025-09-02 04:05:18 -0500584 o_errCode = error_code::INVALID_INPUT_PARAMETER;
585 return std::string{};
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500586 }
Rekha Aparnabb52af42025-09-02 04:05:18 -0500587
588 if (!i_sysCfgJsonObj.contains("frus"))
RekhaAparna017fea9f52025-02-17 04:14:02 -0600589 {
Rekha Aparnabb52af42025-09-02 04:05:18 -0500590 o_errCode = error_code::INVALID_JSON;
591 return std::string{};
592 }
593
594 // check if given path is FRU path
595 if (i_sysCfgJsonObj["frus"].contains(i_vpdPath))
596 {
597 return i_sysCfgJsonObj["frus"][i_vpdPath].at(0).value(
598 "redundantEeprom", "");
599 }
600
601 const nlohmann::json& l_fruList =
602 i_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
603
604 for (const auto& l_fru : l_fruList.items())
605 {
606 const std::string& l_fruPath = l_fru.key();
607 const std::string& l_redundantFruPath =
608 i_sysCfgJsonObj["frus"][l_fruPath].at(0).value("redundantEeprom",
609 "");
610
611 // check if given path is inventory path or redundant FRU path
612 if ((i_sysCfgJsonObj["frus"][l_fruPath].at(0).value("inventoryPath",
613 "") == i_vpdPath) ||
614 (l_redundantFruPath == i_vpdPath))
615 {
616 return l_redundantFruPath;
617 }
RekhaAparna017fea9f52025-02-17 04:14:02 -0600618 }
619
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500620 return std::string();
621}
622
623/**
624 * @brief Get FRU EEPROM path from system config JSON
625 *
626 * Given either D-bus inventory path/FRU EEPROM path/redundant EEPROM path,
627 * this API returns FRU EEPROM path if present in JSON.
628 *
629 * @param[in] i_sysCfgJsonObj - System config JSON object
630 * @param[in] i_vpdPath - Path to where VPD is stored.
Rekha Aparna0578dd22025-09-02 08:20:21 -0500631 * @param[out] o_errCode - To set error code in case of error.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500632 *
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500633 * @return On success return valid path, on failure return empty string.
634 */
635inline std::string getFruPathFromJson(const nlohmann::json& i_sysCfgJsonObj,
Rekha Aparna0578dd22025-09-02 08:20:21 -0500636 const std::string& i_vpdPath,
637 uint16_t& o_errCode)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500638{
Rekha Aparna0578dd22025-09-02 08:20:21 -0500639 if (i_vpdPath.empty())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500640 {
Rekha Aparna0578dd22025-09-02 08:20:21 -0500641 o_errCode = error_code::INVALID_INPUT_PARAMETER;
642 return std::string{};
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500643 }
Rekha Aparna0578dd22025-09-02 08:20:21 -0500644
645 if (!i_sysCfgJsonObj.contains("frus"))
RekhaAparna017fea9f52025-02-17 04:14:02 -0600646 {
Rekha Aparna0578dd22025-09-02 08:20:21 -0500647 o_errCode = error_code::INVALID_JSON;
648 return std::string{};
649 }
650
651 // check if given path is FRU path
652 if (i_sysCfgJsonObj["frus"].contains(i_vpdPath))
653 {
654 return i_vpdPath;
655 }
656
657 const nlohmann::json& l_fruList =
658 i_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
659
660 for (const auto& l_fru : l_fruList.items())
661 {
662 const auto l_fruPath = l_fru.key();
663
664 // check if given path is redundant FRU path or inventory path
665 if (i_vpdPath == i_sysCfgJsonObj["frus"][l_fruPath].at(0).value(
666 "redundantEeprom", "") ||
667 (i_vpdPath == i_sysCfgJsonObj["frus"][l_fruPath].at(0).value(
668 "inventoryPath", "")))
669 {
670 return l_fruPath;
671 }
RekhaAparna017fea9f52025-02-17 04:14:02 -0600672 }
673
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500674 return std::string();
675}
676
677/**
678 * @brief An API to check backup and restore VPD is required.
679 *
680 * The API checks if there is provision for backup and restore mentioned in the
681 * system config JSON, by looking "backupRestoreConfigPath" tag.
682 * Checks if the path mentioned is a hardware path, by checking if the file path
683 * exists and size of contents in the path.
684 *
685 * @param[in] i_sysCfgJsonObj - System config JSON object.
Rekha Aparna196e3082025-09-08 20:40:35 -0500686 * @param[out] o_errCode - To set error code in case of error.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500687 *
688 * @return true if backup and restore is required, false otherwise.
689 */
Rekha Aparna196e3082025-09-08 20:40:35 -0500690inline bool isBackupAndRestoreRequired(const nlohmann::json& i_sysCfgJsonObj,
691 uint16_t& o_errCode)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500692{
Rekha Aparna196e3082025-09-08 20:40:35 -0500693 if (i_sysCfgJsonObj.empty())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500694 {
Rekha Aparna196e3082025-09-08 20:40:35 -0500695 o_errCode = error_code::INVALID_INPUT_PARAMETER;
696 return false;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500697 }
Rekha Aparna196e3082025-09-08 20:40:35 -0500698
699 const std::string& l_backupAndRestoreCfgFilePath =
700 i_sysCfgJsonObj.value("backupRestoreConfigPath", "");
701
702 if (!l_backupAndRestoreCfgFilePath.empty() &&
703 std::filesystem::exists(l_backupAndRestoreCfgFilePath) &&
704 !std::filesystem::is_empty(l_backupAndRestoreCfgFilePath))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500705 {
Rekha Aparna196e3082025-09-08 20:40:35 -0500706 return true;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500707 }
Rekha Aparna196e3082025-09-08 20:40:35 -0500708
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500709 return false;
710}
711
712/** @brief API to check if an action is required for given EEPROM path.
713 *
714 * System config JSON can contain pre-action, post-action etc. like actions
715 * defined for an EEPROM path. The API will check if any such action is defined
716 * for the EEPROM.
717 *
718 * @param[in] i_sysCfgJsonObj - System config JSON object.
719 * @param[in] i_vpdFruPath - EEPROM path.
720 * @param[in] i_action - Action to be checked.
721 * @param[in] i_flowFlag - Denotes the flow w.r.t which the action should be
722 * triggered.
Rekha Aparnab50bf0e2025-09-02 21:13:26 -0500723 * @param[out] o_errCode - To set error code in case of error.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500724 * @return - True if action is defined for the flow, false otherwise.
725 */
Rekha Aparnab50bf0e2025-09-02 21:13:26 -0500726inline bool isActionRequired(const nlohmann::json& i_sysCfgJsonObj,
727 const std::string& i_vpdFruPath,
728 const std::string& i_action,
729 const std::string& i_flowFlag, uint16_t& o_errCode)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500730{
731 if (i_vpdFruPath.empty() || i_action.empty() || i_flowFlag.empty())
732 {
Rekha Aparnab50bf0e2025-09-02 21:13:26 -0500733 o_errCode = error_code::INVALID_INPUT_PARAMETER;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500734 return false;
735 }
736
737 if (!i_sysCfgJsonObj.contains("frus"))
738 {
Rekha Aparnab50bf0e2025-09-02 21:13:26 -0500739 o_errCode = error_code::INVALID_JSON;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500740 return false;
741 }
742
743 if (!i_sysCfgJsonObj["frus"].contains(i_vpdFruPath))
744 {
Rekha Aparnab50bf0e2025-09-02 21:13:26 -0500745 o_errCode = error_code::FRU_PATH_NOT_FOUND;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500746 return false;
747 }
748
749 if ((i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0)).contains(i_action))
750 {
751 if ((i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0))[i_action].contains(
752 i_flowFlag))
753 {
754 return true;
755 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500756 }
757 return false;
758}
759
760/**
761 * @brief An API to return list of FRUs that needs GPIO polling.
762 *
763 * An API that checks for the FRUs that requires GPIO polling and returns
764 * a list of FRUs that needs polling. Returns an empty list if there are
765 * no FRUs that requires polling.
766 *
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500767 * @param[in] i_sysCfgJsonObj - System config JSON object.
Rekha Aparnadc47adb2025-09-08 11:29:58 -0500768 * @param[out] o_errCode - To set error codes in case of error.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500769 *
RekhaAparna017fea9f52025-02-17 04:14:02 -0600770 * @return On success list of FRUs parameters that needs polling. On failure,
771 * empty list.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500772 */
Patrick Williams43fedab2025-02-03 14:28:05 -0500773inline std::vector<std::string> getListOfGpioPollingFrus(
Rekha Aparnadc47adb2025-09-08 11:29:58 -0500774 const nlohmann::json& i_sysCfgJsonObj, uint16_t& o_errCode)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500775{
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500776 std::vector<std::string> l_gpioPollingRequiredFrusList;
777
Rekha Aparnadc47adb2025-09-08 11:29:58 -0500778 if (i_sysCfgJsonObj.empty())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500779 {
Rekha Aparnadc47adb2025-09-08 11:29:58 -0500780 o_errCode = error_code::INVALID_INPUT_PARAMETER;
781 return l_gpioPollingRequiredFrusList;
RekhaAparna017fea9f52025-02-17 04:14:02 -0600782 }
Rekha Aparnadc47adb2025-09-08 11:29:58 -0500783
784 if (!i_sysCfgJsonObj.contains("frus"))
RekhaAparna017fea9f52025-02-17 04:14:02 -0600785 {
Rekha Aparnadc47adb2025-09-08 11:29:58 -0500786 o_errCode = error_code::INVALID_JSON;
787 return l_gpioPollingRequiredFrusList;
788 }
789
790 for (const auto& l_fru : i_sysCfgJsonObj["frus"].items())
791 {
792 const auto l_fruPath = l_fru.key();
793
794 bool l_isHotPluggableFru =
795 isActionRequired(i_sysCfgJsonObj, l_fruPath, "pollingRequired",
796 "hotPlugging", o_errCode);
797
798 if (o_errCode)
799 {
800 logging::logMessage(
801 "Error while checking if action required for FRU [" +
802 std::string(l_fruPath) +
803 "], error : " + vpdSpecificUtility::getErrCodeMsg(o_errCode));
804
805 return l_gpioPollingRequiredFrusList;
806 }
807
808 if (l_isHotPluggableFru)
809 {
810 if (i_sysCfgJsonObj["frus"][l_fruPath]
811 .at(0)["pollingRequired"]["hotPlugging"]
812 .contains("gpioPresence"))
813 {
814 l_gpioPollingRequiredFrusList.push_back(l_fruPath);
815 }
816 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500817 }
818
819 return l_gpioPollingRequiredFrusList;
820}
821
822/**
823 * @brief Get all related path(s) to update keyword value.
824 *
825 * Given FRU EEPROM path/Inventory path needs keyword's value update, this API
826 * returns tuple of FRU EEPROM path, inventory path and redundant EEPROM path if
827 * exists in the system config JSON.
828 *
829 * Note: If the inventory object path or redundant EEPROM path(s) are not found
830 * in the system config JSON, corresponding fields will have empty value in the
831 * returning tuple.
832 *
833 * @param[in] i_sysCfgJsonObj - System config JSON object.
834 * @param[in,out] io_vpdPath - Inventory object path or FRU EEPROM path.
Rekha Aparna2d6f0712025-09-02 03:52:57 -0500835 * @param[out] o_errCode - To set error code in case of error.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500836 *
837 * @return On success returns tuple of EEPROM path, inventory path & redundant
838 * path, on failure returns tuple with given input path alone.
839 */
840inline std::tuple<std::string, std::string, std::string>
841 getAllPathsToUpdateKeyword(const nlohmann::json& i_sysCfgJsonObj,
Rekha Aparna2d6f0712025-09-02 03:52:57 -0500842 std::string io_vpdPath, uint16_t& o_errCode)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500843{
844 types::Path l_inventoryObjPath;
845 types::Path l_redundantFruPath;
Rekha Aparna2d6f0712025-09-02 03:52:57 -0500846 o_errCode = 0;
847
848 if (i_sysCfgJsonObj.empty() || io_vpdPath.empty())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500849 {
Rekha Aparna2d6f0712025-09-02 03:52:57 -0500850 o_errCode = error_code::INVALID_INPUT_PARAMETER;
851 return std::make_tuple(io_vpdPath, l_inventoryObjPath,
852 l_redundantFruPath);
853 }
Rekha Aparna0578dd22025-09-02 08:20:21 -0500854
Rekha Aparna2d6f0712025-09-02 03:52:57 -0500855 // Get hardware path from system config JSON.
856 const types::Path l_fruPath =
857 jsonUtility::getFruPathFromJson(i_sysCfgJsonObj, io_vpdPath, o_errCode);
858
859 if (!l_fruPath.empty())
860 {
861 io_vpdPath = l_fruPath;
862
863 // Get inventory object path from system config JSON
864 l_inventoryObjPath = jsonUtility::getInventoryObjPathFromJson(
865 i_sysCfgJsonObj, l_fruPath, o_errCode);
866
867 if (l_inventoryObjPath.empty())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500868 {
Rekha Aparna2d6f0712025-09-02 03:52:57 -0500869 if (o_errCode)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500870 {
Rekha Aparna2d6f0712025-09-02 03:52:57 -0500871 logging::logMessage(
872 "Failed to get inventory path from JSON for [" +
873 io_vpdPath + "], error : " +
874 vpdSpecificUtility::getErrCodeMsg(o_errCode));
875 }
876 else
877 {
878 o_errCode = error_code::FRU_PATH_NOT_FOUND;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500879 }
Rekha Aparna0578dd22025-09-02 08:20:21 -0500880
Rekha Aparna2d6f0712025-09-02 03:52:57 -0500881 return std::make_tuple(io_vpdPath, l_inventoryObjPath,
882 l_redundantFruPath);
883 }
884
885 // Get redundant hardware path if present in system config JSON
886 l_redundantFruPath = jsonUtility::getRedundantEepromPathFromJson(
887 i_sysCfgJsonObj, l_fruPath, o_errCode);
888
889 if (l_redundantFruPath.empty())
890 {
891 if (o_errCode)
892 {
893 logging::logMessage(
894 "Failed to get redundant EEPROM path for FRU [" +
895 l_fruPath + "], error : " +
896 vpdSpecificUtility::getErrCodeMsg(o_errCode));
897
898 o_errCode = error_code::ERROR_GETTING_REDUNDANT_PATH;
899 }
900 else
901 {
902 o_errCode = error_code::REDUNDANT_PATH_NOT_FOUND;
903 }
Rekha Aparna0578dd22025-09-02 08:20:21 -0500904
905 return std::make_tuple(io_vpdPath, l_inventoryObjPath,
906 l_redundantFruPath);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500907 }
908 }
Rekha Aparna2d6f0712025-09-02 03:52:57 -0500909 else if (o_errCode)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500910 {
911 logging::logMessage(
Rekha Aparna2d6f0712025-09-02 03:52:57 -0500912 "Failed to get FRU path from JSON for [" + io_vpdPath +
913 "], error : " + vpdSpecificUtility::getErrCodeMsg(o_errCode));
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500914 }
Rekha Aparna2d6f0712025-09-02 03:52:57 -0500915 else
916 {
917 o_errCode = error_code::NO_EEPROM_PATH;
918 }
919
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500920 return std::make_tuple(io_vpdPath, l_inventoryObjPath, l_redundantFruPath);
921}
922
923/**
924 * @brief An API to get DBus service name.
925 *
926 * Given DBus inventory path, this API returns DBus service name if present in
927 * the JSON.
928 *
929 * @param[in] i_sysCfgJsonObj - System config JSON object.
930 * @param[in] l_inventoryPath - DBus inventory path.
Rekha Aparnae0d24c02025-09-02 00:15:06 -0500931 * @param[out] o_errCode - To set error code in case of error.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500932 *
933 * @return On success returns the service name present in the system config
934 * JSON, otherwise empty string.
935 *
936 * Note: Caller has to handle in case of empty string received.
937 */
938inline std::string getServiceName(const nlohmann::json& i_sysCfgJsonObj,
Rekha Aparnae0d24c02025-09-02 00:15:06 -0500939 const std::string& l_inventoryPath,
940 uint16_t& o_errCode)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500941{
Rekha Aparnae0d24c02025-09-02 00:15:06 -0500942 if (l_inventoryPath.empty())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500943 {
Rekha Aparnae0d24c02025-09-02 00:15:06 -0500944 o_errCode = error_code::INVALID_INPUT_PARAMETER;
945 return std::string{};
946 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500947
Rekha Aparnae0d24c02025-09-02 00:15:06 -0500948 if (!i_sysCfgJsonObj.contains("frus"))
949 {
950 o_errCode = error_code::INVALID_JSON;
951 return std::string{};
952 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500953
Rekha Aparnae0d24c02025-09-02 00:15:06 -0500954 const nlohmann::json& l_listOfFrus =
955 i_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500956
Rekha Aparnae0d24c02025-09-02 00:15:06 -0500957 for (const auto& l_frus : l_listOfFrus.items())
958 {
959 for (const auto& l_inventoryItem : l_frus.value())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500960 {
Rekha Aparnae0d24c02025-09-02 00:15:06 -0500961 if (l_inventoryPath.compare(l_inventoryItem["inventoryPath"]) ==
962 constants::STR_CMP_SUCCESS)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500963 {
Rekha Aparnae0d24c02025-09-02 00:15:06 -0500964 if (l_inventoryItem.contains("serviceName"))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500965 {
Rekha Aparnae0d24c02025-09-02 00:15:06 -0500966 return l_inventoryItem.value("serviceName", "");
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500967 }
Rekha Aparnae0d24c02025-09-02 00:15:06 -0500968
969 o_errCode = error_code::JSON_MISSING_SERVICE_NAME;
970 return std::string{};
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500971 }
972 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500973 }
Rekha Aparnae0d24c02025-09-02 00:15:06 -0500974
975 o_errCode = error_code::FRU_PATH_NOT_FOUND;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500976 return std::string{};
977}
978
979/**
980 * @brief An API to check if a FRU is tagged as "powerOffOnly"
981 *
982 * Given the system config JSON and VPD FRU path, this API checks if the FRU
983 * VPD can be collected at Chassis Power Off state only.
984 *
985 * @param[in] i_sysCfgJsonObj - System config JSON object.
986 * @param[in] i_vpdFruPath - EEPROM path.
Rekha Aparna52041882025-09-01 20:48:07 -0500987 * @param[out] o_errCode - To set error code for the error.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500988 * @return - True if FRU VPD can be collected at Chassis Power Off state only.
989 * False otherwise
990 */
991inline bool isFruPowerOffOnly(const nlohmann::json& i_sysCfgJsonObj,
Rekha Aparna52041882025-09-01 20:48:07 -0500992 const std::string& i_vpdFruPath,
993 uint16_t& o_errCode)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500994{
995 if (i_vpdFruPath.empty())
996 {
Rekha Aparna52041882025-09-01 20:48:07 -0500997 o_errCode = error_code::INVALID_INPUT_PARAMETER;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500998 return false;
999 }
1000
1001 if (!i_sysCfgJsonObj.contains("frus"))
1002 {
Rekha Aparna52041882025-09-01 20:48:07 -05001003 o_errCode = error_code::INVALID_JSON;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001004 return false;
1005 }
1006
1007 if (!i_sysCfgJsonObj["frus"].contains(i_vpdFruPath))
1008 {
Rekha Aparna52041882025-09-01 20:48:07 -05001009 o_errCode = error_code::FRU_PATH_NOT_FOUND;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001010 return false;
1011 }
1012
1013 return ((i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0))
1014 .contains("powerOffOnly") &&
1015 (i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0)["powerOffOnly"]));
1016}
1017
1018/**
1019 * @brief API which tells if the FRU is replaceable at runtime
1020 *
1021 * @param[in] i_sysCfgJsonObj - System config JSON object.
1022 * @param[in] i_vpdFruPath - EEPROM path.
Rekha Aparnaad0db9e2025-09-01 20:29:18 -05001023 * @param[out] o_errCode - to set error code in case of error.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001024 *
1025 * @return true if FRU is replaceable at runtime. false otherwise.
1026 */
1027inline bool isFruReplaceableAtRuntime(const nlohmann::json& i_sysCfgJsonObj,
Rekha Aparnaad0db9e2025-09-01 20:29:18 -05001028 const std::string& i_vpdFruPath,
1029 uint16_t& o_errCode)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001030{
Rekha Aparnaad0db9e2025-09-01 20:29:18 -05001031 if (i_vpdFruPath.empty())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001032 {
Rekha Aparnaad0db9e2025-09-01 20:29:18 -05001033 o_errCode = error_code::INVALID_INPUT_PARAMETER;
1034 return false;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001035 }
Rekha Aparnaad0db9e2025-09-01 20:29:18 -05001036
1037 if (i_sysCfgJsonObj.empty() || (!i_sysCfgJsonObj.contains("frus")))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001038 {
Rekha Aparnaad0db9e2025-09-01 20:29:18 -05001039 o_errCode = error_code::INVALID_JSON;
1040 return false;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001041 }
1042
Rekha Aparnaad0db9e2025-09-01 20:29:18 -05001043 return (
1044 (i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0))
1045 .contains("replaceableAtRuntime") &&
1046 (i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0)["replaceableAtRuntime"]));
1047
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001048 return false;
1049}
1050
1051/**
1052 * @brief API which tells if the FRU is replaceable at standby
1053 *
1054 * @param[in] i_sysCfgJsonObj - System config JSON object.
1055 * @param[in] i_vpdFruPath - EEPROM path.
Rekha Aparna40845612025-09-01 19:58:56 -05001056 * @param[out] o_errCode - set error code in case of error.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001057 *
1058 * @return true if FRU is replaceable at standby. false otherwise.
1059 */
1060inline bool isFruReplaceableAtStandby(const nlohmann::json& i_sysCfgJsonObj,
Rekha Aparna40845612025-09-01 19:58:56 -05001061 const std::string& i_vpdFruPath,
1062 uint16_t& o_errCode)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001063{
Rekha Aparna40845612025-09-01 19:58:56 -05001064 if (i_vpdFruPath.empty())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001065 {
Rekha Aparna40845612025-09-01 19:58:56 -05001066 o_errCode = error_code::INVALID_INPUT_PARAMETER;
1067 return false;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001068 }
Rekha Aparna40845612025-09-01 19:58:56 -05001069
1070 if (i_sysCfgJsonObj.empty() || (!i_sysCfgJsonObj.contains("frus")))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001071 {
Rekha Aparna40845612025-09-01 19:58:56 -05001072 o_errCode = error_code::INVALID_JSON;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001073 }
1074
Rekha Aparna40845612025-09-01 19:58:56 -05001075 return (
1076 (i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0))
1077 .contains("replaceableAtStandby") &&
1078 (i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0)["replaceableAtStandby"]));
1079
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001080 return false;
1081}
1082
1083/**
1084 * @brief API to get list of FRUs replaceable at standby from JSON.
1085 *
1086 * The API will return a vector of FRUs inventory path which are replaceable at
1087 * standby.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001088 *
1089 * @param[in] i_sysCfgJsonObj - System config JSON object.
Rekha Aparna88d53302025-09-01 18:16:55 -05001090 * @param[out] o_errCode - To set error code in case of error.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001091 *
RekhaAparna017fea9f52025-02-17 04:14:02 -06001092 * @return - On success, list of FRUs replaceable at standby. On failure, empty
1093 * vector.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001094 */
Patrick Williams43fedab2025-02-03 14:28:05 -05001095inline std::vector<std::string> getListOfFrusReplaceableAtStandby(
Rekha Aparna88d53302025-09-01 18:16:55 -05001096 const nlohmann::json& i_sysCfgJsonObj, uint16_t& o_errCode)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001097{
1098 std::vector<std::string> l_frusReplaceableAtStandby;
1099
Rekha Aparna88d53302025-09-01 18:16:55 -05001100 if (!i_sysCfgJsonObj.contains("frus"))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001101 {
Rekha Aparna88d53302025-09-01 18:16:55 -05001102 o_errCode = error_code::INVALID_JSON;
1103 return l_frusReplaceableAtStandby;
1104 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001105
Rekha Aparna88d53302025-09-01 18:16:55 -05001106 const nlohmann::json& l_fruList =
1107 i_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
RekhaAparna017fea9f52025-02-17 04:14:02 -06001108
Rekha Aparna88d53302025-09-01 18:16:55 -05001109 for (const auto& l_fru : l_fruList.items())
1110 {
1111 if (i_sysCfgJsonObj["frus"][l_fru.key()].at(0).value(
1112 "replaceableAtStandby", false))
RekhaAparna017fea9f52025-02-17 04:14:02 -06001113 {
Rekha Aparna88d53302025-09-01 18:16:55 -05001114 const std::string& l_inventoryObjectPath =
1115 i_sysCfgJsonObj["frus"][l_fru.key()].at(0).value(
1116 "inventoryPath", "");
1117
1118 if (!l_inventoryObjectPath.empty())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001119 {
Rekha Aparna88d53302025-09-01 18:16:55 -05001120 l_frusReplaceableAtStandby.emplace_back(l_inventoryObjectPath);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001121 }
1122 }
1123 }
1124
1125 return l_frusReplaceableAtStandby;
1126}
1127
Sunny Srivastava022112b2025-02-19 19:53:29 +05301128/**
1129 * @brief API to select powerVS JSON based on system IM.
1130 *
1131 * The API selects respective JSON based on system IM, parse it and return the
1132 * JSON object. Empty JSON will be returned in case of any error. Caller needs
1133 * to handle empty value.
1134 *
1135 * @param[in] i_imValue - IM value of the system.
Rekha Aparnaadf85262025-09-09 00:41:00 -05001136 * @param[out] o_errCode - to set error code in case of error.
Sunny Srivastava022112b2025-02-19 19:53:29 +05301137 * @return Parsed JSON object, empty JSON otherwise.
1138 */
Rekha Aparnaadf85262025-09-09 00:41:00 -05001139inline nlohmann::json getPowerVsJson(const types::BinaryVector& i_imValue,
1140 uint16_t& o_errCode)
Sunny Srivastava022112b2025-02-19 19:53:29 +05301141{
Rekha Aparnaadf85262025-09-09 00:41:00 -05001142 if (i_imValue.empty() || i_imValue.size() < 4)
Sunny Srivastava022112b2025-02-19 19:53:29 +05301143 {
Rekha Aparnaadf85262025-09-09 00:41:00 -05001144 o_errCode = error_code::INVALID_INPUT_PARAMETER;
Sunny Srivastava022112b2025-02-19 19:53:29 +05301145 return nlohmann::json{};
1146 }
Rekha Aparnaadf85262025-09-09 00:41:00 -05001147
1148 o_errCode = 0;
1149 if ((i_imValue.at(0) == constants::HEX_VALUE_50) &&
1150 (i_imValue.at(1) == constants::HEX_VALUE_00) &&
1151 (i_imValue.at(2) == constants::HEX_VALUE_30))
Sunny Srivastava022112b2025-02-19 19:53:29 +05301152 {
Rekha Aparnaadf85262025-09-09 00:41:00 -05001153 nlohmann::json l_parsedJson = jsonUtility::getParsedJson(
1154 constants::power_vs_50003_json, o_errCode);
1155
1156 if (o_errCode)
1157 {
1158 logging::logMessage(
1159 "Failed to parse JSON file [ " +
1160 std::string(constants::power_vs_50003_json) +
1161 " ], error : " + vpdSpecificUtility::getErrCodeMsg(o_errCode));
1162 }
1163
1164 return l_parsedJson;
Sunny Srivastava022112b2025-02-19 19:53:29 +05301165 }
Rekha Aparnaadf85262025-09-09 00:41:00 -05001166 else if (i_imValue.at(0) == constants::HEX_VALUE_50 &&
1167 (i_imValue.at(1) == constants::HEX_VALUE_00) &&
1168 (i_imValue.at(2) == constants::HEX_VALUE_10))
1169 {
1170 nlohmann::json l_parsedJson = jsonUtility::getParsedJson(
1171 constants::power_vs_50001_json, o_errCode);
1172
1173 if (o_errCode)
1174 {
1175 logging::logMessage(
1176 "Failed to parse JSON file [ " +
1177 std::string(constants::power_vs_50001_json) +
1178 " ], error : " + vpdSpecificUtility::getErrCodeMsg(o_errCode));
1179 }
1180
1181 return l_parsedJson;
1182 }
1183 return nlohmann::json{};
Sunny Srivastava022112b2025-02-19 19:53:29 +05301184}
Souvik Roy495eedd2025-07-02 02:13:43 -05001185
1186/**
1187 * @brief API to get list of FRUs for which "monitorPresence" is true.
1188 *
1189 * @param[in] i_sysCfgJsonObj - System config JSON object.
Rekha Aparna2362bed2025-09-01 13:18:40 -05001190 * @param[out] o_errCode - To set error code in case of error.
Souvik Roy495eedd2025-07-02 02:13:43 -05001191 *
1192 * @return On success, returns list of FRUs for which "monitorPresence" is true,
1193 * empty list on error.
1194 */
1195inline std::vector<types::Path> getFrusWithPresenceMonitoring(
Rekha Aparna2362bed2025-09-01 13:18:40 -05001196 const nlohmann::json& i_sysCfgJsonObj, uint16_t& o_errCode)
Souvik Roy495eedd2025-07-02 02:13:43 -05001197{
1198 std::vector<types::Path> l_frusWithPresenceMonitoring;
Rekha Aparna2362bed2025-09-01 13:18:40 -05001199
1200 if (!i_sysCfgJsonObj.contains("frus"))
Souvik Roy495eedd2025-07-02 02:13:43 -05001201 {
Rekha Aparna2362bed2025-09-01 13:18:40 -05001202 o_errCode = error_code::INVALID_JSON;
1203 return l_frusWithPresenceMonitoring;
1204 }
Souvik Roy495eedd2025-07-02 02:13:43 -05001205
Rekha Aparna2362bed2025-09-01 13:18:40 -05001206 const nlohmann::json& l_listOfFrus =
1207 i_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
Souvik Roy495eedd2025-07-02 02:13:43 -05001208
Rekha Aparna2362bed2025-09-01 13:18:40 -05001209 for (const auto& l_aFru : l_listOfFrus)
1210 {
1211 if (l_aFru.at(0).value("monitorPresence", false))
Souvik Roy495eedd2025-07-02 02:13:43 -05001212 {
Rekha Aparna2362bed2025-09-01 13:18:40 -05001213 l_frusWithPresenceMonitoring.emplace_back(
1214 l_aFru.at(0).value("inventoryPath", ""));
Souvik Roy495eedd2025-07-02 02:13:43 -05001215 }
1216 }
Rekha Aparna2362bed2025-09-01 13:18:40 -05001217
Souvik Roy495eedd2025-07-02 02:13:43 -05001218 return l_frusWithPresenceMonitoring;
1219}
Souvik Roye9120152025-07-02 08:24:38 -05001220
1221/**
1222 * @brief API which tells if the FRU's presence is handled
1223 *
1224 * For a given FRU, this API checks if it's presence is handled by vpd-manager
1225 * by checking the "handlePresence" tag.
1226 *
1227 * @param[in] i_sysCfgJsonObj - System config JSON object.
1228 * @param[in] i_vpdFruPath - EEPROM path.
Rekha Aparnaa1187a52025-09-01 12:42:19 -05001229 * @param[out] o_errCode - To set error code in case of failure.
Souvik Roye9120152025-07-02 08:24:38 -05001230 *
1231 * @return true if FRU presence is handled, false otherwise.
1232 */
1233inline bool isFruPresenceHandled(const nlohmann::json& i_sysCfgJsonObj,
Rekha Aparnaa1187a52025-09-01 12:42:19 -05001234 const std::string& i_vpdFruPath,
1235 uint16_t& o_errCode)
Souvik Roye9120152025-07-02 08:24:38 -05001236{
Rekha Aparnaa1187a52025-09-01 12:42:19 -05001237 if (i_vpdFruPath.empty())
Souvik Roye9120152025-07-02 08:24:38 -05001238 {
Rekha Aparnaa1187a52025-09-01 12:42:19 -05001239 o_errCode = error_code::INVALID_INPUT_PARAMETER;
1240 return false;
Souvik Roye9120152025-07-02 08:24:38 -05001241 }
1242
Rekha Aparnaa1187a52025-09-01 12:42:19 -05001243 if (!i_sysCfgJsonObj.contains("frus"))
1244 {
1245 o_errCode = error_code::INVALID_JSON;
1246 return false;
1247 }
1248
1249 if (!i_sysCfgJsonObj["frus"].contains(i_vpdFruPath))
1250 {
1251 o_errCode = error_code::FRU_PATH_NOT_FOUND;
1252 return false;
1253 }
1254
1255 return i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0).value(
1256 "handlePresence", true);
Souvik Roye9120152025-07-02 08:24:38 -05001257}
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001258} // namespace jsonUtility
1259} // namespace vpd