blob: 5a4c0efecd3cae88d7d92af7dc4b0dc39ae297f1 [file] [log] [blame]
George Liub6151622020-11-23 18:16:18 +08001#include "config.h"
2
Patrick Venture91ac8d32018-11-01 17:03:22 -07003#include "manager.hpp"
4
George Liue9fb5c62021-07-01 14:05:32 +08005#include <phosphor-logging/lg2.hpp>
William A. Kennington III151122a2018-05-15 12:00:32 -07006#include <sdbusplus/exception.hpp>
Vishwanatha Subbanna4fa92482017-03-10 14:39:20 +05307#include <xyz/openbmc_project/Led/Physical/server.hpp>
George Liua6c18f82020-06-22 10:50:04 +08008
9#include <algorithm>
10#include <iostream>
11#include <string>
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +053012namespace phosphor
13{
14namespace led
15{
16
17// Assert -or- De-assert
Vishwanatha Subbannaed490732016-12-20 15:59:29 +053018bool Manager::setGroupState(const std::string& path, bool assert,
Patrick Williams158b2c12022-03-17 05:57:44 -050019 ActionSet& ledsAssert, ActionSet& ledsDeAssert)
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +053020{
21 if (assert)
22 {
23 assertedGroups.insert(&ledMap.at(path));
24 }
25 else
26 {
George Liu7f53a032021-05-04 11:18:21 +080027 if (assertedGroups.contains(&ledMap.at(path)))
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +053028 {
29 assertedGroups.erase(&ledMap.at(path));
30 }
31 }
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +053032
Patrick Williams158b2c12022-03-17 05:57:44 -050033 // This will contain the union of what's already in the asserted ActionSet
34 ActionSet desiredState{};
Patrick Venture91ac8d32018-11-01 17:03:22 -070035 for (const auto& grp : assertedGroups)
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +053036 {
37 desiredState.insert(grp->cbegin(), grp->cend());
38 }
39
Vishwanatha Subbanna4b000d82017-05-03 18:44:16 +053040 // Find difference between Combined and Desired to identify
41 // which LEDs are getting altered
Patrick Williams158b2c12022-03-17 05:57:44 -050042 ActionSet transient{};
Vishwanatha Subbanna4b000d82017-05-03 18:44:16 +053043 std::set_difference(combinedState.begin(), combinedState.end(),
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +053044 desiredState.begin(), desiredState.end(),
Patrick Venture91ac8d32018-11-01 17:03:22 -070045 std::inserter(transient, transient.begin()), ledComp);
46 if (transient.size())
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +053047 {
Vishwanatha Subbanna4b000d82017-05-03 18:44:16 +053048 // Find common LEDs between transient and Desired to know if some LEDs
49 // are changing state and not really getting DeAsserted
Patrick Williams158b2c12022-03-17 05:57:44 -050050 ActionSet ledsTransient{};
Patrick Venture91ac8d32018-11-01 17:03:22 -070051 std::set_intersection(
52 transient.begin(), transient.end(), desiredState.begin(),
53 desiredState.end(),
54 std::inserter(ledsTransient, ledsTransient.begin()), ledLess);
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +053055
Vishwanatha Subbanna4b000d82017-05-03 18:44:16 +053056 // Find difference between above 2 to identify those LEDs which are
57 // really getting DeAsserted
Patrick Venture91ac8d32018-11-01 17:03:22 -070058 std::set_difference(transient.begin(), transient.end(),
59 ledsTransient.begin(), ledsTransient.end(),
Vishwanatha Subbanna447d0c82016-12-19 14:12:42 +053060 std::inserter(ledsDeAssert, ledsDeAssert.begin()),
Vishwanatha Subbanna4b000d82017-05-03 18:44:16 +053061 ledLess);
Vishwanatha Subbanna447d0c82016-12-19 14:12:42 +053062
Vishwanatha Subbanna4b000d82017-05-03 18:44:16 +053063 // Remove the elements from Current that are being DeAsserted.
Alexander Hansenfe476e12024-07-23 15:45:22 +020064 // Power off LEDs that are to be really DeAsserted
65 for (auto& it : ledsDeAssert)
Vishwanatha Subbanna4b000d82017-05-03 18:44:16 +053066 {
Alexander Hansenfe476e12024-07-23 15:45:22 +020067 // Update LEDs in "physically asserted" set by removing those
68 // LEDs which are De-Asserted
69 auto found = currentState.find(it);
70 if (found != currentState.end())
Vishwanatha Subbanna4b000d82017-05-03 18:44:16 +053071 {
Alexander Hansenfe476e12024-07-23 15:45:22 +020072 currentState.erase(found);
Vishwanatha Subbanna4b000d82017-05-03 18:44:16 +053073 }
74 }
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +053075 }
76
Vishwanatha Subbanna4b000d82017-05-03 18:44:16 +053077 // Now LEDs that are to be Asserted. These could either be fresh asserts
78 // -or- change between [On]<-->[Blink]
Patrick Williams158b2c12022-03-17 05:57:44 -050079 ActionSet temp{};
Vishwanatha Subbanna4b000d82017-05-03 18:44:16 +053080 std::unique_copy(desiredState.begin(), desiredState.end(),
Patrick Venture91ac8d32018-11-01 17:03:22 -070081 std::inserter(temp, temp.begin()), ledEqual);
82 if (temp.size())
Vishwanatha Subbanna4b000d82017-05-03 18:44:16 +053083 {
84 // Find difference between [desired to be Asserted] and those LEDs
85 // that are physically asserted currently.
Patrick Venture91ac8d32018-11-01 17:03:22 -070086 std::set_difference(
87 temp.begin(), temp.end(), currentState.begin(), currentState.end(),
88 std::inserter(ledsAssert, ledsAssert.begin()), ledComp);
Vishwanatha Subbanna4b000d82017-05-03 18:44:16 +053089 }
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +053090
Vishwanatha Subbanna4b000d82017-05-03 18:44:16 +053091 // Update the current actual and desired(the virtual actual)
92 currentState = std::move(temp);
93 combinedState = std::move(desiredState);
Vishwanatha Subbannaed490732016-12-20 15:59:29 +053094
95 // If we survive, then set the state accordingly.
96 return assert;
97}
98
George Liub6151622020-11-23 18:16:18 +080099void Manager::setLampTestCallBack(
Patrick Williams158b2c12022-03-17 05:57:44 -0500100 std::function<bool(ActionSet& ledsAssert, ActionSet& ledsDeAssert)>
101 callBack)
George Liub6151622020-11-23 18:16:18 +0800102{
103 lampTestCallBack = callBack;
104}
105
Vishwanatha Subbannaed490732016-12-20 15:59:29 +0530106/** @brief Run through the map and apply action on the LEDs */
Patrick Williams158b2c12022-03-17 05:57:44 -0500107void Manager::driveLEDs(ActionSet& ledsAssert, ActionSet& ledsDeAssert)
Vishwanatha Subbannaed490732016-12-20 15:59:29 +0530108{
George Liub6151622020-11-23 18:16:18 +0800109#ifdef USE_LAMP_TEST
110 // Use the lampTestCallBack method and trigger the callback method in the
111 // lamp test(processLEDUpdates), in this way, all lamp test operations
112 // are performed in the lamp test class.
113 if (lampTestCallBack(ledsAssert, ledsDeAssert))
114 {
115 return;
116 }
117#endif
Potin Laif1ed4792023-07-13 18:45:14 +0800118 ActionSet newReqChangedLeds;
119 std::vector<std::pair<ActionSet&, ActionSet&>> actionsVec = {
120 {reqLedsAssert, ledsAssert}, {reqLedsDeAssert, ledsDeAssert}};
121
122 timer.setEnabled(false);
123 std::set_union(ledsAssert.begin(), ledsAssert.end(), ledsDeAssert.begin(),
124 ledsDeAssert.end(),
125 std::inserter(newReqChangedLeds, newReqChangedLeds.begin()),
126 ledLess);
127
128 // prepare reqLedsAssert & reqLedsDeAssert
129 for (auto pair : actionsVec)
Vishwanatha Subbannaed490732016-12-20 15:59:29 +0530130 {
Potin Laif1ed4792023-07-13 18:45:14 +0800131 ActionSet tmpSet;
132
133 // Discard current required LED actions, if these LEDs have new actions
134 // in newReqChangedLeds.
135 std::set_difference(pair.first.begin(), pair.first.end(),
136 newReqChangedLeds.begin(), newReqChangedLeds.end(),
137 std::inserter(tmpSet, tmpSet.begin()), ledLess);
138
139 // Union the remaining LED actions with new LED actions.
140 pair.first.clear();
141 std::set_union(tmpSet.begin(), tmpSet.end(), pair.second.begin(),
142 pair.second.end(),
143 std::inserter(pair.first, pair.first.begin()), ledLess);
Vishwanatha Subbannaed490732016-12-20 15:59:29 +0530144 }
145
Potin Laif1ed4792023-07-13 18:45:14 +0800146 driveLedsHandler();
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +0530147 return;
148}
149
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530150// Calls into driving physical LED post choosing the action
Potin Laif1ed4792023-07-13 18:45:14 +0800151int Manager::drivePhysicalLED(const std::string& objPath, Layout::Action action,
152 uint8_t dutyOn, const uint16_t period)
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530153{
George Liu1c737af2020-10-16 09:07:02 +0800154 try
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530155 {
George Liu1c737af2020-10-16 09:07:02 +0800156 // If Blink, set its property
157 if (action == Layout::Action::Blink)
158 {
159 PropertyValue dutyOnValue{dutyOn};
160 PropertyValue periodValue{period};
161
George Liu1f0b7152023-07-18 09:24:34 +0800162 dBusHandler.setProperty(objPath, phyLedIntf, "DutyOn", dutyOnValue);
163 dBusHandler.setProperty(objPath, phyLedIntf, "Period", periodValue);
George Liu1c737af2020-10-16 09:07:02 +0800164 }
165
166 PropertyValue actionValue{getPhysicalAction(action)};
George Liu1f0b7152023-07-18 09:24:34 +0800167 dBusHandler.setProperty(objPath, phyLedIntf, "State", actionValue);
George Liu1c737af2020-10-16 09:07:02 +0800168 }
George Liu829c0b32023-07-18 10:00:47 +0800169 catch (const sdbusplus::exception_t& e)
George Liu1c737af2020-10-16 09:07:02 +0800170 {
George Liue9fb5c62021-07-01 14:05:32 +0800171 lg2::error(
172 "Error setting property for physical LED, ERROR = {ERROR}, OBJECT_PATH = {PATH}",
173 "ERROR", e, "PATH", objPath);
Potin Laif1ed4792023-07-13 18:45:14 +0800174 return -1;
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530175 }
Vishwanatha Subbannadcc3f382017-03-24 20:15:02 +0530176
Potin Laif1ed4792023-07-13 18:45:14 +0800177 return 0;
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530178}
179
180/** @brief Returns action string based on enum */
Vishwanatha Subbanna4fa92482017-03-10 14:39:20 +0530181std::string Manager::getPhysicalAction(Layout::Action action)
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530182{
Vishwanatha Subbanna4fa92482017-03-10 14:39:20 +0530183 namespace server = sdbusplus::xyz::openbmc_project::Led::server;
184
185 // TODO: openbmc/phosphor-led-manager#5
186 // Somehow need to use the generated Action enum than giving one
187 // in ledlayout.
Patrick Venture91ac8d32018-11-01 17:03:22 -0700188 if (action == Layout::Action::On)
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530189 {
Vishwanatha Subbanna4fa92482017-03-10 14:39:20 +0530190 return server::convertForMessage(server::Physical::Action::On);
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530191 }
Patrick Venture91ac8d32018-11-01 17:03:22 -0700192 else if (action == Layout::Action::Blink)
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530193 {
Vishwanatha Subbanna4fa92482017-03-10 14:39:20 +0530194 return server::convertForMessage(server::Physical::Action::Blink);
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530195 }
196 else
197 {
Vishwanatha Subbanna4fa92482017-03-10 14:39:20 +0530198 return server::convertForMessage(server::Physical::Action::Off);
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530199 }
200}
201
Potin Laif1ed4792023-07-13 18:45:14 +0800202void Manager::driveLedsHandler(void)
203{
204 ActionSet failedLedsAssert;
205 ActionSet failedLedsDeAssert;
206
207 // This order of LED operation is important.
Alexander Hansenfe476e12024-07-23 15:45:22 +0200208 for (const auto& it : reqLedsDeAssert)
Potin Laif1ed4792023-07-13 18:45:14 +0800209 {
Alexander Hansenfe476e12024-07-23 15:45:22 +0200210 std::string objPath = std::string(phyLedPath) + it.name;
211 lg2::debug("De-Asserting LED, NAME = {NAME}, ACTION = {ACTION}", "NAME",
212 it.name, "ACTION", it.action);
213 if (drivePhysicalLED(objPath, Layout::Action::Off, it.dutyOn,
214 it.period))
Potin Laif1ed4792023-07-13 18:45:14 +0800215 {
Alexander Hansenfe476e12024-07-23 15:45:22 +0200216 failedLedsDeAssert.insert(it);
Potin Laif1ed4792023-07-13 18:45:14 +0800217 }
218 }
219
Alexander Hansenfe476e12024-07-23 15:45:22 +0200220 for (const auto& it : reqLedsAssert)
Potin Laif1ed4792023-07-13 18:45:14 +0800221 {
Alexander Hansenfe476e12024-07-23 15:45:22 +0200222 std::string objPath = std::string(phyLedPath) + it.name;
223 lg2::debug("Asserting LED, NAME = {NAME}, ACTION = {ACTION}", "NAME",
224 it.name, "ACTION", it.action);
225 if (drivePhysicalLED(objPath, it.action, it.dutyOn, it.period))
Potin Laif1ed4792023-07-13 18:45:14 +0800226 {
Alexander Hansenfe476e12024-07-23 15:45:22 +0200227 failedLedsAssert.insert(it);
Potin Laif1ed4792023-07-13 18:45:14 +0800228 }
229 }
230
231 reqLedsAssert = failedLedsAssert;
232 reqLedsDeAssert = failedLedsDeAssert;
233
234 if (reqLedsDeAssert.empty() && reqLedsAssert.empty())
235 {
236 timer.setEnabled(false);
237 }
238 else
239 {
240 timer.restartOnce(std::chrono::seconds(1));
241 }
242
243 return;
244}
245
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +0530246} // namespace led
247} // namespace phosphor