blob: 28e6815f6e9369fa5670176362d872768f7cfc30 [file] [log] [blame]
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +05301#include <iostream>
2#include <string>
3#include <algorithm>
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +05304#include <phosphor-logging/log.hpp>
William A. Kennington III151122a2018-05-15 12:00:32 -07005#include <sdbusplus/exception.hpp>
Vishwanatha Subbanna4fa92482017-03-10 14:39:20 +05306#include <xyz/openbmc_project/Led/Physical/server.hpp>
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +05307#include "manager.hpp"
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +05308namespace phosphor
9{
10namespace led
11{
12
13// Assert -or- De-assert
Vishwanatha Subbannaed490732016-12-20 15:59:29 +053014bool Manager::setGroupState(const std::string& path, bool assert,
Vishwanatha Subbanna4b000d82017-05-03 18:44:16 +053015 group& ledsAssert, group& ledsDeAssert)
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +053016{
17 if (assert)
18 {
19 assertedGroups.insert(&ledMap.at(path));
20 }
21 else
22 {
23 auto search = assertedGroups.find(&ledMap.at(path));
24 if (search != assertedGroups.end())
25 {
26 assertedGroups.erase(&ledMap.at(path));
27 }
28 }
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +053029
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +053030 // This will contain the union of what's already in the asserted group
31 group desiredState {};
32 for(const auto& grp : assertedGroups)
33 {
34 desiredState.insert(grp->cbegin(), grp->cend());
35 }
36
Vishwanatha Subbanna4b000d82017-05-03 18:44:16 +053037 // Find difference between Combined and Desired to identify
38 // which LEDs are getting altered
Vishwanatha Subbanna447d0c82016-12-19 14:12:42 +053039 group transient {};
Vishwanatha Subbanna4b000d82017-05-03 18:44:16 +053040 std::set_difference(combinedState.begin(), combinedState.end(),
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +053041 desiredState.begin(), desiredState.end(),
Vishwanatha Subbannacd569d22017-05-03 12:46:14 +053042 std::inserter(transient, transient.begin()),
43 ledComp);
Vishwanatha Subbanna447d0c82016-12-19 14:12:42 +053044 if(transient.size())
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +053045 {
Vishwanatha Subbanna4b000d82017-05-03 18:44:16 +053046 // Find common LEDs between transient and Desired to know if some LEDs
47 // are changing state and not really getting DeAsserted
48 group ledsTransient {};
49 std::set_intersection(transient.begin(),transient.end(),
50 desiredState.begin(), desiredState.end(),
51 std::inserter(ledsTransient, ledsTransient.begin()),
52 ledLess);
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +053053
Vishwanatha Subbanna4b000d82017-05-03 18:44:16 +053054 // Find difference between above 2 to identify those LEDs which are
55 // really getting DeAsserted
56 std::set_difference(transient.begin(),transient.end(),
57 ledsTransient.begin(),ledsTransient.end(),
Vishwanatha Subbanna447d0c82016-12-19 14:12:42 +053058 std::inserter(ledsDeAssert, ledsDeAssert.begin()),
Vishwanatha Subbanna4b000d82017-05-03 18:44:16 +053059 ledLess);
Vishwanatha Subbanna447d0c82016-12-19 14:12:42 +053060
Vishwanatha Subbanna4b000d82017-05-03 18:44:16 +053061 // Remove the elements from Current that are being DeAsserted.
62 if(ledsDeAssert.size())
63 {
64 // Power off LEDs that are to be really DeAsserted
65 for (auto& it:ledsDeAssert)
66 {
67 // Update LEDs in "physically asserted" set by removing those
68 // LEDs which are De-Asserted
69 auto found = currentState.find(it);
70 if (found != currentState.end())
71 {
72 currentState.erase(found);
73 }
74 }
75 }
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +053076 }
77
Vishwanatha Subbanna4b000d82017-05-03 18:44:16 +053078 // Now LEDs that are to be Asserted. These could either be fresh asserts
79 // -or- change between [On]<-->[Blink]
80 group temp {};
81 std::unique_copy(desiredState.begin(), desiredState.end(),
82 std::inserter(temp, temp.begin()),
83 ledEqual);
84 if(temp.size())
85 {
86 // Find difference between [desired to be Asserted] and those LEDs
87 // that are physically asserted currently.
88 std::set_difference(temp.begin(), temp.end(),
89 currentState.begin(), currentState.end(),
90 std::inserter(ledsAssert, ledsAssert.begin()),
91 ledComp);
92 }
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +053093
Vishwanatha Subbanna4b000d82017-05-03 18:44:16 +053094 // Update the current actual and desired(the virtual actual)
95 currentState = std::move(temp);
96 combinedState = std::move(desiredState);
Vishwanatha Subbannaed490732016-12-20 15:59:29 +053097
98 // If we survive, then set the state accordingly.
99 return assert;
100}
101
102/** @brief Run through the map and apply action on the LEDs */
Vishwanatha Subbanna4b000d82017-05-03 18:44:16 +0530103void Manager::driveLEDs(group& ledsAssert, group& ledsDeAssert)
Vishwanatha Subbannaed490732016-12-20 15:59:29 +0530104{
Alexander Soldatovf3c03412018-04-12 14:40:23 +0300105 using namespace phosphor::logging;
Vishwanatha Subbannadcc3f382017-03-24 20:15:02 +0530106 // Map of physical LED dbus paths to their Service providers
107 populateObjectMap();
108
109 if (phyLeds.empty())
110 {
111 // Error message is inside the map construction logic.
112 return;
113 }
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530114
Vishwanatha Subbannaed490732016-12-20 15:59:29 +0530115 // This order of LED operation is important.
Vishwanatha Subbannaed490732016-12-20 15:59:29 +0530116 if (ledsDeAssert.size())
117 {
Vishwanatha Subbannaed490732016-12-20 15:59:29 +0530118 for (const auto& it: ledsDeAssert)
119 {
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530120 std::string objPath = std::string(PHY_LED_PATH) + it.name;
Alexander Soldatovf3c03412018-04-12 14:40:23 +0300121 log<level::DEBUG>("De-Asserting LED", entry("NAME=%s", it.name.c_str()));
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530122 drivePhysicalLED(objPath, Layout::Action::Off, it.dutyOn);
Vishwanatha Subbannaed490732016-12-20 15:59:29 +0530123 }
124 }
125
Vishwanatha Subbanna447d0c82016-12-19 14:12:42 +0530126 if(ledsAssert.size())
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +0530127 {
Vishwanatha Subbanna447d0c82016-12-19 14:12:42 +0530128 for (const auto& it: ledsAssert)
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +0530129 {
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530130 std::string objPath = std::string(PHY_LED_PATH) + it.name;
Alexander Soldatovf3c03412018-04-12 14:40:23 +0300131 log<level::DEBUG>("Asserting LED", entry("NAME=%s", it.name.c_str()));
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530132 drivePhysicalLED(objPath, it.action, it.dutyOn);
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +0530133 }
134 }
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +0530135 return;
136}
137
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530138// Calls into driving physical LED post choosing the action
139void Manager::drivePhysicalLED(const std::string& objPath,
140 Layout::Action action,
141 uint8_t dutyOn)
142{
Vishwanatha Subbannadcc3f382017-03-24 20:15:02 +0530143 using namespace phosphor::logging;
144
145 auto service = phyLeds.find(objPath);
146 if (service == phyLeds.end() || service->second.empty())
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530147 {
Vishwanatha Subbannadcc3f382017-03-24 20:15:02 +0530148 log<level::ERR>("No service providers for physical LED",
149 entry("PATH=%s",objPath.c_str()));
150 return;
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530151 }
Vishwanatha Subbannadcc3f382017-03-24 20:15:02 +0530152
153 // If Blink, set its property
154 if (action == Layout::Action::Blink)
155 {
156 drivePhysicalLED(service->second, objPath, "DutyOn", dutyOn);
157 }
158 drivePhysicalLED(service->second, objPath, "State",
159 getPhysicalAction(action));
160 return;
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530161}
162
163/** @brief Returns action string based on enum */
Vishwanatha Subbanna4fa92482017-03-10 14:39:20 +0530164std::string Manager::getPhysicalAction(Layout::Action action)
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530165{
Vishwanatha Subbanna4fa92482017-03-10 14:39:20 +0530166 namespace server = sdbusplus::xyz::openbmc_project::Led::server;
167
168 // TODO: openbmc/phosphor-led-manager#5
169 // Somehow need to use the generated Action enum than giving one
170 // in ledlayout.
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530171 if(action == Layout::Action::On)
172 {
Vishwanatha Subbanna4fa92482017-03-10 14:39:20 +0530173 return server::convertForMessage(server::Physical::Action::On);
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530174 }
175 else if(action == Layout::Action::Blink)
176 {
Vishwanatha Subbanna4fa92482017-03-10 14:39:20 +0530177 return server::convertForMessage(server::Physical::Action::Blink);
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530178 }
179 else
180 {
Vishwanatha Subbanna4fa92482017-03-10 14:39:20 +0530181 return server::convertForMessage(server::Physical::Action::Off);
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530182 }
183}
184
Vishwanatha Subbannadcc3f382017-03-24 20:15:02 +0530185/** Populates a map with physical LED paths to its service providers */
186void Manager::populateObjectMap()
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530187{
188 using namespace phosphor::logging;
189
190 // Mapper dbus constructs
191 constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper";
Leonel Gonzalez76f58342017-03-16 13:47:52 -0500192 constexpr auto MAPPER_OBJ_PATH = "/xyz/openbmc_project/object_mapper";
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530193 constexpr auto MAPPER_IFACE = "xyz.openbmc_project.ObjectMapper";
194
Vishwanatha Subbannadcc3f382017-03-24 20:15:02 +0530195 // Needed to be passed to get the SubTree level
196 auto depth = 0;
197
198 // Clean start
199 phyLeds.clear();
200
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530201 // Make a mapper call
202 auto mapperCall = bus.new_method_call(MAPPER_BUSNAME, MAPPER_OBJ_PATH,
Vishwanatha Subbannadcc3f382017-03-24 20:15:02 +0530203 MAPPER_IFACE, "GetSubTree");
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530204 // Cook rest of the things.
Vishwanatha Subbannadcc3f382017-03-24 20:15:02 +0530205 mapperCall.append(PHY_LED_PATH);
206 mapperCall.append(depth);
207 mapperCall.append(std::vector<std::string>({PHY_LED_IFACE}));
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530208
209 auto reply = bus.call(mapperCall);
210 if (reply.is_method_error())
211 {
212 // Its okay if we do not see a corresponding physical LED.
Vishwanatha Subbannadcc3f382017-03-24 20:15:02 +0530213 log<level::INFO>("Error looking up Physical LED services",
214 entry("PATH=%s",PHY_LED_PATH));
215 return;
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530216 }
217
218 // Response by mapper in the case of success
Vishwanatha Subbannadcc3f382017-03-24 20:15:02 +0530219 std::map<std::string, std::map<std::string,
220 std::vector<std::string>>> objectTree;
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530221
Vishwanatha Subbannadcc3f382017-03-24 20:15:02 +0530222 // This is the dict of object paths - service names - interfaces
William A. Kennington III151122a2018-05-15 12:00:32 -0700223 try
224 {
225 reply.read(objectTree);
226 }
227 catch (const sdbusplus::exception::SdBusError& e)
228 {
229 log<level::ERR>("Failed to parse Physical LED service lookup",
230 entry("ERROR=%s", e.what()),
231 entry("REPLY_SIG=%s", reply.get_signature()));
232 return;
233 }
Vishwanatha Subbannadcc3f382017-03-24 20:15:02 +0530234 if (objectTree.empty())
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530235 {
Vishwanatha Subbannadcc3f382017-03-24 20:15:02 +0530236 log<level::INFO>("Physical LED lookup did not return any services",
237 entry("PATH=%s",PHY_LED_PATH));
238 return;
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530239 }
240
Vishwanatha Subbannadcc3f382017-03-24 20:15:02 +0530241 // Now construct our path -> Service name map.
242 for (const auto& iter : objectTree)
243 {
244 phyLeds.emplace(iter.first, iter.second.begin()->first);
245 }
246 return;
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530247}
248
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +0530249} // namespace led
250} // namespace phosphor