Add methods to driving the LEDs
This enables creating custom groups and participating LEDs so that
it can later be generated from MRW. For each of the group, a dbus object
is created which will announce LED actions. Corresponding groups are
asserted / de-asserted based on user input.
Change-Id: I7e64bea13767b8d083dd946f4cf3aeb37e62ff17
Signed-off-by: Vishwanatha Subbanna <vishwa@linux.vnet.ibm.com>
diff --git a/led-manager.cpp b/led-manager.cpp
index 8bc1751..bfbf426 100644
--- a/led-manager.cpp
+++ b/led-manager.cpp
@@ -1,17 +1,19 @@
#include <iostream>
#include <cstring>
+#include <algorithm>
#include <sdbusplus/vtable.hpp>
#include <sdbusplus/message.hpp>
#include <sdbusplus/bus.hpp>
#include "led-manager.hpp"
#include "led-gen.hpp"
-
namespace phosphor
{
-
namespace led
{
+std::set<const Group::group*> Group::assertedGroups;
+Group::group Group::currentState;
+
/** @brief Called when the group's property is read
* Signature as needed by sd_bus
*/
@@ -19,16 +21,10 @@
const char *property, sd_bus_message *reply,
void *data, sd_bus_error* error)
{
- auto group = strrchr(path, '/');
- if (group)
- {
- // Removing the starting '/' in /group
- group++;
- }
+ auto ledMgr = static_cast<Group*>(data);
+ auto state = ledMgr->getGroupState(path);
- //TODO : Need to see how to represent group specific asserted state
- // May be a new tuple / map ?
- sd_bus_message_append(reply, "b", 0);
+ sd_bus_message_append(reply, "b", state);
return 0;
}
@@ -40,49 +36,135 @@
void *data, sd_bus_error* error)
{
bool state {};
- auto group = strrchr(path, '/');
- if (group)
- {
- // Removing the starting '/' in /group
- group++;
- }
-
auto msg = sdbusplus::message::message(value);
sd_bus_message_ref(value);
msg.read(state);
- //TODO : Need to see how to represent group specific asserted state
- // May be a new tuple / map ?
- return 1;
+ auto ledMgr = static_cast<Group*>(data);
+ return ledMgr->setGroupState(path, state);
}
-/** @brief Users having to assert a group will just turn this property to 1
- * similarly, setting this property to 0 will deassert the group
+// Get the asserted state
+bool Group::getGroupState(const std::string& path)
+{
+ return assertedGroups.find(&ledMap.at(path)) != assertedGroups.end();
+}
+
+// Assert -or- De-assert
+int Group::setGroupState(const std::string& path, bool assert)
+{
+ if (assert)
+ {
+ assertedGroups.insert(&ledMap.at(path));
+ }
+ else
+ {
+ auto search = assertedGroups.find(&ledMap.at(path));
+ if (search != assertedGroups.end())
+ {
+ assertedGroups.erase(&ledMap.at(path));
+ }
+ else
+ {
+ std::cout << "Group [ " << path << " ] Not present\n";
+ }
+ }
+ return driveLEDs();
+}
+
+// Run through the map and apply action
+int Group::driveLEDs()
+{
+ // This will contain the union of what's already in the asserted group
+ group desiredState {};
+ for(const auto& grp : assertedGroups)
+ {
+ desiredState.insert(grp->cbegin(), grp->cend());
+ }
+
+ // Always Do execute Turn Off and then Turn on since we have the Blink
+ // taking priority over -on-
+ group ledsToDeAssert {};
+
+ std::set_difference(currentState.begin(), currentState.end(),
+ desiredState.begin(), desiredState.end(),
+ std::inserter(ledsToDeAssert, ledsToDeAssert.begin()));
+ if(ledsToDeAssert.size())
+ {
+ // We really do not want the Group Manager to know how a particular LED
+ // transitions from State-A --> State-B and all this must be handled by
+ // the physical LED controller implementation.
+ // So in this case, Group Manager really does not want to turn off the
+ // LEDs and then turning it back on and let the physical LED controller
+ // handle that.
+
+ // If we previously had a FRU in ON state , and then if there was a
+ // request to make it blink, the end state would now be blink.
+ // If we either turn off blink / fault, then we need to go back to its
+ // previous state.
+ group ledsToReAssert {};
+ std::set_intersection(desiredState.begin(), desiredState.end(),
+ ledsToDeAssert.begin(), ledsToDeAssert.end(),
+ std::inserter(ledsToReAssert, ledsToReAssert.begin()),
+ ledComp);
+
+ if (ledsToReAssert.size())
+ {
+ std::cout << "Asserting LEDs again" << std::endl;
+ for (const auto& it: ledsToReAssert)
+ {
+ std::cout << "\t{" << it.name << "::" << it.action << "}"
+ << std::endl;
+ }
+ }
+ }
+
+ // Turn on these
+ group ledsToAssert {};
+ std::set_difference(desiredState.begin(), desiredState.end(),
+ currentState.begin(), currentState.end(),
+ std::inserter(ledsToAssert, ledsToAssert.begin()));
+
+ if(ledsToAssert.size())
+ {
+ std::cout << "Asserting LEDs" << std::endl;
+ for (const auto& it: ledsToAssert)
+ {
+ std::cout << "\t{" << it.name << "::" << it.action << "}"
+ << std::endl;
+ }
+ }
+
+ // Done.. Save the latest and greatest.
+ currentState = std::move(desiredState);
+
+ return 0;
+}
+
+/** @brief Users having to assert a group will just turn this property to TRUE
+ * similarly, setting this property to FALSE will deassert the group
*/
constexpr sdbusplus::vtable::vtable_t led_vtable[] =
{
sdbusplus::vtable::start(),
- sdbusplus::vtable::property("Assert", "b",
- getGroupState, setGroupState, sdbusplus::vtable::property_::emits_change),
- sdbusplus::vtable::end()
+ sdbusplus::vtable::property("Asserted", "b",
+ getGroupState, setGroupState,
+ sdbusplus::vtable::property_::emits_change),
+ sdbusplus::vtable::end()
};
/** @brief Initialize the bus and announce services */
-Manager::Manager(const char* busName,
- const char* objPath,
- const char* intfName) :
- iv_bus(sdbusplus::bus::new_system()),
- objManager(iv_bus, objPath)
+Group::Group(const char* busName,
+ const char* objPath,
+ const char* intfName) :
+ bus(sdbusplus::bus::new_system()),
+ objManager(bus, objPath)
{
- // Like /org/openbmc/ledmanager/groups/
- auto path = std::string(objPath) + "/";
-
/** Now create so many dbus objects as there are groups */
- for (auto &grp: Manager::cv_LedMap)
+ for (auto &grp: Group::ledMap)
{
- auto grpPath = path + grp.first;
- intfContainer.emplace_back(sdbusplus::server::interface::interface(
- iv_bus, grpPath.c_str(), intfName, led_vtable, this));
+ intfContainer.emplace_back(bus, grp.first.c_str(),
+ intfName, led_vtable, this);
// These are now set of structs having LED name and the action. Do not
// have anything to be done here at the moment but need to create a
@@ -94,18 +176,18 @@
}
// Once done, claim the bus and systemd will
// consider this service started
- iv_bus.request_name(busName);
+ bus.request_name(busName);
}
/** @brief Wait for client requests */
-void Manager::run()
+void Group::run()
{
while(true)
{
try
{
- iv_bus.process_discard();
- iv_bus.wait();
+ bus.process_discard();
+ bus.wait();
}
catch (std::exception &e)
{