blob: 77ba546dc79c500d41573c5e5fdca2a9744997ac [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{
Vishwanatha Subbannadcc3f382017-03-24 20:15:02 +0530104 // Map of physical LED dbus paths to their Service providers
105 populateObjectMap();
106
107 if (phyLeds.empty())
108 {
109 // Error message is inside the map construction logic.
110 return;
111 }
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530112
Vishwanatha Subbannaed490732016-12-20 15:59:29 +0530113 // This order of LED operation is important.
Vishwanatha Subbannaed490732016-12-20 15:59:29 +0530114 if (ledsDeAssert.size())
115 {
116 std::cout << "De-Asserting LEDs" << std::endl;
117 for (const auto& it: ledsDeAssert)
118 {
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530119 std::string objPath = std::string(PHY_LED_PATH) + it.name;
120 drivePhysicalLED(objPath, Layout::Action::Off, it.dutyOn);
Vishwanatha Subbannaed490732016-12-20 15:59:29 +0530121 }
122 }
123
Vishwanatha Subbanna447d0c82016-12-19 14:12:42 +0530124 if(ledsAssert.size())
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +0530125 {
126 std::cout << "Asserting LEDs" << std::endl;
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;
130 drivePhysicalLED(objPath, it.action, it.dutyOn);
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +0530131 }
132 }
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +0530133 return;
134}
135
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530136// Calls into driving physical LED post choosing the action
137void Manager::drivePhysicalLED(const std::string& objPath,
138 Layout::Action action,
139 uint8_t dutyOn)
140{
Vishwanatha Subbannadcc3f382017-03-24 20:15:02 +0530141 using namespace phosphor::logging;
142
143 auto service = phyLeds.find(objPath);
144 if (service == phyLeds.end() || service->second.empty())
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530145 {
Vishwanatha Subbannadcc3f382017-03-24 20:15:02 +0530146 log<level::ERR>("No service providers for physical LED",
147 entry("PATH=%s",objPath.c_str()));
148 return;
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530149 }
Vishwanatha Subbannadcc3f382017-03-24 20:15:02 +0530150
151 // If Blink, set its property
152 if (action == Layout::Action::Blink)
153 {
154 drivePhysicalLED(service->second, objPath, "DutyOn", dutyOn);
155 }
156 drivePhysicalLED(service->second, objPath, "State",
157 getPhysicalAction(action));
158 return;
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530159}
160
161/** @brief Returns action string based on enum */
Vishwanatha Subbanna4fa92482017-03-10 14:39:20 +0530162std::string Manager::getPhysicalAction(Layout::Action action)
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530163{
Vishwanatha Subbanna4fa92482017-03-10 14:39:20 +0530164 namespace server = sdbusplus::xyz::openbmc_project::Led::server;
165
166 // TODO: openbmc/phosphor-led-manager#5
167 // Somehow need to use the generated Action enum than giving one
168 // in ledlayout.
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530169 if(action == Layout::Action::On)
170 {
Vishwanatha Subbanna4fa92482017-03-10 14:39:20 +0530171 return server::convertForMessage(server::Physical::Action::On);
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530172 }
173 else if(action == Layout::Action::Blink)
174 {
Vishwanatha Subbanna4fa92482017-03-10 14:39:20 +0530175 return server::convertForMessage(server::Physical::Action::Blink);
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530176 }
177 else
178 {
Vishwanatha Subbanna4fa92482017-03-10 14:39:20 +0530179 return server::convertForMessage(server::Physical::Action::Off);
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530180 }
181}
182
Vishwanatha Subbannadcc3f382017-03-24 20:15:02 +0530183/** Populates a map with physical LED paths to its service providers */
184void Manager::populateObjectMap()
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530185{
186 using namespace phosphor::logging;
187
188 // Mapper dbus constructs
189 constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper";
Leonel Gonzalez76f58342017-03-16 13:47:52 -0500190 constexpr auto MAPPER_OBJ_PATH = "/xyz/openbmc_project/object_mapper";
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530191 constexpr auto MAPPER_IFACE = "xyz.openbmc_project.ObjectMapper";
192
Vishwanatha Subbannadcc3f382017-03-24 20:15:02 +0530193 // Needed to be passed to get the SubTree level
194 auto depth = 0;
195
196 // Clean start
197 phyLeds.clear();
198
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530199 // Make a mapper call
200 auto mapperCall = bus.new_method_call(MAPPER_BUSNAME, MAPPER_OBJ_PATH,
Vishwanatha Subbannadcc3f382017-03-24 20:15:02 +0530201 MAPPER_IFACE, "GetSubTree");
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530202 // Cook rest of the things.
Vishwanatha Subbannadcc3f382017-03-24 20:15:02 +0530203 mapperCall.append(PHY_LED_PATH);
204 mapperCall.append(depth);
205 mapperCall.append(std::vector<std::string>({PHY_LED_IFACE}));
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530206
207 auto reply = bus.call(mapperCall);
208 if (reply.is_method_error())
209 {
210 // Its okay if we do not see a corresponding physical LED.
Vishwanatha Subbannadcc3f382017-03-24 20:15:02 +0530211 log<level::INFO>("Error looking up Physical LED services",
212 entry("PATH=%s",PHY_LED_PATH));
213 return;
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530214 }
215
216 // Response by mapper in the case of success
Vishwanatha Subbannadcc3f382017-03-24 20:15:02 +0530217 std::map<std::string, std::map<std::string,
218 std::vector<std::string>>> objectTree;
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530219
Vishwanatha Subbannadcc3f382017-03-24 20:15:02 +0530220 // This is the dict of object paths - service names - interfaces
221 reply.read(objectTree);
222 if (objectTree.empty())
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530223 {
Vishwanatha Subbannadcc3f382017-03-24 20:15:02 +0530224 log<level::INFO>("Physical LED lookup did not return any services",
225 entry("PATH=%s",PHY_LED_PATH));
226 return;
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530227 }
228
Vishwanatha Subbannadcc3f382017-03-24 20:15:02 +0530229 // Now construct our path -> Service name map.
230 for (const auto& iter : objectTree)
231 {
232 phyLeds.emplace(iter.first, iter.second.begin()->first);
233 }
234 return;
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530235}
236
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +0530237} // namespace led
238} // namespace phosphor