summaryrefslogtreecommitdiffstats
path: root/led-manager.cpp
blob: bfbf426ec8bf3fb053d66e3ac900f89044fc1275 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
#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
 */
int getGroupState(sd_bus *bus, const char *path, const char *interface,
                  const char *property, sd_bus_message *reply,
                  void *data, sd_bus_error* error)
{
    auto ledMgr = static_cast<Group*>(data);
    auto state = ledMgr->getGroupState(path);

    sd_bus_message_append(reply, "b", state);
    return 0;
}

/** @brief Called when the group's asserted state is updated
 *         Signature as needed by sd_bus
 */
int setGroupState(sd_bus *bus, const char *path, const char *interface,
                  const char *property, sd_bus_message *value,
                  void *data, sd_bus_error* error)
{
    bool state {};
    auto msg = sdbusplus::message::message(value);
    sd_bus_message_ref(value);
    msg.read(state);

    auto ledMgr = static_cast<Group*>(data);
    return ledMgr->setGroupState(path, state);
}

// 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("Asserted", "b",
                                getGroupState, setGroupState,
                                sdbusplus::vtable::property_::emits_change),
                                sdbusplus::vtable::end()
};

/** @brief Initialize the bus and announce services */
Group::Group(const char* busName,
             const char* objPath,
             const char* intfName) :
    bus(sdbusplus::bus::new_system()),
    objManager(bus, objPath)
{
    /** Now create so many dbus objects as there are groups */
    for (auto &grp: Group::ledMap)
    {
        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
        // mapping between led names to device strigs eventually
        //for (auto &set: grp.second)
        //{

        //}
    }
    // Once done, claim the bus and systemd will
    // consider this service started
    bus.request_name(busName);
}

/** @brief Wait for client requests */
void Group::run()
{
    while(true)
    {
        try
        {
            bus.process_discard();
            bus.wait();
        }
        catch (std::exception &e)
        {
            std::cerr << e.what() << std::endl;
        }
    }
}

} // namespace led

} // namespace phosphor
OpenPOWER on IntegriCloud