blob: 18d257bd3e4e5c257521d7324e548a7548a09ea2 [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
Alexander Hansena6f9a412024-07-24 12:27:42 +020017// apply the led action to the map
18static void applyGroupAction(std::map<LedName, Layout::LedAction>& newState,
19 Layout::LedAction action)
20{
21 if (!newState.contains(action.name))
22 {
23 newState[action.name] = action;
24 return;
25 }
26
27 auto currentAction = newState[action.name];
28
29 if (currentAction.action == action.priority)
30 {
31 // if the current action is already the priority action,
32 // we cannot override it
33 return;
34 }
35
36 newState[action.name] = action;
37}
38
39// create the resulting new map from all currently asserted groups
Alexander Hansen7ba70c82024-07-23 13:46:25 +020040static auto getNewMapWithGroupPriorities(
41 std::set<const Layout::GroupLayout*, Layout::CompareGroupLayout> sorted)
Alexander Hansena6f9a412024-07-24 12:27:42 +020042 -> std::map<LedName, Layout::LedAction>
43{
44 std::map<LedName, Layout::LedAction> newState;
45
46 // update the new map with the desired state
Alexander Hansen7ba70c82024-07-23 13:46:25 +020047 for (const auto it : sorted)
Alexander Hansena6f9a412024-07-24 12:27:42 +020048 {
49 // apply all led actions of that group to the map
Alexander Hansen7ba70c82024-07-23 13:46:25 +020050 for (Layout::LedAction action : it->actionSet)
51 {
52 newState[action.name] = action;
53 }
54 }
55 return newState;
56}
57
58static std::map<LedName, Layout::LedAction> getNewMapWithLEDPriorities(
59 std::set<const Layout::GroupLayout*> assertedGroups)
60{
61 std::map<LedName, Layout::LedAction> newState;
62 // update the new map with the desired state
63 for (const Layout::GroupLayout* it : assertedGroups)
64 {
65 // apply all led actions of that group to the map
66 for (Layout::LedAction action : it->actionSet)
Alexander Hansena6f9a412024-07-24 12:27:42 +020067 {
68 applyGroupAction(newState, action);
69 }
70 }
71 return newState;
72}
73
Alexander Hansen7ba70c82024-07-23 13:46:25 +020074// create the resulting new map from all currently asserted groups
75std::map<LedName, Layout::LedAction>
76 Manager::getNewMap(std::set<const Layout::GroupLayout*> assertedGroups)
77{
78 std::map<LedName, Layout::LedAction> newState;
79
80 std::set<const Layout::GroupLayout*, Layout::CompareGroupLayout> sorted;
81
82 bool groupPriorities = false;
83
84 for (const Layout::GroupLayout* it : assertedGroups)
85 {
86 sorted.insert(it);
87
88 if (it->priority != 0)
89 {
90 groupPriorities = true;
91 }
92 }
93
94 if (groupPriorities)
95 {
96 newState = getNewMapWithGroupPriorities(sorted);
97 }
98 else
99 {
100 newState = getNewMapWithLEDPriorities(assertedGroups);
101 }
102
103 return newState;
104}
105
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +0530106// Assert -or- De-assert
Vishwanatha Subbannaed490732016-12-20 15:59:29 +0530107bool Manager::setGroupState(const std::string& path, bool assert,
Patrick Williams158b2c12022-03-17 05:57:44 -0500108 ActionSet& ledsAssert, ActionSet& ledsDeAssert)
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +0530109{
110 if (assert)
111 {
112 assertedGroups.insert(&ledMap.at(path));
113 }
114 else
115 {
George Liu7f53a032021-05-04 11:18:21 +0800116 if (assertedGroups.contains(&ledMap.at(path)))
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +0530117 {
118 assertedGroups.erase(&ledMap.at(path));
119 }
120 }
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +0530121
Alexander Hansena6f9a412024-07-24 12:27:42 +0200122 // create the new map from the asserted groups
123 auto newState = getNewMap(assertedGroups);
124
125 // the ledsAssert are those that are in the new map and change state
126 // + those in the new map and not in the old map
127 for (const auto& [name, action] : newState)
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +0530128 {
Alexander Hansena6f9a412024-07-24 12:27:42 +0200129 if (ledStateMap.contains(name))
130 {
131 // check if the led action has changed
132 auto& currentAction = ledStateMap[name];
133
134 if (currentAction.action == action.action)
135 continue;
136 }
137
138 ledsAssert.insert(action);
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +0530139 }
140
Alexander Hansena6f9a412024-07-24 12:27:42 +0200141 // the ledsDeAssert are those in the old map but not in the new map
142 for (const auto& [name, action] : ledStateMap)
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +0530143 {
Alexander Hansena6f9a412024-07-24 12:27:42 +0200144 if (!newState.contains(name))
Vishwanatha Subbanna4b000d82017-05-03 18:44:16 +0530145 {
Alexander Hansena6f9a412024-07-24 12:27:42 +0200146 ledsDeAssert.insert(action);
Vishwanatha Subbanna4b000d82017-05-03 18:44:16 +0530147 }
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +0530148 }
149
Alexander Hansena6f9a412024-07-24 12:27:42 +0200150 ledStateMap = newState;
Vishwanatha Subbannaed490732016-12-20 15:59:29 +0530151
152 // If we survive, then set the state accordingly.
153 return assert;
154}
155
George Liub6151622020-11-23 18:16:18 +0800156void Manager::setLampTestCallBack(
Patrick Williams158b2c12022-03-17 05:57:44 -0500157 std::function<bool(ActionSet& ledsAssert, ActionSet& ledsDeAssert)>
158 callBack)
George Liub6151622020-11-23 18:16:18 +0800159{
160 lampTestCallBack = callBack;
161}
162
Vishwanatha Subbannaed490732016-12-20 15:59:29 +0530163/** @brief Run through the map and apply action on the LEDs */
Patrick Williams158b2c12022-03-17 05:57:44 -0500164void Manager::driveLEDs(ActionSet& ledsAssert, ActionSet& ledsDeAssert)
Vishwanatha Subbannaed490732016-12-20 15:59:29 +0530165{
George Liub6151622020-11-23 18:16:18 +0800166#ifdef USE_LAMP_TEST
167 // Use the lampTestCallBack method and trigger the callback method in the
168 // lamp test(processLEDUpdates), in this way, all lamp test operations
169 // are performed in the lamp test class.
170 if (lampTestCallBack(ledsAssert, ledsDeAssert))
171 {
172 return;
173 }
174#endif
Potin Laif1ed4792023-07-13 18:45:14 +0800175 ActionSet newReqChangedLeds;
176 std::vector<std::pair<ActionSet&, ActionSet&>> actionsVec = {
177 {reqLedsAssert, ledsAssert}, {reqLedsDeAssert, ledsDeAssert}};
178
179 timer.setEnabled(false);
180 std::set_union(ledsAssert.begin(), ledsAssert.end(), ledsDeAssert.begin(),
181 ledsDeAssert.end(),
182 std::inserter(newReqChangedLeds, newReqChangedLeds.begin()),
183 ledLess);
184
185 // prepare reqLedsAssert & reqLedsDeAssert
186 for (auto pair : actionsVec)
Vishwanatha Subbannaed490732016-12-20 15:59:29 +0530187 {
Potin Laif1ed4792023-07-13 18:45:14 +0800188 ActionSet tmpSet;
189
190 // Discard current required LED actions, if these LEDs have new actions
191 // in newReqChangedLeds.
192 std::set_difference(pair.first.begin(), pair.first.end(),
193 newReqChangedLeds.begin(), newReqChangedLeds.end(),
194 std::inserter(tmpSet, tmpSet.begin()), ledLess);
195
196 // Union the remaining LED actions with new LED actions.
197 pair.first.clear();
198 std::set_union(tmpSet.begin(), tmpSet.end(), pair.second.begin(),
199 pair.second.end(),
200 std::inserter(pair.first, pair.first.begin()), ledLess);
Vishwanatha Subbannaed490732016-12-20 15:59:29 +0530201 }
202
Potin Laif1ed4792023-07-13 18:45:14 +0800203 driveLedsHandler();
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +0530204 return;
205}
206
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530207// Calls into driving physical LED post choosing the action
Potin Laif1ed4792023-07-13 18:45:14 +0800208int Manager::drivePhysicalLED(const std::string& objPath, Layout::Action action,
209 uint8_t dutyOn, const uint16_t period)
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530210{
George Liu1c737af2020-10-16 09:07:02 +0800211 try
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530212 {
George Liu1c737af2020-10-16 09:07:02 +0800213 // If Blink, set its property
214 if (action == Layout::Action::Blink)
215 {
216 PropertyValue dutyOnValue{dutyOn};
217 PropertyValue periodValue{period};
218
George Liu1f0b7152023-07-18 09:24:34 +0800219 dBusHandler.setProperty(objPath, phyLedIntf, "DutyOn", dutyOnValue);
220 dBusHandler.setProperty(objPath, phyLedIntf, "Period", periodValue);
George Liu1c737af2020-10-16 09:07:02 +0800221 }
222
223 PropertyValue actionValue{getPhysicalAction(action)};
George Liu1f0b7152023-07-18 09:24:34 +0800224 dBusHandler.setProperty(objPath, phyLedIntf, "State", actionValue);
George Liu1c737af2020-10-16 09:07:02 +0800225 }
George Liu829c0b32023-07-18 10:00:47 +0800226 catch (const sdbusplus::exception_t& e)
George Liu1c737af2020-10-16 09:07:02 +0800227 {
George Liue9fb5c62021-07-01 14:05:32 +0800228 lg2::error(
229 "Error setting property for physical LED, ERROR = {ERROR}, OBJECT_PATH = {PATH}",
230 "ERROR", e, "PATH", objPath);
Potin Laif1ed4792023-07-13 18:45:14 +0800231 return -1;
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530232 }
Vishwanatha Subbannadcc3f382017-03-24 20:15:02 +0530233
Potin Laif1ed4792023-07-13 18:45:14 +0800234 return 0;
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530235}
236
237/** @brief Returns action string based on enum */
Vishwanatha Subbanna4fa92482017-03-10 14:39:20 +0530238std::string Manager::getPhysicalAction(Layout::Action action)
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530239{
Vishwanatha Subbanna4fa92482017-03-10 14:39:20 +0530240 namespace server = sdbusplus::xyz::openbmc_project::Led::server;
241
242 // TODO: openbmc/phosphor-led-manager#5
243 // Somehow need to use the generated Action enum than giving one
244 // in ledlayout.
Patrick Venture91ac8d32018-11-01 17:03:22 -0700245 if (action == Layout::Action::On)
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530246 {
Vishwanatha Subbanna4fa92482017-03-10 14:39:20 +0530247 return server::convertForMessage(server::Physical::Action::On);
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530248 }
Patrick Venture91ac8d32018-11-01 17:03:22 -0700249 else if (action == Layout::Action::Blink)
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530250 {
Vishwanatha Subbanna4fa92482017-03-10 14:39:20 +0530251 return server::convertForMessage(server::Physical::Action::Blink);
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530252 }
253 else
254 {
Vishwanatha Subbanna4fa92482017-03-10 14:39:20 +0530255 return server::convertForMessage(server::Physical::Action::Off);
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530256 }
257}
258
Potin Laif1ed4792023-07-13 18:45:14 +0800259void Manager::driveLedsHandler(void)
260{
261 ActionSet failedLedsAssert;
262 ActionSet failedLedsDeAssert;
263
264 // This order of LED operation is important.
Alexander Hansenfe476e12024-07-23 15:45:22 +0200265 for (const auto& it : reqLedsDeAssert)
Potin Laif1ed4792023-07-13 18:45:14 +0800266 {
Alexander Hansenfe476e12024-07-23 15:45:22 +0200267 std::string objPath = std::string(phyLedPath) + it.name;
268 lg2::debug("De-Asserting LED, NAME = {NAME}, ACTION = {ACTION}", "NAME",
269 it.name, "ACTION", it.action);
270 if (drivePhysicalLED(objPath, Layout::Action::Off, it.dutyOn,
271 it.period))
Potin Laif1ed4792023-07-13 18:45:14 +0800272 {
Alexander Hansenfe476e12024-07-23 15:45:22 +0200273 failedLedsDeAssert.insert(it);
Potin Laif1ed4792023-07-13 18:45:14 +0800274 }
275 }
276
Alexander Hansenfe476e12024-07-23 15:45:22 +0200277 for (const auto& it : reqLedsAssert)
Potin Laif1ed4792023-07-13 18:45:14 +0800278 {
Alexander Hansenfe476e12024-07-23 15:45:22 +0200279 std::string objPath = std::string(phyLedPath) + it.name;
280 lg2::debug("Asserting LED, NAME = {NAME}, ACTION = {ACTION}", "NAME",
281 it.name, "ACTION", it.action);
282 if (drivePhysicalLED(objPath, it.action, it.dutyOn, it.period))
Potin Laif1ed4792023-07-13 18:45:14 +0800283 {
Alexander Hansenfe476e12024-07-23 15:45:22 +0200284 failedLedsAssert.insert(it);
Potin Laif1ed4792023-07-13 18:45:14 +0800285 }
286 }
287
288 reqLedsAssert = failedLedsAssert;
289 reqLedsDeAssert = failedLedsDeAssert;
290
291 if (reqLedsDeAssert.empty() && reqLedsAssert.empty())
292 {
293 timer.setEnabled(false);
294 }
295 else
296 {
297 timer.restartOnce(std::chrono::seconds(1));
298 }
299
300 return;
301}
302
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +0530303} // namespace led
304} // namespace phosphor