blob: ec02419d72d5bceb36546b58d2506f19364d0593 [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
40auto Manager::getNewMap(std::set<const ActionSet*> assertedGroups)
41 -> std::map<LedName, Layout::LedAction>
42{
43 std::map<LedName, Layout::LedAction> newState;
44
45 // update the new map with the desired state
46 for (const auto it : assertedGroups)
47 {
48 // apply all led actions of that group to the map
49 for (auto action : *it)
50 {
51 applyGroupAction(newState, action);
52 }
53 }
54 return newState;
55}
56
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +053057// Assert -or- De-assert
Vishwanatha Subbannaed490732016-12-20 15:59:29 +053058bool Manager::setGroupState(const std::string& path, bool assert,
Patrick Williams158b2c12022-03-17 05:57:44 -050059 ActionSet& ledsAssert, ActionSet& ledsDeAssert)
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +053060{
61 if (assert)
62 {
63 assertedGroups.insert(&ledMap.at(path));
64 }
65 else
66 {
George Liu7f53a032021-05-04 11:18:21 +080067 if (assertedGroups.contains(&ledMap.at(path)))
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +053068 {
69 assertedGroups.erase(&ledMap.at(path));
70 }
71 }
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +053072
Alexander Hansena6f9a412024-07-24 12:27:42 +020073 // create the new map from the asserted groups
74 auto newState = getNewMap(assertedGroups);
75
76 // the ledsAssert are those that are in the new map and change state
77 // + those in the new map and not in the old map
78 for (const auto& [name, action] : newState)
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +053079 {
Alexander Hansena6f9a412024-07-24 12:27:42 +020080 if (ledStateMap.contains(name))
81 {
82 // check if the led action has changed
83 auto& currentAction = ledStateMap[name];
84
85 if (currentAction.action == action.action)
86 continue;
87 }
88
89 ledsAssert.insert(action);
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +053090 }
91
Alexander Hansena6f9a412024-07-24 12:27:42 +020092 // the ledsDeAssert are those in the old map but not in the new map
93 for (const auto& [name, action] : ledStateMap)
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +053094 {
Alexander Hansena6f9a412024-07-24 12:27:42 +020095 if (!newState.contains(name))
Vishwanatha Subbanna4b000d82017-05-03 18:44:16 +053096 {
Alexander Hansena6f9a412024-07-24 12:27:42 +020097 ledsDeAssert.insert(action);
Vishwanatha Subbanna4b000d82017-05-03 18:44:16 +053098 }
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +053099 }
100
Alexander Hansena6f9a412024-07-24 12:27:42 +0200101 ledStateMap = newState;
Vishwanatha Subbannaed490732016-12-20 15:59:29 +0530102
103 // If we survive, then set the state accordingly.
104 return assert;
105}
106
George Liub6151622020-11-23 18:16:18 +0800107void Manager::setLampTestCallBack(
Patrick Williams158b2c12022-03-17 05:57:44 -0500108 std::function<bool(ActionSet& ledsAssert, ActionSet& ledsDeAssert)>
109 callBack)
George Liub6151622020-11-23 18:16:18 +0800110{
111 lampTestCallBack = callBack;
112}
113
Vishwanatha Subbannaed490732016-12-20 15:59:29 +0530114/** @brief Run through the map and apply action on the LEDs */
Patrick Williams158b2c12022-03-17 05:57:44 -0500115void Manager::driveLEDs(ActionSet& ledsAssert, ActionSet& ledsDeAssert)
Vishwanatha Subbannaed490732016-12-20 15:59:29 +0530116{
George Liub6151622020-11-23 18:16:18 +0800117#ifdef USE_LAMP_TEST
118 // Use the lampTestCallBack method and trigger the callback method in the
119 // lamp test(processLEDUpdates), in this way, all lamp test operations
120 // are performed in the lamp test class.
121 if (lampTestCallBack(ledsAssert, ledsDeAssert))
122 {
123 return;
124 }
125#endif
Potin Laif1ed4792023-07-13 18:45:14 +0800126 ActionSet newReqChangedLeds;
127 std::vector<std::pair<ActionSet&, ActionSet&>> actionsVec = {
128 {reqLedsAssert, ledsAssert}, {reqLedsDeAssert, ledsDeAssert}};
129
130 timer.setEnabled(false);
131 std::set_union(ledsAssert.begin(), ledsAssert.end(), ledsDeAssert.begin(),
132 ledsDeAssert.end(),
133 std::inserter(newReqChangedLeds, newReqChangedLeds.begin()),
134 ledLess);
135
136 // prepare reqLedsAssert & reqLedsDeAssert
137 for (auto pair : actionsVec)
Vishwanatha Subbannaed490732016-12-20 15:59:29 +0530138 {
Potin Laif1ed4792023-07-13 18:45:14 +0800139 ActionSet tmpSet;
140
141 // Discard current required LED actions, if these LEDs have new actions
142 // in newReqChangedLeds.
143 std::set_difference(pair.first.begin(), pair.first.end(),
144 newReqChangedLeds.begin(), newReqChangedLeds.end(),
145 std::inserter(tmpSet, tmpSet.begin()), ledLess);
146
147 // Union the remaining LED actions with new LED actions.
148 pair.first.clear();
149 std::set_union(tmpSet.begin(), tmpSet.end(), pair.second.begin(),
150 pair.second.end(),
151 std::inserter(pair.first, pair.first.begin()), ledLess);
Vishwanatha Subbannaed490732016-12-20 15:59:29 +0530152 }
153
Potin Laif1ed4792023-07-13 18:45:14 +0800154 driveLedsHandler();
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +0530155 return;
156}
157
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530158// Calls into driving physical LED post choosing the action
Potin Laif1ed4792023-07-13 18:45:14 +0800159int Manager::drivePhysicalLED(const std::string& objPath, Layout::Action action,
160 uint8_t dutyOn, const uint16_t period)
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530161{
George Liu1c737af2020-10-16 09:07:02 +0800162 try
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530163 {
George Liu1c737af2020-10-16 09:07:02 +0800164 // If Blink, set its property
165 if (action == Layout::Action::Blink)
166 {
167 PropertyValue dutyOnValue{dutyOn};
168 PropertyValue periodValue{period};
169
George Liu1f0b7152023-07-18 09:24:34 +0800170 dBusHandler.setProperty(objPath, phyLedIntf, "DutyOn", dutyOnValue);
171 dBusHandler.setProperty(objPath, phyLedIntf, "Period", periodValue);
George Liu1c737af2020-10-16 09:07:02 +0800172 }
173
174 PropertyValue actionValue{getPhysicalAction(action)};
George Liu1f0b7152023-07-18 09:24:34 +0800175 dBusHandler.setProperty(objPath, phyLedIntf, "State", actionValue);
George Liu1c737af2020-10-16 09:07:02 +0800176 }
George Liu829c0b32023-07-18 10:00:47 +0800177 catch (const sdbusplus::exception_t& e)
George Liu1c737af2020-10-16 09:07:02 +0800178 {
George Liue9fb5c62021-07-01 14:05:32 +0800179 lg2::error(
180 "Error setting property for physical LED, ERROR = {ERROR}, OBJECT_PATH = {PATH}",
181 "ERROR", e, "PATH", objPath);
Potin Laif1ed4792023-07-13 18:45:14 +0800182 return -1;
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530183 }
Vishwanatha Subbannadcc3f382017-03-24 20:15:02 +0530184
Potin Laif1ed4792023-07-13 18:45:14 +0800185 return 0;
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530186}
187
188/** @brief Returns action string based on enum */
Vishwanatha Subbanna4fa92482017-03-10 14:39:20 +0530189std::string Manager::getPhysicalAction(Layout::Action action)
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530190{
Vishwanatha Subbanna4fa92482017-03-10 14:39:20 +0530191 namespace server = sdbusplus::xyz::openbmc_project::Led::server;
192
193 // TODO: openbmc/phosphor-led-manager#5
194 // Somehow need to use the generated Action enum than giving one
195 // in ledlayout.
Patrick Venture91ac8d32018-11-01 17:03:22 -0700196 if (action == Layout::Action::On)
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530197 {
Vishwanatha Subbanna4fa92482017-03-10 14:39:20 +0530198 return server::convertForMessage(server::Physical::Action::On);
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530199 }
Patrick Venture91ac8d32018-11-01 17:03:22 -0700200 else if (action == Layout::Action::Blink)
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530201 {
Vishwanatha Subbanna4fa92482017-03-10 14:39:20 +0530202 return server::convertForMessage(server::Physical::Action::Blink);
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530203 }
204 else
205 {
Vishwanatha Subbanna4fa92482017-03-10 14:39:20 +0530206 return server::convertForMessage(server::Physical::Action::Off);
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530207 }
208}
209
Potin Laif1ed4792023-07-13 18:45:14 +0800210void Manager::driveLedsHandler(void)
211{
212 ActionSet failedLedsAssert;
213 ActionSet failedLedsDeAssert;
214
215 // This order of LED operation is important.
Alexander Hansenfe476e12024-07-23 15:45:22 +0200216 for (const auto& it : reqLedsDeAssert)
Potin Laif1ed4792023-07-13 18:45:14 +0800217 {
Alexander Hansenfe476e12024-07-23 15:45:22 +0200218 std::string objPath = std::string(phyLedPath) + it.name;
219 lg2::debug("De-Asserting LED, NAME = {NAME}, ACTION = {ACTION}", "NAME",
220 it.name, "ACTION", it.action);
221 if (drivePhysicalLED(objPath, Layout::Action::Off, it.dutyOn,
222 it.period))
Potin Laif1ed4792023-07-13 18:45:14 +0800223 {
Alexander Hansenfe476e12024-07-23 15:45:22 +0200224 failedLedsDeAssert.insert(it);
Potin Laif1ed4792023-07-13 18:45:14 +0800225 }
226 }
227
Alexander Hansenfe476e12024-07-23 15:45:22 +0200228 for (const auto& it : reqLedsAssert)
Potin Laif1ed4792023-07-13 18:45:14 +0800229 {
Alexander Hansenfe476e12024-07-23 15:45:22 +0200230 std::string objPath = std::string(phyLedPath) + it.name;
231 lg2::debug("Asserting LED, NAME = {NAME}, ACTION = {ACTION}", "NAME",
232 it.name, "ACTION", it.action);
233 if (drivePhysicalLED(objPath, it.action, it.dutyOn, it.period))
Potin Laif1ed4792023-07-13 18:45:14 +0800234 {
Alexander Hansenfe476e12024-07-23 15:45:22 +0200235 failedLedsAssert.insert(it);
Potin Laif1ed4792023-07-13 18:45:14 +0800236 }
237 }
238
239 reqLedsAssert = failedLedsAssert;
240 reqLedsDeAssert = failedLedsDeAssert;
241
242 if (reqLedsDeAssert.empty() && reqLedsAssert.empty())
243 {
244 timer.setEnabled(false);
245 }
246 else
247 {
248 timer.restartOnce(std::chrono::seconds(1));
249 }
250
251 return;
252}
253
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +0530254} // namespace led
255} // namespace phosphor