blob: 7c7d730210189dc609f6cf463076b1ad07342ddc [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
Alexander Hansen55badf72024-07-24 14:35:13 +020029 const bool hasPriority = currentAction.priority.has_value();
30
31 if (hasPriority && currentAction.action == action.priority)
Alexander Hansena6f9a412024-07-24 12:27:42 +020032 {
33 // if the current action is already the priority action,
34 // we cannot override it
35 return;
36 }
37
38 newState[action.name] = action;
39}
40
41// create the resulting new map from all currently asserted groups
Alexander Hansen7ba70c82024-07-23 13:46:25 +020042static auto getNewMapWithGroupPriorities(
43 std::set<const Layout::GroupLayout*, Layout::CompareGroupLayout> sorted)
Alexander Hansena6f9a412024-07-24 12:27:42 +020044 -> std::map<LedName, Layout::LedAction>
45{
46 std::map<LedName, Layout::LedAction> newState;
47
48 // update the new map with the desired state
Alexander Hansen7ba70c82024-07-23 13:46:25 +020049 for (const auto it : sorted)
Alexander Hansena6f9a412024-07-24 12:27:42 +020050 {
51 // apply all led actions of that group to the map
George Liu112821c2024-08-22 19:00:24 +080052 for (const Layout::LedAction& action : it->actionSet)
Alexander Hansen7ba70c82024-07-23 13:46:25 +020053 {
54 newState[action.name] = action;
55 }
56 }
57 return newState;
58}
59
60static std::map<LedName, Layout::LedAction> getNewMapWithLEDPriorities(
61 std::set<const Layout::GroupLayout*> assertedGroups)
62{
63 std::map<LedName, Layout::LedAction> newState;
64 // update the new map with the desired state
65 for (const Layout::GroupLayout* it : assertedGroups)
66 {
67 // apply all led actions of that group to the map
George Liu112821c2024-08-22 19:00:24 +080068 for (const Layout::LedAction& action : it->actionSet)
Alexander Hansena6f9a412024-07-24 12:27:42 +020069 {
70 applyGroupAction(newState, action);
71 }
72 }
73 return newState;
74}
75
Alexander Hansen7ba70c82024-07-23 13:46:25 +020076// create the resulting new map from all currently asserted groups
77std::map<LedName, Layout::LedAction>
78 Manager::getNewMap(std::set<const Layout::GroupLayout*> assertedGroups)
79{
80 std::map<LedName, Layout::LedAction> newState;
81
82 std::set<const Layout::GroupLayout*, Layout::CompareGroupLayout> sorted;
83
84 bool groupPriorities = false;
85
86 for (const Layout::GroupLayout* it : assertedGroups)
87 {
88 sorted.insert(it);
89
90 if (it->priority != 0)
91 {
92 groupPriorities = true;
93 }
94 }
95
96 if (groupPriorities)
97 {
98 newState = getNewMapWithGroupPriorities(sorted);
99 }
100 else
101 {
102 newState = getNewMapWithLEDPriorities(assertedGroups);
103 }
104
105 return newState;
106}
107
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +0530108// Assert -or- De-assert
Vishwanatha Subbannaed490732016-12-20 15:59:29 +0530109bool Manager::setGroupState(const std::string& path, bool assert,
Patrick Williams158b2c12022-03-17 05:57:44 -0500110 ActionSet& ledsAssert, ActionSet& ledsDeAssert)
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +0530111{
112 if (assert)
113 {
114 assertedGroups.insert(&ledMap.at(path));
115 }
116 else
117 {
George Liu7f53a032021-05-04 11:18:21 +0800118 if (assertedGroups.contains(&ledMap.at(path)))
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +0530119 {
120 assertedGroups.erase(&ledMap.at(path));
121 }
122 }
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +0530123
Alexander Hansena6f9a412024-07-24 12:27:42 +0200124 // create the new map from the asserted groups
125 auto newState = getNewMap(assertedGroups);
126
127 // the ledsAssert are those that are in the new map and change state
128 // + those in the new map and not in the old map
129 for (const auto& [name, action] : newState)
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +0530130 {
Alexander Hansena6f9a412024-07-24 12:27:42 +0200131 if (ledStateMap.contains(name))
132 {
133 // check if the led action has changed
134 auto& currentAction = ledStateMap[name];
135
136 if (currentAction.action == action.action)
137 continue;
138 }
139
140 ledsAssert.insert(action);
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +0530141 }
142
Alexander Hansena6f9a412024-07-24 12:27:42 +0200143 // the ledsDeAssert are those in the old map but not in the new map
144 for (const auto& [name, action] : ledStateMap)
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +0530145 {
Alexander Hansena6f9a412024-07-24 12:27:42 +0200146 if (!newState.contains(name))
Vishwanatha Subbanna4b000d82017-05-03 18:44:16 +0530147 {
Alexander Hansena6f9a412024-07-24 12:27:42 +0200148 ledsDeAssert.insert(action);
Vishwanatha Subbanna4b000d82017-05-03 18:44:16 +0530149 }
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +0530150 }
151
Alexander Hansena6f9a412024-07-24 12:27:42 +0200152 ledStateMap = newState;
Vishwanatha Subbannaed490732016-12-20 15:59:29 +0530153
154 // If we survive, then set the state accordingly.
155 return assert;
156}
157
George Liub6151622020-11-23 18:16:18 +0800158void Manager::setLampTestCallBack(
Patrick Williams158b2c12022-03-17 05:57:44 -0500159 std::function<bool(ActionSet& ledsAssert, ActionSet& ledsDeAssert)>
160 callBack)
George Liub6151622020-11-23 18:16:18 +0800161{
162 lampTestCallBack = callBack;
163}
164
Vishwanatha Subbannaed490732016-12-20 15:59:29 +0530165/** @brief Run through the map and apply action on the LEDs */
Patrick Williams158b2c12022-03-17 05:57:44 -0500166void Manager::driveLEDs(ActionSet& ledsAssert, ActionSet& ledsDeAssert)
Vishwanatha Subbannaed490732016-12-20 15:59:29 +0530167{
George Liub6151622020-11-23 18:16:18 +0800168#ifdef USE_LAMP_TEST
169 // Use the lampTestCallBack method and trigger the callback method in the
170 // lamp test(processLEDUpdates), in this way, all lamp test operations
171 // are performed in the lamp test class.
172 if (lampTestCallBack(ledsAssert, ledsDeAssert))
173 {
174 return;
175 }
176#endif
Potin Laif1ed4792023-07-13 18:45:14 +0800177 ActionSet newReqChangedLeds;
178 std::vector<std::pair<ActionSet&, ActionSet&>> actionsVec = {
179 {reqLedsAssert, ledsAssert}, {reqLedsDeAssert, ledsDeAssert}};
180
181 timer.setEnabled(false);
182 std::set_union(ledsAssert.begin(), ledsAssert.end(), ledsDeAssert.begin(),
183 ledsDeAssert.end(),
184 std::inserter(newReqChangedLeds, newReqChangedLeds.begin()),
185 ledLess);
186
187 // prepare reqLedsAssert & reqLedsDeAssert
188 for (auto pair : actionsVec)
Vishwanatha Subbannaed490732016-12-20 15:59:29 +0530189 {
Potin Laif1ed4792023-07-13 18:45:14 +0800190 ActionSet tmpSet;
191
192 // Discard current required LED actions, if these LEDs have new actions
193 // in newReqChangedLeds.
194 std::set_difference(pair.first.begin(), pair.first.end(),
195 newReqChangedLeds.begin(), newReqChangedLeds.end(),
196 std::inserter(tmpSet, tmpSet.begin()), ledLess);
197
198 // Union the remaining LED actions with new LED actions.
199 pair.first.clear();
200 std::set_union(tmpSet.begin(), tmpSet.end(), pair.second.begin(),
201 pair.second.end(),
202 std::inserter(pair.first, pair.first.begin()), ledLess);
Vishwanatha Subbannaed490732016-12-20 15:59:29 +0530203 }
204
Potin Laif1ed4792023-07-13 18:45:14 +0800205 driveLedsHandler();
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +0530206 return;
207}
208
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530209// Calls into driving physical LED post choosing the action
Potin Laif1ed4792023-07-13 18:45:14 +0800210int Manager::drivePhysicalLED(const std::string& objPath, Layout::Action action,
211 uint8_t dutyOn, const uint16_t period)
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530212{
George Liu1c737af2020-10-16 09:07:02 +0800213 try
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530214 {
George Liu1c737af2020-10-16 09:07:02 +0800215 // If Blink, set its property
216 if (action == Layout::Action::Blink)
217 {
218 PropertyValue dutyOnValue{dutyOn};
219 PropertyValue periodValue{period};
220
George Liuf0592552024-08-23 09:46:17 +0800221 phosphor::led::utils::DBusHandler::setProperty(
222 objPath, phyLedIntf, "DutyOn", dutyOnValue);
223 phosphor::led::utils::DBusHandler::setProperty(
224 objPath, phyLedIntf, "Period", periodValue);
George Liu1c737af2020-10-16 09:07:02 +0800225 }
226
227 PropertyValue actionValue{getPhysicalAction(action)};
George Liuf0592552024-08-23 09:46:17 +0800228 phosphor::led::utils::DBusHandler::setProperty(objPath, phyLedIntf,
229 "State", actionValue);
George Liu1c737af2020-10-16 09:07:02 +0800230 }
George Liu829c0b32023-07-18 10:00:47 +0800231 catch (const sdbusplus::exception_t& e)
George Liu1c737af2020-10-16 09:07:02 +0800232 {
George Liue9fb5c62021-07-01 14:05:32 +0800233 lg2::error(
234 "Error setting property for physical LED, ERROR = {ERROR}, OBJECT_PATH = {PATH}",
235 "ERROR", e, "PATH", objPath);
Potin Laif1ed4792023-07-13 18:45:14 +0800236 return -1;
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530237 }
Vishwanatha Subbannadcc3f382017-03-24 20:15:02 +0530238
Potin Laif1ed4792023-07-13 18:45:14 +0800239 return 0;
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530240}
241
242/** @brief Returns action string based on enum */
Vishwanatha Subbanna4fa92482017-03-10 14:39:20 +0530243std::string Manager::getPhysicalAction(Layout::Action action)
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530244{
Vishwanatha Subbanna4fa92482017-03-10 14:39:20 +0530245 namespace server = sdbusplus::xyz::openbmc_project::Led::server;
246
247 // TODO: openbmc/phosphor-led-manager#5
248 // Somehow need to use the generated Action enum than giving one
249 // in ledlayout.
Patrick Venture91ac8d32018-11-01 17:03:22 -0700250 if (action == Layout::Action::On)
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530251 {
Vishwanatha Subbanna4fa92482017-03-10 14:39:20 +0530252 return server::convertForMessage(server::Physical::Action::On);
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530253 }
Patrick Venture91ac8d32018-11-01 17:03:22 -0700254 else if (action == Layout::Action::Blink)
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530255 {
Vishwanatha Subbanna4fa92482017-03-10 14:39:20 +0530256 return server::convertForMessage(server::Physical::Action::Blink);
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530257 }
258 else
259 {
Vishwanatha Subbanna4fa92482017-03-10 14:39:20 +0530260 return server::convertForMessage(server::Physical::Action::Off);
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530261 }
262}
263
Potin Laif1ed4792023-07-13 18:45:14 +0800264void Manager::driveLedsHandler(void)
265{
266 ActionSet failedLedsAssert;
267 ActionSet failedLedsDeAssert;
268
269 // This order of LED operation is important.
Alexander Hansenfe476e12024-07-23 15:45:22 +0200270 for (const auto& it : reqLedsDeAssert)
Potin Laif1ed4792023-07-13 18:45:14 +0800271 {
Alexander Hansenfe476e12024-07-23 15:45:22 +0200272 std::string objPath = std::string(phyLedPath) + it.name;
273 lg2::debug("De-Asserting LED, NAME = {NAME}, ACTION = {ACTION}", "NAME",
274 it.name, "ACTION", it.action);
275 if (drivePhysicalLED(objPath, Layout::Action::Off, it.dutyOn,
276 it.period))
Potin Laif1ed4792023-07-13 18:45:14 +0800277 {
Alexander Hansenfe476e12024-07-23 15:45:22 +0200278 failedLedsDeAssert.insert(it);
Potin Laif1ed4792023-07-13 18:45:14 +0800279 }
280 }
281
Alexander Hansenfe476e12024-07-23 15:45:22 +0200282 for (const auto& it : reqLedsAssert)
Potin Laif1ed4792023-07-13 18:45:14 +0800283 {
Alexander Hansenfe476e12024-07-23 15:45:22 +0200284 std::string objPath = std::string(phyLedPath) + it.name;
285 lg2::debug("Asserting LED, NAME = {NAME}, ACTION = {ACTION}", "NAME",
286 it.name, "ACTION", it.action);
287 if (drivePhysicalLED(objPath, it.action, it.dutyOn, it.period))
Potin Laif1ed4792023-07-13 18:45:14 +0800288 {
Alexander Hansenfe476e12024-07-23 15:45:22 +0200289 failedLedsAssert.insert(it);
Potin Laif1ed4792023-07-13 18:45:14 +0800290 }
291 }
292
293 reqLedsAssert = failedLedsAssert;
294 reqLedsDeAssert = failedLedsDeAssert;
295
296 if (reqLedsDeAssert.empty() && reqLedsAssert.empty())
297 {
298 timer.setEnabled(false);
299 }
300 else
301 {
302 timer.restartOnce(std::chrono::seconds(1));
303 }
304
305 return;
306}
307
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +0530308} // namespace led
309} // namespace phosphor