blob: 69d82b08f2d3162cda6ba56fb55f2dda9abfe6d0 [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>
Vishwanatha Subbanna4fa92482017-03-10 14:39:20 +05305#include <xyz/openbmc_project/Led/Physical/server.hpp>
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +05306#include "manager.hpp"
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +05307namespace phosphor
8{
9namespace led
10{
11
12// Assert -or- De-assert
Vishwanatha Subbannaed490732016-12-20 15:59:29 +053013bool Manager::setGroupState(const std::string& path, bool assert,
Vishwanatha Subbanna4b000d82017-05-03 18:44:16 +053014 group& ledsAssert, group& ledsDeAssert)
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +053015{
16 if (assert)
17 {
18 assertedGroups.insert(&ledMap.at(path));
19 }
20 else
21 {
22 auto search = assertedGroups.find(&ledMap.at(path));
23 if (search != assertedGroups.end())
24 {
25 assertedGroups.erase(&ledMap.at(path));
26 }
27 }
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +053028
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +053029 // This will contain the union of what's already in the asserted group
30 group desiredState {};
31 for(const auto& grp : assertedGroups)
32 {
33 desiredState.insert(grp->cbegin(), grp->cend());
34 }
35
Vishwanatha Subbanna4b000d82017-05-03 18:44:16 +053036 // Find difference between Combined and Desired to identify
37 // which LEDs are getting altered
Vishwanatha Subbanna447d0c82016-12-19 14:12:42 +053038 group transient {};
Vishwanatha Subbanna4b000d82017-05-03 18:44:16 +053039 std::set_difference(combinedState.begin(), combinedState.end(),
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +053040 desiredState.begin(), desiredState.end(),
Vishwanatha Subbannacd569d22017-05-03 12:46:14 +053041 std::inserter(transient, transient.begin()),
42 ledComp);
Vishwanatha Subbanna447d0c82016-12-19 14:12:42 +053043 if(transient.size())
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +053044 {
Vishwanatha Subbanna4b000d82017-05-03 18:44:16 +053045 // Find common LEDs between transient and Desired to know if some LEDs
46 // are changing state and not really getting DeAsserted
47 group ledsTransient {};
48 std::set_intersection(transient.begin(),transient.end(),
49 desiredState.begin(), desiredState.end(),
50 std::inserter(ledsTransient, ledsTransient.begin()),
51 ledLess);
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +053052
Vishwanatha Subbanna4b000d82017-05-03 18:44:16 +053053 // Find difference between above 2 to identify those LEDs which are
54 // really getting DeAsserted
55 std::set_difference(transient.begin(),transient.end(),
56 ledsTransient.begin(),ledsTransient.end(),
Vishwanatha Subbanna447d0c82016-12-19 14:12:42 +053057 std::inserter(ledsDeAssert, ledsDeAssert.begin()),
Vishwanatha Subbanna4b000d82017-05-03 18:44:16 +053058 ledLess);
Vishwanatha Subbanna447d0c82016-12-19 14:12:42 +053059
Vishwanatha Subbanna4b000d82017-05-03 18:44:16 +053060 // Remove the elements from Current that are being DeAsserted.
61 if(ledsDeAssert.size())
62 {
63 // Power off LEDs that are to be really DeAsserted
64 for (auto& it:ledsDeAssert)
65 {
66 // Update LEDs in "physically asserted" set by removing those
67 // LEDs which are De-Asserted
68 auto found = currentState.find(it);
69 if (found != currentState.end())
70 {
71 currentState.erase(found);
72 }
73 }
74 }
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +053075 }
76
Vishwanatha Subbanna4b000d82017-05-03 18:44:16 +053077 // Now LEDs that are to be Asserted. These could either be fresh asserts
78 // -or- change between [On]<-->[Blink]
79 group temp {};
80 std::unique_copy(desiredState.begin(), desiredState.end(),
81 std::inserter(temp, temp.begin()),
82 ledEqual);
83 if(temp.size())
84 {
85 // Find difference between [desired to be Asserted] and those LEDs
86 // that are physically asserted currently.
87 std::set_difference(temp.begin(), temp.end(),
88 currentState.begin(), currentState.end(),
89 std::inserter(ledsAssert, ledsAssert.begin()),
90 ledComp);
91 }
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 {
Vishwanatha Subbannaed490732016-12-20 15:59:29 +0530117 for (const auto& it: ledsDeAssert)
118 {
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530119 std::string objPath = std::string(PHY_LED_PATH) + it.name;
Alexander Soldatovf3c03412018-04-12 14:40:23 +0300120 log<level::DEBUG>("De-Asserting LED", entry("NAME=%s", it.name.c_str()));
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530121 drivePhysicalLED(objPath, Layout::Action::Off, it.dutyOn);
Vishwanatha Subbannaed490732016-12-20 15:59:29 +0530122 }
123 }
124
Vishwanatha Subbanna447d0c82016-12-19 14:12:42 +0530125 if(ledsAssert.size())
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +0530126 {
Vishwanatha Subbanna447d0c82016-12-19 14:12:42 +0530127 for (const auto& it: ledsAssert)
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +0530128 {
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530129 std::string objPath = std::string(PHY_LED_PATH) + it.name;
Alexander Soldatovf3c03412018-04-12 14:40:23 +0300130 log<level::DEBUG>("Asserting LED", entry("NAME=%s", it.name.c_str()));
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530131 drivePhysicalLED(objPath, it.action, it.dutyOn);
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +0530132 }
133 }
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +0530134 return;
135}
136
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530137// Calls into driving physical LED post choosing the action
138void Manager::drivePhysicalLED(const std::string& objPath,
139 Layout::Action action,
140 uint8_t dutyOn)
141{
Vishwanatha Subbannadcc3f382017-03-24 20:15:02 +0530142 using namespace phosphor::logging;
143
144 auto service = phyLeds.find(objPath);
145 if (service == phyLeds.end() || service->second.empty())
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530146 {
Vishwanatha Subbannadcc3f382017-03-24 20:15:02 +0530147 log<level::ERR>("No service providers for physical LED",
148 entry("PATH=%s",objPath.c_str()));
149 return;
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530150 }
Vishwanatha Subbannadcc3f382017-03-24 20:15:02 +0530151
152 // If Blink, set its property
153 if (action == Layout::Action::Blink)
154 {
155 drivePhysicalLED(service->second, objPath, "DutyOn", dutyOn);
156 }
157 drivePhysicalLED(service->second, objPath, "State",
158 getPhysicalAction(action));
159 return;
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530160}
161
162/** @brief Returns action string based on enum */
Vishwanatha Subbanna4fa92482017-03-10 14:39:20 +0530163std::string Manager::getPhysicalAction(Layout::Action action)
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530164{
Vishwanatha Subbanna4fa92482017-03-10 14:39:20 +0530165 namespace server = sdbusplus::xyz::openbmc_project::Led::server;
166
167 // TODO: openbmc/phosphor-led-manager#5
168 // Somehow need to use the generated Action enum than giving one
169 // in ledlayout.
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530170 if(action == Layout::Action::On)
171 {
Vishwanatha Subbanna4fa92482017-03-10 14:39:20 +0530172 return server::convertForMessage(server::Physical::Action::On);
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530173 }
174 else if(action == Layout::Action::Blink)
175 {
Vishwanatha Subbanna4fa92482017-03-10 14:39:20 +0530176 return server::convertForMessage(server::Physical::Action::Blink);
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530177 }
178 else
179 {
Vishwanatha Subbanna4fa92482017-03-10 14:39:20 +0530180 return server::convertForMessage(server::Physical::Action::Off);
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530181 }
182}
183
Vishwanatha Subbannadcc3f382017-03-24 20:15:02 +0530184/** Populates a map with physical LED paths to its service providers */
185void Manager::populateObjectMap()
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530186{
187 using namespace phosphor::logging;
188
189 // Mapper dbus constructs
190 constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper";
Leonel Gonzalez76f58342017-03-16 13:47:52 -0500191 constexpr auto MAPPER_OBJ_PATH = "/xyz/openbmc_project/object_mapper";
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530192 constexpr auto MAPPER_IFACE = "xyz.openbmc_project.ObjectMapper";
193
Vishwanatha Subbannadcc3f382017-03-24 20:15:02 +0530194 // Needed to be passed to get the SubTree level
195 auto depth = 0;
196
197 // Clean start
198 phyLeds.clear();
199
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530200 // Make a mapper call
201 auto mapperCall = bus.new_method_call(MAPPER_BUSNAME, MAPPER_OBJ_PATH,
Vishwanatha Subbannadcc3f382017-03-24 20:15:02 +0530202 MAPPER_IFACE, "GetSubTree");
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530203 // Cook rest of the things.
Vishwanatha Subbannadcc3f382017-03-24 20:15:02 +0530204 mapperCall.append(PHY_LED_PATH);
205 mapperCall.append(depth);
206 mapperCall.append(std::vector<std::string>({PHY_LED_IFACE}));
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530207
208 auto reply = bus.call(mapperCall);
209 if (reply.is_method_error())
210 {
211 // Its okay if we do not see a corresponding physical LED.
Vishwanatha Subbannadcc3f382017-03-24 20:15:02 +0530212 log<level::INFO>("Error looking up Physical LED services",
213 entry("PATH=%s",PHY_LED_PATH));
214 return;
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530215 }
216
217 // Response by mapper in the case of success
Vishwanatha Subbannadcc3f382017-03-24 20:15:02 +0530218 std::map<std::string, std::map<std::string,
219 std::vector<std::string>>> objectTree;
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530220
Vishwanatha Subbannadcc3f382017-03-24 20:15:02 +0530221 // This is the dict of object paths - service names - interfaces
222 reply.read(objectTree);
223 if (objectTree.empty())
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530224 {
Vishwanatha Subbannadcc3f382017-03-24 20:15:02 +0530225 log<level::INFO>("Physical LED lookup did not return any services",
226 entry("PATH=%s",PHY_LED_PATH));
227 return;
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530228 }
229
Vishwanatha Subbannadcc3f382017-03-24 20:15:02 +0530230 // Now construct our path -> Service name map.
231 for (const auto& iter : objectTree)
232 {
233 phyLeds.emplace(iter.first, iter.second.begin()->first);
234 }
235 return;
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530236}
237
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +0530238} // namespace led
239} // namespace phosphor