xref: /openbmc/phosphor-led-manager/manager/manager.cpp (revision 9e1041513797665efc119084f774db2848908292)
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