blob: 77419336ece83494b4a2dcee6648a6e4eef8d9e6 [file] [log] [blame]
Patrick Venture91ac8d32018-11-01 17:03:22 -07001#include "manager.hpp"
2
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +05303#include <phosphor-logging/log.hpp>
William A. Kennington III151122a2018-05-15 12:00:32 -07004#include <sdbusplus/exception.hpp>
Vishwanatha Subbanna4fa92482017-03-10 14:39:20 +05305#include <xyz/openbmc_project/Led/Physical/server.hpp>
George Liua6c18f82020-06-22 10:50:04 +08006
7#include <algorithm>
8#include <iostream>
9#include <string>
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +053010namespace phosphor
11{
12namespace led
13{
14
15// Assert -or- De-assert
Vishwanatha Subbannaed490732016-12-20 15:59:29 +053016bool Manager::setGroupState(const std::string& path, bool assert,
Vishwanatha Subbanna4b000d82017-05-03 18:44:16 +053017 group& ledsAssert, group& ledsDeAssert)
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +053018{
19 if (assert)
20 {
21 assertedGroups.insert(&ledMap.at(path));
22 }
23 else
24 {
25 auto search = assertedGroups.find(&ledMap.at(path));
26 if (search != assertedGroups.end())
27 {
28 assertedGroups.erase(&ledMap.at(path));
29 }
30 }
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +053031
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +053032 // This will contain the union of what's already in the asserted group
Patrick Venture91ac8d32018-11-01 17:03:22 -070033 group desiredState{};
34 for (const auto& grp : assertedGroups)
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +053035 {
36 desiredState.insert(grp->cbegin(), grp->cend());
37 }
38
Vishwanatha Subbanna4b000d82017-05-03 18:44:16 +053039 // Find difference between Combined and Desired to identify
40 // which LEDs are getting altered
Patrick Venture91ac8d32018-11-01 17:03:22 -070041 group transient{};
Vishwanatha Subbanna4b000d82017-05-03 18:44:16 +053042 std::set_difference(combinedState.begin(), combinedState.end(),
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +053043 desiredState.begin(), desiredState.end(),
Patrick Venture91ac8d32018-11-01 17:03:22 -070044 std::inserter(transient, transient.begin()), ledComp);
45 if (transient.size())
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +053046 {
Vishwanatha Subbanna4b000d82017-05-03 18:44:16 +053047 // Find common LEDs between transient and Desired to know if some LEDs
48 // are changing state and not really getting DeAsserted
Patrick Venture91ac8d32018-11-01 17:03:22 -070049 group ledsTransient{};
50 std::set_intersection(
51 transient.begin(), transient.end(), desiredState.begin(),
52 desiredState.end(),
53 std::inserter(ledsTransient, ledsTransient.begin()), ledLess);
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +053054
Vishwanatha Subbanna4b000d82017-05-03 18:44:16 +053055 // Find difference between above 2 to identify those LEDs which are
56 // really getting DeAsserted
Patrick Venture91ac8d32018-11-01 17:03:22 -070057 std::set_difference(transient.begin(), transient.end(),
58 ledsTransient.begin(), ledsTransient.end(),
Vishwanatha Subbanna447d0c82016-12-19 14:12:42 +053059 std::inserter(ledsDeAssert, ledsDeAssert.begin()),
Vishwanatha Subbanna4b000d82017-05-03 18:44:16 +053060 ledLess);
Vishwanatha Subbanna447d0c82016-12-19 14:12:42 +053061
Vishwanatha Subbanna4b000d82017-05-03 18:44:16 +053062 // Remove the elements from Current that are being DeAsserted.
Patrick Venture91ac8d32018-11-01 17:03:22 -070063 if (ledsDeAssert.size())
Vishwanatha Subbanna4b000d82017-05-03 18:44:16 +053064 {
65 // Power off LEDs that are to be really DeAsserted
Patrick Venture91ac8d32018-11-01 17:03:22 -070066 for (auto& it : ledsDeAssert)
Vishwanatha Subbanna4b000d82017-05-03 18:44:16 +053067 {
68 // Update LEDs in "physically asserted" set by removing those
69 // LEDs which are De-Asserted
70 auto found = currentState.find(it);
71 if (found != currentState.end())
72 {
73 currentState.erase(found);
74 }
75 }
76 }
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +053077 }
78
Vishwanatha Subbanna4b000d82017-05-03 18:44:16 +053079 // Now LEDs that are to be Asserted. These could either be fresh asserts
80 // -or- change between [On]<-->[Blink]
Patrick Venture91ac8d32018-11-01 17:03:22 -070081 group temp{};
Vishwanatha Subbanna4b000d82017-05-03 18:44:16 +053082 std::unique_copy(desiredState.begin(), desiredState.end(),
Patrick Venture91ac8d32018-11-01 17:03:22 -070083 std::inserter(temp, temp.begin()), ledEqual);
84 if (temp.size())
Vishwanatha Subbanna4b000d82017-05-03 18:44:16 +053085 {
86 // Find difference between [desired to be Asserted] and those LEDs
87 // that are physically asserted currently.
Patrick Venture91ac8d32018-11-01 17:03:22 -070088 std::set_difference(
89 temp.begin(), temp.end(), currentState.begin(), currentState.end(),
90 std::inserter(ledsAssert, ledsAssert.begin()), ledComp);
Vishwanatha Subbanna4b000d82017-05-03 18:44:16 +053091 }
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +053092
Vishwanatha Subbanna4b000d82017-05-03 18:44:16 +053093 // Update the current actual and desired(the virtual actual)
94 currentState = std::move(temp);
95 combinedState = std::move(desiredState);
Vishwanatha Subbannaed490732016-12-20 15:59:29 +053096
97 // If we survive, then set the state accordingly.
98 return assert;
99}
100
101/** @brief Run through the map and apply action on the LEDs */
Vishwanatha Subbanna4b000d82017-05-03 18:44:16 +0530102void Manager::driveLEDs(group& ledsAssert, group& ledsDeAssert)
Vishwanatha Subbannaed490732016-12-20 15:59:29 +0530103{
Alexander Soldatovf3c03412018-04-12 14:40:23 +0300104 using namespace phosphor::logging;
Vishwanatha Subbannadcc3f382017-03-24 20:15:02 +0530105 // Map of physical LED dbus paths to their Service providers
106 populateObjectMap();
107
108 if (phyLeds.empty())
109 {
110 // Error message is inside the map construction logic.
111 return;
112 }
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530113
Vishwanatha Subbannaed490732016-12-20 15:59:29 +0530114 // This order of LED operation is important.
Vishwanatha Subbannaed490732016-12-20 15:59:29 +0530115 if (ledsDeAssert.size())
116 {
Patrick Venture91ac8d32018-11-01 17:03:22 -0700117 for (const auto& it : ledsDeAssert)
Vishwanatha Subbannaed490732016-12-20 15:59:29 +0530118 {
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530119 std::string objPath = std::string(PHY_LED_PATH) + it.name;
Patrick Venture91ac8d32018-11-01 17:03:22 -0700120 log<level::DEBUG>("De-Asserting LED",
121 entry("NAME=%s", it.name.c_str()));
tony lee6fd9e442019-04-23 09:09:15 +0800122 drivePhysicalLED(objPath, Layout::Action::Off, it.dutyOn,
123 it.period);
Vishwanatha Subbannaed490732016-12-20 15:59:29 +0530124 }
125 }
126
Patrick Venture91ac8d32018-11-01 17:03:22 -0700127 if (ledsAssert.size())
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +0530128 {
Patrick Venture91ac8d32018-11-01 17:03:22 -0700129 for (const auto& it : ledsAssert)
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +0530130 {
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530131 std::string objPath = std::string(PHY_LED_PATH) + it.name;
Patrick Venture91ac8d32018-11-01 17:03:22 -0700132 log<level::DEBUG>("Asserting LED",
133 entry("NAME=%s", it.name.c_str()));
tony lee6fd9e442019-04-23 09:09:15 +0800134 drivePhysicalLED(objPath, it.action, it.dutyOn, it.period);
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +0530135 }
136 }
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +0530137 return;
138}
139
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530140// Calls into driving physical LED post choosing the action
141void Manager::drivePhysicalLED(const std::string& objPath,
tony lee6fd9e442019-04-23 09:09:15 +0800142 Layout::Action action, uint8_t dutyOn,
143 const uint16_t period)
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530144{
Vishwanatha Subbannadcc3f382017-03-24 20:15:02 +0530145 using namespace phosphor::logging;
146
147 auto service = phyLeds.find(objPath);
148 if (service == phyLeds.end() || service->second.empty())
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530149 {
Vishwanatha Subbannadcc3f382017-03-24 20:15:02 +0530150 log<level::ERR>("No service providers for physical LED",
Patrick Venture91ac8d32018-11-01 17:03:22 -0700151 entry("PATH=%s", objPath.c_str()));
Vishwanatha Subbannadcc3f382017-03-24 20:15:02 +0530152 return;
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530153 }
Vishwanatha Subbannadcc3f382017-03-24 20:15:02 +0530154
Patrick Venture91ac8d32018-11-01 17:03:22 -0700155 // If Blink, set its property
156 if (action == Layout::Action::Blink)
157 {
158 drivePhysicalLED(service->second, objPath, "DutyOn", dutyOn);
tony lee6fd9e442019-04-23 09:09:15 +0800159 drivePhysicalLED(service->second, objPath, "Period", period);
Patrick Venture91ac8d32018-11-01 17:03:22 -0700160 }
161 drivePhysicalLED(service->second, objPath, "State",
162 getPhysicalAction(action));
163 return;
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530164}
165
166/** @brief Returns action string based on enum */
Vishwanatha Subbanna4fa92482017-03-10 14:39:20 +0530167std::string Manager::getPhysicalAction(Layout::Action action)
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530168{
Vishwanatha Subbanna4fa92482017-03-10 14:39:20 +0530169 namespace server = sdbusplus::xyz::openbmc_project::Led::server;
170
171 // TODO: openbmc/phosphor-led-manager#5
172 // Somehow need to use the generated Action enum than giving one
173 // in ledlayout.
Patrick Venture91ac8d32018-11-01 17:03:22 -0700174 if (action == Layout::Action::On)
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530175 {
Vishwanatha Subbanna4fa92482017-03-10 14:39:20 +0530176 return server::convertForMessage(server::Physical::Action::On);
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530177 }
Patrick Venture91ac8d32018-11-01 17:03:22 -0700178 else if (action == Layout::Action::Blink)
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530179 {
Vishwanatha Subbanna4fa92482017-03-10 14:39:20 +0530180 return server::convertForMessage(server::Physical::Action::Blink);
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530181 }
182 else
183 {
Vishwanatha Subbanna4fa92482017-03-10 14:39:20 +0530184 return server::convertForMessage(server::Physical::Action::Off);
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530185 }
186}
187
Vishwanatha Subbannadcc3f382017-03-24 20:15:02 +0530188/** Populates a map with physical LED paths to its service providers */
189void Manager::populateObjectMap()
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530190{
191 using namespace phosphor::logging;
192
193 // Mapper dbus constructs
Patrick Venture91ac8d32018-11-01 17:03:22 -0700194 constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper";
195 constexpr auto MAPPER_OBJ_PATH = "/xyz/openbmc_project/object_mapper";
196 constexpr auto MAPPER_IFACE = "xyz.openbmc_project.ObjectMapper";
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530197
Vishwanatha Subbannadcc3f382017-03-24 20:15:02 +0530198 // Needed to be passed to get the SubTree level
199 auto depth = 0;
200
201 // Clean start
202 phyLeds.clear();
203
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530204 // Make a mapper call
205 auto mapperCall = bus.new_method_call(MAPPER_BUSNAME, MAPPER_OBJ_PATH,
Vishwanatha Subbannadcc3f382017-03-24 20:15:02 +0530206 MAPPER_IFACE, "GetSubTree");
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530207 // Cook rest of the things.
Vishwanatha Subbannadcc3f382017-03-24 20:15:02 +0530208 mapperCall.append(PHY_LED_PATH);
209 mapperCall.append(depth);
210 mapperCall.append(std::vector<std::string>({PHY_LED_IFACE}));
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530211
212 auto reply = bus.call(mapperCall);
213 if (reply.is_method_error())
214 {
215 // Its okay if we do not see a corresponding physical LED.
Vishwanatha Subbannadcc3f382017-03-24 20:15:02 +0530216 log<level::INFO>("Error looking up Physical LED services",
Patrick Venture91ac8d32018-11-01 17:03:22 -0700217 entry("PATH=%s", PHY_LED_PATH));
Vishwanatha Subbannadcc3f382017-03-24 20:15:02 +0530218 return;
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530219 }
220
221 // Response by mapper in the case of success
Patrick Venture91ac8d32018-11-01 17:03:22 -0700222 std::map<std::string, std::map<std::string, std::vector<std::string>>>
223 objectTree;
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530224
Vishwanatha Subbannadcc3f382017-03-24 20:15:02 +0530225 // This is the dict of object paths - service names - interfaces
William A. Kennington III151122a2018-05-15 12:00:32 -0700226 try
227 {
228 reply.read(objectTree);
229 }
230 catch (const sdbusplus::exception::SdBusError& e)
231 {
232 log<level::ERR>("Failed to parse Physical LED service lookup",
233 entry("ERROR=%s", e.what()),
234 entry("REPLY_SIG=%s", reply.get_signature()));
235 return;
236 }
Vishwanatha Subbannadcc3f382017-03-24 20:15:02 +0530237 if (objectTree.empty())
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530238 {
Vishwanatha Subbannadcc3f382017-03-24 20:15:02 +0530239 log<level::INFO>("Physical LED lookup did not return any services",
Patrick Venture91ac8d32018-11-01 17:03:22 -0700240 entry("PATH=%s", PHY_LED_PATH));
Vishwanatha Subbannadcc3f382017-03-24 20:15:02 +0530241 return;
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530242 }
243
Vishwanatha Subbannadcc3f382017-03-24 20:15:02 +0530244 // Now construct our path -> Service name map.
245 for (const auto& iter : objectTree)
246 {
247 phyLeds.emplace(iter.first, iter.second.begin()->first);
248 }
249 return;
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530250}
251
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +0530252} // namespace led
253} // namespace phosphor