blob: 0d25877d5ffe63aa0657b2f89c5864c98991939e [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 Subbanna4c8c72b2016-11-29 23:02:06 +05305#include "manager.hpp"
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +05306namespace phosphor
7{
8namespace led
9{
10
11// Assert -or- De-assert
Vishwanatha Subbannaed490732016-12-20 15:59:29 +053012bool Manager::setGroupState(const std::string& path, bool assert,
13 group& ledsAssert, group& ledsDeAssert,
14 group& ledsUpdate)
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 Subbanna447d0c82016-12-19 14:12:42 +053036 // Has the LEDs that are either to be turned off -or- want a new assertion
37 group transient {};
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +053038 std::set_difference(currentState.begin(), currentState.end(),
39 desiredState.begin(), desiredState.end(),
Vishwanatha Subbanna447d0c82016-12-19 14:12:42 +053040 std::inserter(transient, transient.begin()));
Vishwanatha Subbanna447d0c82016-12-19 14:12:42 +053041 if(transient.size())
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +053042 {
43 // We really do not want the Manager to know how a particular LED
44 // transitions from State-A --> State-B and all this must be handled by
45 // the physical LED controller implementation.
46 // So in this case, Manager really does not want to turn off the
47 // LEDs and then turning it back on and let the physical LED controller
48 // handle that.
49
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +053050 // If we previously had a FRU in ON state , and then if there was a
51 // request to make it blink, the end state would now be blink.
52 // If we either turn off blink / fault, then we need to go back to its
53 // previous state.
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +053054 std::set_intersection(desiredState.begin(), desiredState.end(),
Vishwanatha Subbanna447d0c82016-12-19 14:12:42 +053055 transient.begin(), transient.end(),
56 std::inserter(ledsUpdate, ledsUpdate.begin()),
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +053057 ledComp);
58
Vishwanatha Subbanna447d0c82016-12-19 14:12:42 +053059 // These LEDs are only to be De-Asserted.
Vishwanatha Subbanna447d0c82016-12-19 14:12:42 +053060 std::set_difference(transient.begin(), transient.end(),
61 ledsUpdate.begin(), ledsUpdate.end(),
62 std::inserter(ledsDeAssert, ledsDeAssert.begin()),
63 ledComp);
64
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +053065 }
66
67 // Turn on these
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +053068 std::set_difference(desiredState.begin(), desiredState.end(),
69 currentState.begin(), currentState.end(),
Vishwanatha Subbanna447d0c82016-12-19 14:12:42 +053070 std::inserter(ledsAssert, ledsAssert.begin()));
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +053071
Vishwanatha Subbannaed490732016-12-20 15:59:29 +053072
73 // Done.. Save the latest and greatest.
74 currentState = std::move(desiredState);
75
76 // If we survive, then set the state accordingly.
77 return assert;
78}
79
80/** @brief Run through the map and apply action on the LEDs */
81void Manager::driveLEDs(group& ledsAssert, group& ledsDeAssert,
82 group& ledsUpdate)
83{
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +053084 // For now, physical LED is driven by xyz.openbmc_project.Led.Controller
85 // at /xyz/openbmc_project/led/physical. However, its possible that in the
86 // future, the physical LEDs are driven by different dbus services.
87 // when that happens, service name needs to be obtained everytime a
88 // particular LED would be targeted as opposed to getting one now and then
89 // using it for all
90
Vishwanatha Subbannaed490732016-12-20 15:59:29 +053091 // This order of LED operation is important.
92 if (ledsUpdate.size())
93 {
94 std::cout << "Updating LED states between (On <--> Blink)"
95 << std::endl;
96 for (const auto& it: ledsUpdate)
97 {
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +053098 std::string objPath = std::string(PHY_LED_PATH) + it.name;
99 drivePhysicalLED(objPath, it.action, it.dutyOn);
Vishwanatha Subbannaed490732016-12-20 15:59:29 +0530100 }
101 }
102
103 if (ledsDeAssert.size())
104 {
105 std::cout << "De-Asserting LEDs" << std::endl;
106 for (const auto& it: ledsDeAssert)
107 {
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530108 std::string objPath = std::string(PHY_LED_PATH) + it.name;
109 drivePhysicalLED(objPath, Layout::Action::Off, it.dutyOn);
Vishwanatha Subbannaed490732016-12-20 15:59:29 +0530110 }
111 }
112
Vishwanatha Subbanna447d0c82016-12-19 14:12:42 +0530113 if(ledsAssert.size())
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +0530114 {
115 std::cout << "Asserting LEDs" << std::endl;
Vishwanatha Subbanna447d0c82016-12-19 14:12:42 +0530116 for (const auto& it: ledsAssert)
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +0530117 {
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530118 std::string objPath = std::string(PHY_LED_PATH) + it.name;
119 drivePhysicalLED(objPath, it.action, it.dutyOn);
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +0530120 }
121 }
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +0530122 return;
123}
124
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530125// Calls into driving physical LED post choosing the action
126void Manager::drivePhysicalLED(const std::string& objPath,
127 Layout::Action action,
128 uint8_t dutyOn)
129{
130 auto service = getServiceName(objPath, PHY_LED_IFACE);
131 if (!service.empty())
132 {
133 // If Blink, set its property
134 if (action == Layout::Action::Blink)
135 {
136 drivePhysicalLED(service, objPath, "DutyOn", dutyOn);
137 }
138 drivePhysicalLED(service, objPath, "State",
139 getPhysicalAction(action));
140 }
141}
142
143/** @brief Returns action string based on enum */
144const char* const Manager::getPhysicalAction(Layout::Action action)
145{
146 // TODO : When this is moved over to using libdus interfaces, this code will
147 // away. https://github.com/openbmc/phosphor-led-manager/issues/2
148 if(action == Layout::Action::On)
149 {
150 return "xyz.openbmc_project.Led.Physical.Action.On";
151 }
152 else if(action == Layout::Action::Blink)
153 {
154 return "xyz.openbmc_project.Led.Physical.Action.Blink";
155 }
156 else
157 {
158 return "xyz.openbmc_project.Led.Physical.Action.Off";
159 }
160}
161
162/** Given the LED dbus path and interface, returns the service name */
163std::string Manager::getServiceName(const std::string& objPath,
164 const std::string& interface) const
165{
166 using namespace phosphor::logging;
167
168 // Mapper dbus constructs
169 constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper";
Leonel Gonzalez76f58342017-03-16 13:47:52 -0500170 constexpr auto MAPPER_OBJ_PATH = "/xyz/openbmc_project/object_mapper";
Vishwanatha Subbanna11ca8f92017-02-27 19:33:45 +0530171 constexpr auto MAPPER_IFACE = "xyz.openbmc_project.ObjectMapper";
172
173 // Make a mapper call
174 auto mapperCall = bus.new_method_call(MAPPER_BUSNAME, MAPPER_OBJ_PATH,
175 MAPPER_IFACE, "GetObject");
176 // Cook rest of the things.
177 mapperCall.append(objPath);
178 mapperCall.append(std::vector<std::string>({interface}));
179
180 auto reply = bus.call(mapperCall);
181 if (reply.is_method_error())
182 {
183 // Its okay if we do not see a corresponding physical LED.
184 log<level::INFO>("Error looking up Physical LED service",
185 entry("PATH=%s",objPath.c_str()));
186 return "";
187 }
188
189 // Response by mapper in the case of success
190 std::map<std::string, std::vector<std::string>> serviceNames;
191
192 // This is the service name for the passed in objpath
193 reply.read(serviceNames);
194 if (serviceNames.empty())
195 {
196 log<level::INFO>("Physical LED lookup did not return any service",
197 entry("PATH=%s",objPath.c_str()));
198 return "";
199 }
200
201 return serviceNames.begin()->first;
202}
203
Vishwanatha Subbanna4c8c72b2016-11-29 23:02:06 +0530204} // namespace led
205} // namespace phosphor