blob: 93d1415aa813e9f53f0e2e62f190f675fbc40f62 [file] [log] [blame]
Brandon Wymana0f33ce2019-10-17 18:32:29 -05001#include "psu_manager.hpp"
2
3#include "utility.hpp"
4
Brandon Wymanb76ab242020-09-16 18:06:06 -05005#include <fmt/format.h>
6#include <sys/types.h>
7#include <unistd.h>
8
Brandon Wymanecbecbc2021-08-31 22:53:21 +00009#include <regex>
10
Brandon Wymanaed1f752019-11-25 18:10:52 -060011using namespace phosphor::logging;
12
Brandon Wyman63ea78b2020-09-24 16:49:09 -050013namespace phosphor::power::manager
Brandon Wymana0f33ce2019-10-17 18:32:29 -050014{
15
Brandon Wyman510acaa2020-11-05 18:32:04 -060016constexpr auto IBMCFFPSInterface =
17 "xyz.openbmc_project.Configuration.IBMCFFPSConnector";
18constexpr auto i2cBusProp = "I2CBus";
19constexpr auto i2cAddressProp = "I2CAddress";
20constexpr auto psuNameProp = "Name";
B. J. Wyman681b2a32021-04-20 22:31:22 +000021constexpr auto presLineName = "NamedPresenceGpio";
Brandon Wyman510acaa2020-11-05 18:32:04 -060022
Adriana Kobylak9bab9e12021-02-24 15:32:03 -060023constexpr auto supportedConfIntf =
24 "xyz.openbmc_project.Configuration.SupportedConfiguration";
Adriana Kobylak9bab9e12021-02-24 15:32:03 -060025
Brandon Wyman510acaa2020-11-05 18:32:04 -060026PSUManager::PSUManager(sdbusplus::bus::bus& bus, const sdeventplus::Event& e) :
27 bus(bus)
28{
Brandon Wyman510acaa2020-11-05 18:32:04 -060029 // Subscribe to InterfacesAdded before doing a property read, otherwise
30 // the interface could be created after the read attempt but before the
31 // match is created.
32 entityManagerIfacesAddedMatch = std::make_unique<sdbusplus::bus::match_t>(
33 bus,
34 sdbusplus::bus::match::rules::interfacesAdded() +
35 sdbusplus::bus::match::rules::sender(
36 "xyz.openbmc_project.EntityManager"),
37 std::bind(&PSUManager::entityManagerIfaceAdded, this,
38 std::placeholders::_1));
39 getPSUConfiguration();
40 getSystemProperties();
41
42 using namespace sdeventplus;
43 auto interval = std::chrono::milliseconds(1000);
44 timer = std::make_unique<utility::Timer<ClockId::Monotonic>>(
45 e, std::bind(&PSUManager::analyze, this), interval);
46
47 // Subscribe to power state changes
48 powerService = util::getService(POWER_OBJ_PATH, POWER_IFACE, bus);
49 powerOnMatch = std::make_unique<sdbusplus::bus::match_t>(
50 bus,
51 sdbusplus::bus::match::rules::propertiesChanged(POWER_OBJ_PATH,
52 POWER_IFACE),
53 [this](auto& msg) { this->powerStateChanged(msg); });
54
55 initialize();
56}
57
Brandon Wyman510acaa2020-11-05 18:32:04 -060058void PSUManager::getPSUConfiguration()
59{
60 using namespace phosphor::power::util;
61 auto depth = 0;
62 auto objects = getSubTree(bus, "/", IBMCFFPSInterface, depth);
63
64 psus.clear();
65
66 // I should get a map of objects back.
67 // Each object will have a path, a service, and an interface.
68 // The interface should match the one passed into this function.
69 for (const auto& [path, services] : objects)
70 {
71 auto service = services.begin()->first;
72
73 if (path.empty() || service.empty())
74 {
75 continue;
76 }
77
78 // For each object in the array of objects, I want to get properties
79 // from the service, path, and interface.
80 auto properties =
81 getAllProperties(bus, path, IBMCFFPSInterface, service);
82
83 getPSUProperties(properties);
84 }
85
86 if (psus.empty())
87 {
88 // Interface or properties not found. Let the Interfaces Added callback
89 // process the information once the interfaces are added to D-Bus.
90 log<level::INFO>(fmt::format("No power supplies to monitor").c_str());
91 }
92}
93
94void PSUManager::getPSUProperties(util::DbusPropertyMap& properties)
95{
96 // From passed in properties, I want to get: I2CBus, I2CAddress,
97 // and Name. Create a power supply object, using Name to build the inventory
98 // path.
99 const auto basePSUInvPath =
100 "/xyz/openbmc_project/inventory/system/chassis/motherboard/powersupply";
101 uint64_t* i2cbus = nullptr;
102 uint64_t* i2caddr = nullptr;
103 std::string* psuname = nullptr;
B. J. Wyman681b2a32021-04-20 22:31:22 +0000104 std::string* preslineptr = nullptr;
Brandon Wyman510acaa2020-11-05 18:32:04 -0600105
106 for (const auto& property : properties)
107 {
108 try
109 {
110 if (property.first == i2cBusProp)
111 {
112 i2cbus = std::get_if<uint64_t>(&properties[i2cBusProp]);
113 }
114 else if (property.first == i2cAddressProp)
115 {
116 i2caddr = std::get_if<uint64_t>(&properties[i2cAddressProp]);
117 }
118 else if (property.first == psuNameProp)
119 {
120 psuname = std::get_if<std::string>(&properties[psuNameProp]);
121 }
B. J. Wyman681b2a32021-04-20 22:31:22 +0000122 else if (property.first == presLineName)
123 {
124 preslineptr =
125 std::get_if<std::string>(&properties[presLineName]);
126 }
Brandon Wyman510acaa2020-11-05 18:32:04 -0600127 }
128 catch (std::exception& e)
129 {
130 }
131 }
132
133 if ((i2cbus) && (i2caddr) && (psuname) && (!psuname->empty()))
134 {
135 std::string invpath = basePSUInvPath;
136 invpath.push_back(psuname->back());
B. J. Wyman681b2a32021-04-20 22:31:22 +0000137 std::string presline = "";
Brandon Wyman510acaa2020-11-05 18:32:04 -0600138
139 log<level::DEBUG>(fmt::format("Inventory Path: {}", invpath).c_str());
140
B. J. Wyman681b2a32021-04-20 22:31:22 +0000141 if (nullptr != preslineptr)
142 {
143 presline = *preslineptr;
144 }
145
Brandon Wymanecbecbc2021-08-31 22:53:21 +0000146 auto invMatch =
147 std::find_if(psus.begin(), psus.end(), [&invpath](auto& psu) {
148 return psu->getInventoryPath() == invpath;
149 });
150 if (invMatch != psus.end())
151 {
152 // This power supply has the same inventory path as the one with
153 // information just added to D-Bus.
154 // Changes to GPIO line name unlikely, so skip checking.
155 // Changes to the I2C bus and address unlikely, as that would
156 // require corresponding device tree updates.
157 // Return out to avoid duplicate object creation.
158 return;
159 }
160
B. J. Wyman681b2a32021-04-20 22:31:22 +0000161 log<level::DEBUG>(
162 fmt::format("make PowerSupply bus: {} addr: {} presline: {}",
163 *i2cbus, *i2caddr, presline)
164 .c_str());
165 auto psu = std::make_unique<PowerSupply>(bus, invpath, *i2cbus,
166 *i2caddr, presline);
Brandon Wyman510acaa2020-11-05 18:32:04 -0600167 psus.emplace_back(std::move(psu));
168 }
169
170 if (psus.empty())
171 {
172 log<level::INFO>(fmt::format("No power supplies to monitor").c_str());
173 }
174}
175
Adriana Kobylake1074d82021-03-16 20:46:44 +0000176void PSUManager::populateSysProperties(const util::DbusPropertyMap& properties)
177{
178 try
179 {
Adriana Kobylak9ea66a62021-03-24 17:54:14 +0000180 auto propIt = properties.find("SupportedType");
181 if (propIt == properties.end())
182 {
183 return;
184 }
185 const std::string* type = std::get_if<std::string>(&(propIt->second));
186 if ((type == nullptr) || (*type != "PowerSupply"))
187 {
188 return;
189 }
190
Adriana Kobylak9ea66a62021-03-24 17:54:14 +0000191 propIt = properties.find("SupportedModel");
192 if (propIt == properties.end())
193 {
194 return;
195 }
Adriana Kobylakd3a70d92021-06-04 16:24:45 +0000196 const std::string* model = std::get_if<std::string>(&(propIt->second));
197 if (model == nullptr)
Adriana Kobylak9ea66a62021-03-24 17:54:14 +0000198 {
199 return;
200 }
Adriana Kobylak9ea66a62021-03-24 17:54:14 +0000201
Adriana Kobylakd3a70d92021-06-04 16:24:45 +0000202 sys_properties sys;
Adriana Kobylak9ea66a62021-03-24 17:54:14 +0000203 propIt = properties.find("RedundantCount");
Adriana Kobylake1074d82021-03-16 20:46:44 +0000204 if (propIt != properties.end())
205 {
206 const uint64_t* count = std::get_if<uint64_t>(&(propIt->second));
207 if (count != nullptr)
208 {
Adriana Kobylakd3a70d92021-06-04 16:24:45 +0000209 sys.powerSupplyCount = *count;
Adriana Kobylake1074d82021-03-16 20:46:44 +0000210 }
211 }
Adriana Kobylak9ea66a62021-03-24 17:54:14 +0000212 propIt = properties.find("InputVoltage");
213 if (propIt != properties.end())
214 {
Adriana Kobylakd3a70d92021-06-04 16:24:45 +0000215 const std::vector<uint64_t>* voltage =
216 std::get_if<std::vector<uint64_t>>(&(propIt->second));
Adriana Kobylak9ea66a62021-03-24 17:54:14 +0000217 if (voltage != nullptr)
218 {
219 sys.inputVoltage = *voltage;
220 }
221 }
222
Adriana Kobylakd3a70d92021-06-04 16:24:45 +0000223 supportedConfigs.emplace(*model, sys);
Adriana Kobylake1074d82021-03-16 20:46:44 +0000224 }
225 catch (std::exception& e)
226 {
227 }
228}
229
Adriana Kobylak9bab9e12021-02-24 15:32:03 -0600230void PSUManager::getSystemProperties()
231{
Adriana Kobylak9bab9e12021-02-24 15:32:03 -0600232
Adriana Kobylak9bab9e12021-02-24 15:32:03 -0600233 try
234 {
235 util::DbusSubtree subtree =
236 util::getSubTree(bus, INVENTORY_OBJ_PATH, supportedConfIntf, 0);
Adriana Kobylake1074d82021-03-16 20:46:44 +0000237 if (subtree.empty())
Adriana Kobylak9bab9e12021-02-24 15:32:03 -0600238 {
239 throw std::runtime_error("Supported Configuration Not Found");
240 }
Adriana Kobylak9bab9e12021-02-24 15:32:03 -0600241
Adriana Kobylake1074d82021-03-16 20:46:44 +0000242 for (const auto& [objPath, services] : subtree)
243 {
244 std::string service = services.begin()->first;
245 if (objPath.empty() || service.empty())
246 {
247 continue;
Adriana Kobylak9bab9e12021-02-24 15:32:03 -0600248 }
Adriana Kobylake1074d82021-03-16 20:46:44 +0000249 auto properties = util::getAllProperties(
250 bus, objPath, supportedConfIntf, service);
251 populateSysProperties(properties);
Adriana Kobylak9bab9e12021-02-24 15:32:03 -0600252 }
253 }
254 catch (std::exception& e)
255 {
256 // Interface or property not found. Let the Interfaces Added callback
257 // process the information once the interfaces are added to D-Bus.
258 }
259}
260
Brandon Wyman3e429132021-03-18 18:03:14 -0500261void PSUManager::entityManagerIfaceAdded(sdbusplus::message::message& msg)
Adriana Kobylak9bab9e12021-02-24 15:32:03 -0600262{
263 try
264 {
265 sdbusplus::message::object_path objPath;
Adriana Kobylake1074d82021-03-16 20:46:44 +0000266 std::map<std::string, std::map<std::string, util::DbusVariant>>
Adriana Kobylak9bab9e12021-02-24 15:32:03 -0600267 interfaces;
268 msg.read(objPath, interfaces);
269
270 auto itIntf = interfaces.find(supportedConfIntf);
Brandon Wyman510acaa2020-11-05 18:32:04 -0600271 if (itIntf != interfaces.cend())
Adriana Kobylak9bab9e12021-02-24 15:32:03 -0600272 {
Brandon Wyman510acaa2020-11-05 18:32:04 -0600273 populateSysProperties(itIntf->second);
Adriana Kobylak9bab9e12021-02-24 15:32:03 -0600274 }
275
Brandon Wyman510acaa2020-11-05 18:32:04 -0600276 itIntf = interfaces.find(IBMCFFPSInterface);
277 if (itIntf != interfaces.cend())
278 {
279 log<level::INFO>(
280 fmt::format("InterfacesAdded for: {}", IBMCFFPSInterface)
281 .c_str());
282 getPSUProperties(itIntf->second);
283 }
Adriana Kobylak8f16fb52021-03-31 15:50:15 +0000284
285 // Call to validate the psu configuration if the power is on and both
286 // the IBMCFFPSConnector and SupportedConfiguration interfaces have been
287 // processed
288 if (powerOn && !psus.empty() && !supportedConfigs.empty())
289 {
290 validateConfig();
291 }
Adriana Kobylak9bab9e12021-02-24 15:32:03 -0600292 }
293 catch (std::exception& e)
294 {
295 // Ignore, the property may be of a different type than expected.
296 }
297}
298
Brandon Wymana0f33ce2019-10-17 18:32:29 -0500299void PSUManager::powerStateChanged(sdbusplus::message::message& msg)
300{
301 int32_t state = 0;
302 std::string msgSensor;
Patrick Williamsabe49412020-05-13 17:59:47 -0500303 std::map<std::string, std::variant<int32_t>> msgData;
Brandon Wymana0f33ce2019-10-17 18:32:29 -0500304 msg.read(msgSensor, msgData);
305
306 // Check if it was the Present property that changed.
307 auto valPropMap = msgData.find("state");
308 if (valPropMap != msgData.end())
309 {
310 state = std::get<int32_t>(valPropMap->second);
311
312 // Power is on when state=1. Clear faults.
313 if (state)
314 {
315 powerOn = true;
Adriana Kobylak8f16fb52021-03-31 15:50:15 +0000316 validateConfig();
Brandon Wymana0f33ce2019-10-17 18:32:29 -0500317 clearFaults();
318 }
319 else
320 {
321 powerOn = false;
Adriana Kobylak8f16fb52021-03-31 15:50:15 +0000322 runValidateConfig = true;
Brandon Wymana0f33ce2019-10-17 18:32:29 -0500323 }
324 }
325}
326
Brandon Wymanb76ab242020-09-16 18:06:06 -0500327void PSUManager::createError(
328 const std::string& faultName,
329 const std::map<std::string, std::string>& additionalData)
330{
331 using namespace sdbusplus::xyz::openbmc_project;
332 constexpr auto loggingObjectPath = "/xyz/openbmc_project/logging";
333 constexpr auto loggingCreateInterface =
334 "xyz.openbmc_project.Logging.Create";
335
336 try
337 {
338 auto service =
339 util::getService(loggingObjectPath, loggingCreateInterface, bus);
340
341 if (service.empty())
342 {
343 log<level::ERR>("Unable to get logging manager service");
344 return;
345 }
346
347 auto method = bus.new_method_call(service.c_str(), loggingObjectPath,
348 loggingCreateInterface, "Create");
349
350 auto level = Logging::server::Entry::Level::Error;
351 method.append(faultName, level, additionalData);
352
353 auto reply = bus.call(method);
354 }
355 catch (std::exception& e)
356 {
357 log<level::ERR>(
358 fmt::format(
359 "Failed creating event log for fault {} due to error {}",
360 faultName, e.what())
361 .c_str());
362 }
363}
364
Brandon Wyman63ea78b2020-09-24 16:49:09 -0500365void PSUManager::analyze()
366{
367 for (auto& psu : psus)
368 {
369 psu->analyze();
370 }
371
Brandon Wyman3180f4d2020-12-08 17:53:46 -0600372 if (powerOn)
Brandon Wyman63ea78b2020-09-24 16:49:09 -0500373 {
Adriana Kobylakf2ba1462021-06-24 15:16:17 +0000374 std::map<std::string, std::string> additionalData;
375 auto requiredPSUsPresent = hasRequiredPSUs(additionalData);
376
Brandon Wyman3180f4d2020-12-08 17:53:46 -0600377 for (auto& psu : psus)
Brandon Wyman63ea78b2020-09-24 16:49:09 -0500378 {
Brandon Wyman3180f4d2020-12-08 17:53:46 -0600379 additionalData["_PID"] = std::to_string(getpid());
380 // TODO: Fault priorities #918
381 if (!psu->isFaultLogged() && !psu->isPresent())
382 {
Adriana Kobylakf2ba1462021-06-24 15:16:17 +0000383 if (!requiredPSUsPresent)
384 {
385 // Create error for power supply missing.
386 additionalData["CALLOUT_INVENTORY_PATH"] =
387 psu->getInventoryPath();
388 additionalData["CALLOUT_PRIORITY"] = "H";
389 createError(
390 "xyz.openbmc_project.Power.PowerSupply.Error.Missing",
391 additionalData);
392 }
Brandon Wyman3180f4d2020-12-08 17:53:46 -0600393 psu->setFaultLogged();
394 }
395 else if (!psu->isFaultLogged() && psu->isFaulted())
396 {
397 additionalData["STATUS_WORD"] =
398 std::to_string(psu->getStatusWord());
Jay Meyer10d94052020-11-30 14:41:21 -0600399 additionalData["STATUS_MFR"] =
400 std::to_string(psu->getMFRFault());
Brandon Wyman3180f4d2020-12-08 17:53:46 -0600401 // If there are faults being reported, they possibly could be
402 // related to a bug in the firmware version running on the power
403 // supply. Capture that data into the error as well.
404 additionalData["FW_VERSION"] = psu->getFWVersion();
405
406 if ((psu->hasInputFault() || psu->hasVINUVFault()))
407 {
408 /* The power supply location might be needed if the input
409 * fault is due to a problem with the power supply itself.
410 * Include the inventory path with a call out priority of
411 * low.
412 */
413 additionalData["CALLOUT_INVENTORY_PATH"] =
414 psu->getInventoryPath();
415 additionalData["CALLOUT_PRIORITY"] = "L";
416 createError("xyz.openbmc_project.Power.PowerSupply.Error."
417 "InputFault",
418 additionalData);
419 psu->setFaultLogged();
420 }
421 else if (psu->hasMFRFault())
422 {
423 /* This can represent a variety of faults that result in
424 * calling out the power supply for replacement: Output
425 * OverCurrent, Output Under Voltage, and potentially other
426 * faults.
427 *
428 * Also plan on putting specific fault in AdditionalData,
429 * along with register names and register values
430 * (STATUS_WORD, STATUS_MFR, etc.).*/
431
432 additionalData["CALLOUT_INVENTORY_PATH"] =
433 psu->getInventoryPath();
434
435 createError(
436 "xyz.openbmc_project.Power.PowerSupply.Error.Fault",
Brandon Wyman52e54e82020-10-08 14:44:58 -0500437 additionalData);
Brandon Wyman63ea78b2020-09-24 16:49:09 -0500438
Brandon Wyman3180f4d2020-12-08 17:53:46 -0600439 psu->setFaultLogged();
440 }
441 else if (psu->hasCommFault())
442 {
443 /* Attempts to communicate with the power supply have
444 * reached there limit. Create an error. */
445 additionalData["CALLOUT_DEVICE_PATH"] =
446 psu->getDevicePath();
Brandon Wymanb76ab242020-09-16 18:06:06 -0500447
Brandon Wyman3180f4d2020-12-08 17:53:46 -0600448 createError(
449 "xyz.openbmc_project.Power.PowerSupply.Error.CommFault",
450 additionalData);
Brandon Wymanb76ab242020-09-16 18:06:06 -0500451
Brandon Wyman3180f4d2020-12-08 17:53:46 -0600452 psu->setFaultLogged();
453 }
Brandon Wyman4176d6b2020-10-07 17:41:06 -0500454 }
Brandon Wyman63ea78b2020-09-24 16:49:09 -0500455 }
456 }
457}
458
Adriana Kobylak8f16fb52021-03-31 15:50:15 +0000459void PSUManager::validateConfig()
460{
Adriana Kobylak70e7f932021-06-10 18:53:56 +0000461 if (!runValidateConfig || supportedConfigs.empty())
Adriana Kobylak8f16fb52021-03-31 15:50:15 +0000462 {
463 return;
464 }
465
Adriana Kobylak4d9aaf92021-06-30 15:27:42 +0000466 std::map<std::string, std::string> additionalData;
467 auto supported = hasRequiredPSUs(additionalData);
468 if (supported)
469 {
470 runValidateConfig = false;
471 return;
472 }
473
474 // Validation failed, create an error log.
475 // Return without setting the runValidateConfig flag to false because
476 // it may be that an additional supported configuration interface is
477 // added and we need to validate it to see if it matches this system.
478 createError("xyz.openbmc_project.Power.PowerSupply.Error.NotSupported",
479 additionalData);
480}
481
482bool PSUManager::hasRequiredPSUs(
483 std::map<std::string, std::string>& additionalData)
484{
Adriana Kobylak8f16fb52021-03-31 15:50:15 +0000485 // Check that all PSUs have the same model name. Initialize the model
486 // variable with the first PSU name found, then use it as a base to compare
487 // against the rest of the PSUs.
488 std::string model{};
Adriana Kobylak4d9aaf92021-06-30 15:27:42 +0000489 for (const auto& psu : psus)
Adriana Kobylak8f16fb52021-03-31 15:50:15 +0000490 {
Adriana Kobylak4d9aaf92021-06-30 15:27:42 +0000491 auto psuModel = psu->getModelName();
Adriana Kobylak8f16fb52021-03-31 15:50:15 +0000492 if (psuModel.empty())
493 {
494 continue;
495 }
496 if (model.empty())
497 {
498 model = psuModel;
499 continue;
500 }
Adriana Kobylak4d9aaf92021-06-30 15:27:42 +0000501 if (psuModel != model)
Adriana Kobylak8f16fb52021-03-31 15:50:15 +0000502 {
Adriana Kobylak8f16fb52021-03-31 15:50:15 +0000503 additionalData["EXPECTED_MODEL"] = model;
504 additionalData["ACTUAL_MODEL"] = psuModel;
Adriana Kobylak4d9aaf92021-06-30 15:27:42 +0000505 additionalData["CALLOUT_INVENTORY_PATH"] = psu->getInventoryPath();
506 return false;
Adriana Kobylak8f16fb52021-03-31 15:50:15 +0000507 }
508 }
Adriana Kobylak70e7f932021-06-10 18:53:56 +0000509
Adriana Kobylak4d9aaf92021-06-30 15:27:42 +0000510 auto presentCount =
511 std::count_if(psus.begin(), psus.end(),
512 [](const auto& psu) { return psu->isPresent(); });
513
Adriana Kobylak70e7f932021-06-10 18:53:56 +0000514 // Validate the supported configurations. A system may support more than one
Adriana Kobylak4175ffb2021-08-02 14:51:05 +0000515 // power supply model configuration. Since all configurations need to be
516 // checked, the additional data would contain only the information of the
517 // last configuration that did not match.
518 std::map<std::string, std::string> tmpAdditionalData;
Adriana Kobylak70e7f932021-06-10 18:53:56 +0000519 for (const auto& config : supportedConfigs)
520 {
Adriana Kobylak4d9aaf92021-06-30 15:27:42 +0000521 if (config.first != model)
Adriana Kobylak70e7f932021-06-10 18:53:56 +0000522 {
523 continue;
524 }
525 if (presentCount != config.second.powerSupplyCount)
526 {
Adriana Kobylak4175ffb2021-08-02 14:51:05 +0000527 tmpAdditionalData.clear();
528 tmpAdditionalData["EXPECTED_COUNT"] =
Adriana Kobylak70e7f932021-06-10 18:53:56 +0000529 std::to_string(config.second.powerSupplyCount);
Adriana Kobylak4175ffb2021-08-02 14:51:05 +0000530 tmpAdditionalData["ACTUAL_COUNT"] = std::to_string(presentCount);
Adriana Kobylak70e7f932021-06-10 18:53:56 +0000531 continue;
532 }
Adriana Kobylak4175ffb2021-08-02 14:51:05 +0000533
534 bool voltageValidated = true;
535 for (const auto& psu : psus)
536 {
537 if (!psu->isPresent())
538 {
539 // Only present PSUs report a valid input voltage
540 continue;
541 }
542
543 double actualInputVoltage;
544 int inputVoltage;
545 psu->getInputVoltage(actualInputVoltage, inputVoltage);
546
547 if (std::find(config.second.inputVoltage.begin(),
548 config.second.inputVoltage.end(),
549 inputVoltage) == config.second.inputVoltage.end())
550 {
551 tmpAdditionalData.clear();
552 tmpAdditionalData["ACTUAL_VOLTAGE"] =
553 std::to_string(actualInputVoltage);
554 for (const auto& voltage : config.second.inputVoltage)
555 {
556 tmpAdditionalData["EXPECTED_VOLTAGE"] +=
557 std::to_string(voltage) + " ";
558 }
559 tmpAdditionalData["CALLOUT_INVENTORY_PATH"] =
560 psu->getInventoryPath();
561
562 voltageValidated = false;
563 break;
564 }
565 }
566 if (!voltageValidated)
567 {
568 continue;
569 }
570
Adriana Kobylak4d9aaf92021-06-30 15:27:42 +0000571 return true;
Adriana Kobylak70e7f932021-06-10 18:53:56 +0000572 }
Adriana Kobylak70e7f932021-06-10 18:53:56 +0000573
Adriana Kobylak4175ffb2021-08-02 14:51:05 +0000574 additionalData.insert(tmpAdditionalData.begin(), tmpAdditionalData.end());
Adriana Kobylak4d9aaf92021-06-30 15:27:42 +0000575 return false;
Adriana Kobylak8f16fb52021-03-31 15:50:15 +0000576}
577
Brandon Wyman63ea78b2020-09-24 16:49:09 -0500578} // namespace phosphor::power::manager