1953315d2SPatrick Williams #include "config.h"
2953315d2SPatrick Williams
3953315d2SPatrick Williams #include "manager.hpp"
4953315d2SPatrick Williams
5953315d2SPatrick Williams #include <phosphor-logging/lg2.hpp>
6953315d2SPatrick Williams #include <sdbusplus/exception.hpp>
7953315d2SPatrick Williams #include <xyz/openbmc_project/Led/Physical/server.hpp>
8953315d2SPatrick Williams
9953315d2SPatrick Williams #include <algorithm>
10953315d2SPatrick Williams #include <iostream>
11953315d2SPatrick Williams #include <string>
12953315d2SPatrick Williams namespace phosphor
13953315d2SPatrick Williams {
14953315d2SPatrick Williams namespace led
15953315d2SPatrick Williams {
16953315d2SPatrick Williams
17a6f9a41eSAlexander Hansen // apply the led action to the map
applyGroupAction(std::map<LedName,Layout::LedAction> & newState,Layout::LedAction action)18a6f9a41eSAlexander Hansen static void applyGroupAction(std::map<LedName, Layout::LedAction>& newState,
19a6f9a41eSAlexander Hansen Layout::LedAction action)
20a6f9a41eSAlexander Hansen {
21a6f9a41eSAlexander Hansen if (!newState.contains(action.name))
22a6f9a41eSAlexander Hansen {
23a6f9a41eSAlexander Hansen newState[action.name] = action;
24a6f9a41eSAlexander Hansen return;
25a6f9a41eSAlexander Hansen }
26a6f9a41eSAlexander Hansen
27a6f9a41eSAlexander Hansen auto currentAction = newState[action.name];
28a6f9a41eSAlexander Hansen
2955badf79SAlexander Hansen const bool hasPriority = currentAction.priority.has_value();
3055badf79SAlexander Hansen
3155badf79SAlexander Hansen if (hasPriority && currentAction.action == action.priority)
32a6f9a41eSAlexander Hansen {
33a6f9a41eSAlexander Hansen // if the current action is already the priority action,
34a6f9a41eSAlexander Hansen // we cannot override it
35a6f9a41eSAlexander Hansen return;
36a6f9a41eSAlexander Hansen }
37a6f9a41eSAlexander Hansen
38a6f9a41eSAlexander Hansen newState[action.name] = action;
39a6f9a41eSAlexander Hansen }
40a6f9a41eSAlexander Hansen
41a6f9a41eSAlexander Hansen // create the resulting new map from all currently asserted groups
getNewMapWithGroupPriorities(std::set<const Layout::GroupLayout *,Layout::CompareGroupLayout> sorted)427ba70c82SAlexander Hansen static auto getNewMapWithGroupPriorities(
437ba70c82SAlexander Hansen std::set<const Layout::GroupLayout*, Layout::CompareGroupLayout> sorted)
44a6f9a41eSAlexander Hansen -> std::map<LedName, Layout::LedAction>
45a6f9a41eSAlexander Hansen {
46a6f9a41eSAlexander Hansen std::map<LedName, Layout::LedAction> newState;
47a6f9a41eSAlexander Hansen
48a6f9a41eSAlexander Hansen // update the new map with the desired state
493d48751bSGeorge Liu for (const auto* it : sorted)
50a6f9a41eSAlexander Hansen {
51a6f9a41eSAlexander Hansen // apply all led actions of that group to the map
52112821cfSGeorge Liu for (const Layout::LedAction& action : it->actionSet)
537ba70c82SAlexander Hansen {
547ba70c82SAlexander Hansen newState[action.name] = action;
557ba70c82SAlexander Hansen }
567ba70c82SAlexander Hansen }
577ba70c82SAlexander Hansen return newState;
587ba70c82SAlexander Hansen }
597ba70c82SAlexander Hansen
getNewMapWithLEDPriorities(std::set<const Layout::GroupLayout * > assertedGroups)607ba70c82SAlexander Hansen static std::map<LedName, Layout::LedAction> getNewMapWithLEDPriorities(
617ba70c82SAlexander Hansen std::set<const Layout::GroupLayout*> assertedGroups)
627ba70c82SAlexander Hansen {
637ba70c82SAlexander Hansen std::map<LedName, Layout::LedAction> newState;
647ba70c82SAlexander Hansen // update the new map with the desired state
657ba70c82SAlexander Hansen for (const Layout::GroupLayout* it : assertedGroups)
667ba70c82SAlexander Hansen {
677ba70c82SAlexander Hansen // apply all led actions of that group to the map
68112821cfSGeorge Liu for (const Layout::LedAction& action : it->actionSet)
69a6f9a41eSAlexander Hansen {
70a6f9a41eSAlexander Hansen applyGroupAction(newState, action);
71a6f9a41eSAlexander Hansen }
72a6f9a41eSAlexander Hansen }
73a6f9a41eSAlexander Hansen return newState;
74a6f9a41eSAlexander Hansen }
75a6f9a41eSAlexander Hansen
767ba70c82SAlexander Hansen // create the resulting new map from all currently asserted groups
777ba70c82SAlexander Hansen std::map<LedName, Layout::LedAction>
getNewMap(std::set<const Layout::GroupLayout * > assertedGroups)787ba70c82SAlexander Hansen Manager::getNewMap(std::set<const Layout::GroupLayout*> assertedGroups)
797ba70c82SAlexander Hansen {
807ba70c82SAlexander Hansen std::map<LedName, Layout::LedAction> newState;
817ba70c82SAlexander Hansen
827ba70c82SAlexander Hansen std::set<const Layout::GroupLayout*, Layout::CompareGroupLayout> sorted;
837ba70c82SAlexander Hansen
847ba70c82SAlexander Hansen bool groupPriorities = false;
857ba70c82SAlexander Hansen
867ba70c82SAlexander Hansen for (const Layout::GroupLayout* it : assertedGroups)
877ba70c82SAlexander Hansen {
887ba70c82SAlexander Hansen sorted.insert(it);
897ba70c82SAlexander Hansen
907ba70c82SAlexander Hansen if (it->priority != 0)
917ba70c82SAlexander Hansen {
927ba70c82SAlexander Hansen groupPriorities = true;
937ba70c82SAlexander Hansen }
947ba70c82SAlexander Hansen }
957ba70c82SAlexander Hansen
967ba70c82SAlexander Hansen if (groupPriorities)
977ba70c82SAlexander Hansen {
987ba70c82SAlexander Hansen newState = getNewMapWithGroupPriorities(sorted);
997ba70c82SAlexander Hansen }
1007ba70c82SAlexander Hansen else
1017ba70c82SAlexander Hansen {
1027ba70c82SAlexander Hansen newState = getNewMapWithLEDPriorities(assertedGroups);
1037ba70c82SAlexander Hansen }
1047ba70c82SAlexander Hansen
1057ba70c82SAlexander Hansen return newState;
1067ba70c82SAlexander Hansen }
1077ba70c82SAlexander Hansen
108953315d2SPatrick Williams // Assert -or- De-assert
setGroupState(const std::string & path,bool assert,ActionSet & ledsAssert,ActionSet & ledsDeAssert)109953315d2SPatrick Williams bool Manager::setGroupState(const std::string& path, bool assert,
110158b2c14SPatrick Williams ActionSet& ledsAssert, ActionSet& ledsDeAssert)
111953315d2SPatrick Williams {
112953315d2SPatrick Williams if (assert)
113953315d2SPatrick Williams {
114953315d2SPatrick Williams assertedGroups.insert(&ledMap.at(path));
115953315d2SPatrick Williams }
116953315d2SPatrick Williams else
117953315d2SPatrick Williams {
118953315d2SPatrick Williams if (assertedGroups.contains(&ledMap.at(path)))
119953315d2SPatrick Williams {
120953315d2SPatrick Williams assertedGroups.erase(&ledMap.at(path));
121953315d2SPatrick Williams }
122953315d2SPatrick Williams }
123953315d2SPatrick Williams
124a6f9a41eSAlexander Hansen // create the new map from the asserted groups
125a6f9a41eSAlexander Hansen auto newState = getNewMap(assertedGroups);
126a6f9a41eSAlexander Hansen
127a6f9a41eSAlexander Hansen // the ledsAssert are those that are in the new map and change state
128a6f9a41eSAlexander Hansen // + those in the new map and not in the old map
129a6f9a41eSAlexander Hansen for (const auto& [name, action] : newState)
130953315d2SPatrick Williams {
131a6f9a41eSAlexander Hansen if (ledStateMap.contains(name))
132a6f9a41eSAlexander Hansen {
133a6f9a41eSAlexander Hansen // check if the led action has changed
134a6f9a41eSAlexander Hansen auto& currentAction = ledStateMap[name];
135a6f9a41eSAlexander Hansen
136a6f9a41eSAlexander Hansen if (currentAction.action == action.action)
137*9e104151SGeorge Liu {
138a6f9a41eSAlexander Hansen continue;
139953315d2SPatrick Williams }
140*9e104151SGeorge Liu }
141953315d2SPatrick Williams
142a6f9a41eSAlexander Hansen ledsAssert.insert(action);
143953315d2SPatrick Williams }
144a6f9a41eSAlexander Hansen
145a6f9a41eSAlexander Hansen // the ledsDeAssert are those in the old map but not in the new map
146a6f9a41eSAlexander Hansen for (const auto& [name, action] : ledStateMap)
147a6f9a41eSAlexander Hansen {
148a6f9a41eSAlexander Hansen if (!newState.contains(name))
149a6f9a41eSAlexander Hansen {
150a6f9a41eSAlexander Hansen ledsDeAssert.insert(action);
151953315d2SPatrick Williams }
152953315d2SPatrick Williams }
153953315d2SPatrick Williams
154a6f9a41eSAlexander Hansen ledStateMap = newState;
155953315d2SPatrick Williams
156953315d2SPatrick Williams // If we survive, then set the state accordingly.
157953315d2SPatrick Williams return assert;
158953315d2SPatrick Williams }
159953315d2SPatrick Williams
setLampTestCallBack(std::function<bool (ActionSet & ledsAssert,ActionSet & ledsDeAssert)> callBack)160953315d2SPatrick Williams void Manager::setLampTestCallBack(
161158b2c14SPatrick Williams std::function<bool(ActionSet& ledsAssert, ActionSet& ledsDeAssert)>
162158b2c14SPatrick Williams callBack)
163953315d2SPatrick Williams {
164953315d2SPatrick Williams lampTestCallBack = callBack;
165953315d2SPatrick Williams }
166953315d2SPatrick Williams
167953315d2SPatrick Williams /** @brief Run through the map and apply action on the LEDs */
driveLEDs(ActionSet & ledsAssert,ActionSet & ledsDeAssert)168158b2c14SPatrick Williams void Manager::driveLEDs(ActionSet& ledsAssert, ActionSet& ledsDeAssert)
169953315d2SPatrick Williams {
170953315d2SPatrick Williams #ifdef USE_LAMP_TEST
171953315d2SPatrick Williams // Use the lampTestCallBack method and trigger the callback method in the
172953315d2SPatrick Williams // lamp test(processLEDUpdates), in this way, all lamp test operations
173953315d2SPatrick Williams // are performed in the lamp test class.
174953315d2SPatrick Williams if (lampTestCallBack(ledsAssert, ledsDeAssert))
175953315d2SPatrick Williams {
176953315d2SPatrick Williams return;
177953315d2SPatrick Williams }
178953315d2SPatrick Williams #endif
179f1ed4796SPotin Lai ActionSet newReqChangedLeds;
180f1ed4796SPotin Lai std::vector<std::pair<ActionSet&, ActionSet&>> actionsVec = {
181f1ed4796SPotin Lai {reqLedsAssert, ledsAssert}, {reqLedsDeAssert, ledsDeAssert}};
182f1ed4796SPotin Lai
183f1ed4796SPotin Lai timer.setEnabled(false);
184f1ed4796SPotin Lai std::set_union(ledsAssert.begin(), ledsAssert.end(), ledsDeAssert.begin(),
185f1ed4796SPotin Lai ledsDeAssert.end(),
186f1ed4796SPotin Lai std::inserter(newReqChangedLeds, newReqChangedLeds.begin()),
187f1ed4796SPotin Lai ledLess);
188f1ed4796SPotin Lai
189f1ed4796SPotin Lai // prepare reqLedsAssert & reqLedsDeAssert
190f1ed4796SPotin Lai for (auto pair : actionsVec)
191953315d2SPatrick Williams {
192f1ed4796SPotin Lai ActionSet tmpSet;
193f1ed4796SPotin Lai
194f1ed4796SPotin Lai // Discard current required LED actions, if these LEDs have new actions
195f1ed4796SPotin Lai // in newReqChangedLeds.
196f1ed4796SPotin Lai std::set_difference(pair.first.begin(), pair.first.end(),
197f1ed4796SPotin Lai newReqChangedLeds.begin(), newReqChangedLeds.end(),
198f1ed4796SPotin Lai std::inserter(tmpSet, tmpSet.begin()), ledLess);
199f1ed4796SPotin Lai
200f1ed4796SPotin Lai // Union the remaining LED actions with new LED actions.
201f1ed4796SPotin Lai pair.first.clear();
202f1ed4796SPotin Lai std::set_union(tmpSet.begin(), tmpSet.end(), pair.second.begin(),
203f1ed4796SPotin Lai pair.second.end(),
204f1ed4796SPotin Lai std::inserter(pair.first, pair.first.begin()), ledLess);
205953315d2SPatrick Williams }
206953315d2SPatrick Williams
207f1ed4796SPotin Lai driveLedsHandler();
208953315d2SPatrick Williams return;
209953315d2SPatrick Williams }
210953315d2SPatrick Williams
211953315d2SPatrick Williams // Calls into driving physical LED post choosing the action
drivePhysicalLED(const std::string & objPath,Layout::Action action,uint8_t dutyOn,uint16_t period)212f1ed4796SPotin Lai int Manager::drivePhysicalLED(const std::string& objPath, Layout::Action action,
21380f51bbbSGeorge Liu uint8_t dutyOn, uint16_t period)
214953315d2SPatrick Williams {
215953315d2SPatrick Williams try
216953315d2SPatrick Williams {
217953315d2SPatrick Williams // If Blink, set its property
218953315d2SPatrick Williams if (action == Layout::Action::Blink)
219953315d2SPatrick Williams {
220953315d2SPatrick Williams PropertyValue dutyOnValue{dutyOn};
221953315d2SPatrick Williams PropertyValue periodValue{period};
222953315d2SPatrick Williams
223f0592559SGeorge Liu phosphor::led::utils::DBusHandler::setProperty(
224f0592559SGeorge Liu objPath, phyLedIntf, "DutyOn", dutyOnValue);
225f0592559SGeorge Liu phosphor::led::utils::DBusHandler::setProperty(
226f0592559SGeorge Liu objPath, phyLedIntf, "Period", periodValue);
227953315d2SPatrick Williams }
228953315d2SPatrick Williams
229953315d2SPatrick Williams PropertyValue actionValue{getPhysicalAction(action)};
230f0592559SGeorge Liu phosphor::led::utils::DBusHandler::setProperty(objPath, phyLedIntf,
231f0592559SGeorge Liu "State", actionValue);
232953315d2SPatrick Williams }
233829c0b34SGeorge Liu catch (const sdbusplus::exception_t& e)
234953315d2SPatrick Williams {
235953315d2SPatrick Williams lg2::error(
236953315d2SPatrick Williams "Error setting property for physical LED, ERROR = {ERROR}, OBJECT_PATH = {PATH}",
237953315d2SPatrick Williams "ERROR", e, "PATH", objPath);
238f1ed4796SPotin Lai return -1;
239953315d2SPatrick Williams }
240953315d2SPatrick Williams
241f1ed4796SPotin Lai return 0;
242953315d2SPatrick Williams }
243953315d2SPatrick Williams
244953315d2SPatrick Williams /** @brief Returns action string based on enum */
getPhysicalAction(Layout::Action action)245953315d2SPatrick Williams std::string Manager::getPhysicalAction(Layout::Action action)
246953315d2SPatrick Williams {
247953315d2SPatrick Williams namespace server = sdbusplus::xyz::openbmc_project::Led::server;
248953315d2SPatrick Williams
249953315d2SPatrick Williams // TODO: openbmc/phosphor-led-manager#5
250953315d2SPatrick Williams // Somehow need to use the generated Action enum than giving one
251953315d2SPatrick Williams // in ledlayout.
252953315d2SPatrick Williams if (action == Layout::Action::On)
253953315d2SPatrick Williams {
254953315d2SPatrick Williams return server::convertForMessage(server::Physical::Action::On);
255953315d2SPatrick Williams }
256953315d2SPatrick Williams else if (action == Layout::Action::Blink)
257953315d2SPatrick Williams {
258953315d2SPatrick Williams return server::convertForMessage(server::Physical::Action::Blink);
259953315d2SPatrick Williams }
260953315d2SPatrick Williams else
261953315d2SPatrick Williams {
262953315d2SPatrick Williams return server::convertForMessage(server::Physical::Action::Off);
263953315d2SPatrick Williams }
264953315d2SPatrick Williams }
265953315d2SPatrick Williams
driveLedsHandler(void)266f1ed4796SPotin Lai void Manager::driveLedsHandler(void)
267f1ed4796SPotin Lai {
268f1ed4796SPotin Lai ActionSet failedLedsAssert;
269f1ed4796SPotin Lai ActionSet failedLedsDeAssert;
270f1ed4796SPotin Lai
271f1ed4796SPotin Lai // This order of LED operation is important.
272f1ed4796SPotin Lai for (const auto& it : reqLedsDeAssert)
273f1ed4796SPotin Lai {
274f1ed4796SPotin Lai std::string objPath = std::string(phyLedPath) + it.name;
275fe476e17SAlexander Hansen lg2::debug("De-Asserting LED, NAME = {NAME}, ACTION = {ACTION}", "NAME",
276fe476e17SAlexander Hansen it.name, "ACTION", it.action);
277f1ed4796SPotin Lai if (drivePhysicalLED(objPath, Layout::Action::Off, it.dutyOn,
27849875a26SGeorge Liu it.period) != 0)
279f1ed4796SPotin Lai {
280f1ed4796SPotin Lai failedLedsDeAssert.insert(it);
281f1ed4796SPotin Lai }
282f1ed4796SPotin Lai }
283f1ed4796SPotin Lai
284f1ed4796SPotin Lai for (const auto& it : reqLedsAssert)
285f1ed4796SPotin Lai {
286f1ed4796SPotin Lai std::string objPath = std::string(phyLedPath) + it.name;
287fe476e17SAlexander Hansen lg2::debug("Asserting LED, NAME = {NAME}, ACTION = {ACTION}", "NAME",
288fe476e17SAlexander Hansen it.name, "ACTION", it.action);
28949875a26SGeorge Liu if (drivePhysicalLED(objPath, it.action, it.dutyOn, it.period) != 0)
290f1ed4796SPotin Lai {
291f1ed4796SPotin Lai failedLedsAssert.insert(it);
292f1ed4796SPotin Lai }
293f1ed4796SPotin Lai }
294f1ed4796SPotin Lai
295f1ed4796SPotin Lai reqLedsAssert = failedLedsAssert;
296f1ed4796SPotin Lai reqLedsDeAssert = failedLedsDeAssert;
297f1ed4796SPotin Lai
298f1ed4796SPotin Lai if (reqLedsDeAssert.empty() && reqLedsAssert.empty())
299f1ed4796SPotin Lai {
300f1ed4796SPotin Lai timer.setEnabled(false);
301f1ed4796SPotin Lai }
302f1ed4796SPotin Lai else
303f1ed4796SPotin Lai {
304f1ed4796SPotin Lai timer.restartOnce(std::chrono::seconds(1));
305f1ed4796SPotin Lai }
306f1ed4796SPotin Lai
307f1ed4796SPotin Lai return;
308f1ed4796SPotin Lai }
309f1ed4796SPotin Lai
310953315d2SPatrick Williams } // namespace led
311953315d2SPatrick Williams } // namespace phosphor
312