xref: /openbmc/bmcweb/features/redfish/lib/led.hpp (revision 2eaa9279866425cbc463529d72d522f0f32caf1f)
1 // SPDX-License-Identifier: Apache-2.0
2 // SPDX-FileCopyrightText: Copyright OpenBMC Authors
3 // SPDX-FileCopyrightText: Copyright 2019 Intel Corporation
4 #pragma once
5 
6 #include "async_resp.hpp"
7 #include "dbus_singleton.hpp"
8 #include "dbus_utility.hpp"
9 #include "error_messages.hpp"
10 #include "generated/enums/chassis.hpp"
11 #include "logging.hpp"
12 #include "utils/dbus_utils.hpp"
13 
14 #include <asm-generic/errno.h>
15 
16 #include <boost/system/error_code.hpp>
17 #include <sdbusplus/asio/property.hpp>
18 #include <sdbusplus/message/native_types.hpp>
19 
20 #include <array>
21 #include <functional>
22 #include <memory>
23 #include <string>
24 #include <string_view>
25 #include <utility>
26 
27 namespace redfish
28 {
29 static constexpr std::array<std::string_view, 1> ledGroupInterface = {
30     "xyz.openbmc_project.Led.Group"};
31 /**
32  * @brief Retrieves identify led group properties over dbus
33  *
34  * @param[in] asyncResp     Shared pointer for generating response message.
35  *
36  * @return None.
37  */
38 // TODO (Gunnar): Remove IndicatorLED after enough time has passed
39 inline void getIndicatorLedState(
40     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
41 {
42     BMCWEB_LOG_DEBUG("Get led groups");
43     dbus::utility::getProperty<bool>(
44         "xyz.openbmc_project.LED.GroupManager",
45         "/xyz/openbmc_project/led/groups/enclosure_identify_blink",
46         "xyz.openbmc_project.Led.Group", "Asserted",
47         [asyncResp](const boost::system::error_code& ec, const bool blinking) {
48             // Some systems may not have enclosure_identify_blink object so
49             // proceed to get enclosure_identify state.
50             if (ec == boost::system::errc::invalid_argument)
51             {
52                 BMCWEB_LOG_DEBUG(
53                     "Get identity blinking LED failed, mismatch in property type");
54                 messages::internalError(asyncResp->res);
55                 return;
56             }
57 
58             // Blinking ON, no need to check enclosure_identify assert.
59             if (!ec && blinking)
60             {
61                 asyncResp->res.jsonValue["IndicatorLED"] =
62                     chassis::IndicatorLED::Blinking;
63                 return;
64             }
65 
66             dbus::utility::getProperty<bool>(
67                 "xyz.openbmc_project.LED.GroupManager",
68                 "/xyz/openbmc_project/led/groups/enclosure_identify",
69                 "xyz.openbmc_project.Led.Group", "Asserted",
70                 [asyncResp](const boost::system::error_code& ec2,
71                             const bool ledOn) {
72                     if (ec2 == boost::system::errc::invalid_argument)
73                     {
74                         BMCWEB_LOG_DEBUG(
75                             "Get enclosure identity led failed, mismatch in property type");
76                         messages::internalError(asyncResp->res);
77                         return;
78                     }
79 
80                     if (ec2)
81                     {
82                         return;
83                     }
84 
85                     if (ledOn)
86                     {
87                         asyncResp->res.jsonValue["IndicatorLED"] =
88                             chassis::IndicatorLED::Lit;
89                     }
90                     else
91                     {
92                         asyncResp->res.jsonValue["IndicatorLED"] =
93                             chassis::IndicatorLED::Off;
94                     }
95                 });
96         });
97 }
98 
99 /**
100  * @brief Sets identify led group properties
101  *
102  * @param[in] asyncResp     Shared pointer for generating response message.
103  * @param[in] ledState  LED state passed from request
104  *
105  * @return None.
106  */
107 // TODO (Gunnar): Remove IndicatorLED after enough time has passed
108 inline void setIndicatorLedState(
109     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
110     const std::string& ledState)
111 {
112     BMCWEB_LOG_DEBUG("Set led groups");
113     bool ledOn = false;
114     bool ledBlinkng = false;
115 
116     if (ledState == "Lit")
117     {
118         ledOn = true;
119     }
120     else if (ledState == "Blinking")
121     {
122         ledBlinkng = true;
123     }
124     else if (ledState != "Off")
125     {
126         messages::propertyValueNotInList(asyncResp->res, ledState,
127                                          "IndicatorLED");
128         return;
129     }
130 
131     sdbusplus::asio::setProperty(
132         *crow::connections::systemBus, "xyz.openbmc_project.LED.GroupManager",
133         "/xyz/openbmc_project/led/groups/enclosure_identify_blink",
134         "xyz.openbmc_project.Led.Group", "Asserted", ledBlinkng,
135         [asyncResp, ledOn,
136          ledBlinkng](const boost::system::error_code& ec) mutable {
137             if (ec)
138             {
139                 // Some systems may not have enclosure_identify_blink object so
140                 // Lets set enclosure_identify state to true if Blinking is
141                 // true.
142                 if (ledBlinkng)
143                 {
144                     ledOn = true;
145                 }
146             }
147             setDbusProperty(
148                 asyncResp, "IndicatorLED",
149                 "xyz.openbmc_project.LED.GroupManager",
150                 sdbusplus::message::object_path(
151                     "/xyz/openbmc_project/led/groups/enclosure_identify"),
152                 "xyz.openbmc_project.Led.Group", "Asserted", ledBlinkng);
153         });
154 }
155 
156 inline void handleLedGroupSubtree(
157     const std::string& objPath, const boost::system::error_code& ec,
158     const dbus::utility::MapperGetSubTreeResponse& subtree,
159     const std::function<void(const boost::system::error_code& ec,
160                              const std::string& ledGroupPath,
161                              const std::string& service)>& callback)
162 {
163     if (ec)
164     {
165         // Callback will handle the error
166         callback(ec, "", "");
167         return;
168     }
169 
170     if (subtree.empty())
171     {
172         // Callback will handle the error
173         BMCWEB_LOG_DEBUG(
174             "No LED group associated with the specified object path: {}",
175             objPath);
176         callback(ec, "", "");
177         return;
178     }
179 
180     if (subtree.size() > 1)
181     {
182         // Callback will handle the error
183         BMCWEB_LOG_DEBUG(
184             "More than one LED group associated with the object {}: {}",
185             objPath, subtree.size());
186         callback(ec, "", "");
187         return;
188     }
189 
190     const auto& [ledGroupPath, serviceMap] = *subtree.begin();
191     const auto& [service, interfaces] = *serviceMap.begin();
192     callback(ec, ledGroupPath, service);
193 }
194 
195 inline void getLedGroupPath(
196     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
197     const std::string& objPath,
198     std::function<void(const boost::system::error_code& ec,
199                        const std::string& ledGroupPath,
200                        const std::string& service)>&& callback)
201 {
202     static constexpr const char* ledObjectPath =
203         "/xyz/openbmc_project/led/groups";
204     sdbusplus::message::object_path ledGroupAssociatedPath =
205         objPath + "/identifying";
206 
207     dbus::utility::getAssociatedSubTree(
208         ledGroupAssociatedPath, sdbusplus::message::object_path(ledObjectPath),
209         0, ledGroupInterface,
210         [asyncResp, objPath, callback{std::move(callback)}](
211             const boost::system::error_code& ec,
212             const dbus::utility::MapperGetSubTreeResponse& subtree) {
213             handleLedGroupSubtree(objPath, ec, subtree, callback);
214         });
215 }
216 
217 inline void afterGetLedState(
218     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
219     const boost::system::error_code& ec, bool assert)
220 {
221     if (ec)
222     {
223         if (ec.value() != EBADR)
224         {
225             BMCWEB_LOG_ERROR("DBUS response error for get ledState {}",
226                              ec.value());
227             messages::internalError(asyncResp->res);
228         }
229         return;
230     }
231 
232     asyncResp->res.jsonValue["LocationIndicatorActive"] = assert;
233 }
234 
235 inline void getLedState(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
236                         const boost::system::error_code& ec,
237                         const std::string& ledGroupPath,
238                         const std::string& service)
239 {
240     if (ec)
241     {
242         if (ec.value() != EBADR)
243         {
244             BMCWEB_LOG_ERROR("DBUS response error {}", ec.value());
245             messages::internalError(asyncResp->res);
246         }
247         return;
248     }
249 
250     if (ledGroupPath.empty() || service.empty())
251     {
252         // No LED group associated, not an error
253         return;
254     }
255 
256     sdbusplus::asio::getProperty<bool>(
257         *crow::connections::systemBus, service, ledGroupPath,
258         "xyz.openbmc_project.Led.Group", "Asserted",
259         std::bind_front(afterGetLedState, asyncResp));
260 }
261 
262 /**
263  * @brief Retrieves identify led group properties over dbus
264  *
265  * @param[in] asyncResp Shared pointer for generating response
266  * message.
267  * @param[in] objPath   Object path on PIM
268  *
269  * @return None.
270  */
271 inline void getLocationIndicatorActive(
272     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
273     const std::string& objPath)
274 {
275     BMCWEB_LOG_DEBUG("Get LocationIndicatorActive for {}", objPath);
276     getLedGroupPath(asyncResp, objPath,
277                     [asyncResp](const boost::system::error_code& ec,
278                                 const std::string& ledGroupPath,
279                                 const std::string& service) {
280                         getLedState(asyncResp, ec, ledGroupPath, service);
281                     });
282 }
283 
284 inline void setLedState(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
285                         bool ledState, const boost::system::error_code& ec,
286                         const std::string& ledGroupPath,
287                         const std::string& service)
288 {
289     if (ec)
290     {
291         if (ec.value() == EBADR)
292         {
293             messages::propertyUnknown(asyncResp->res,
294                                       "LocationIndicatorActive");
295             return;
296         }
297         BMCWEB_LOG_ERROR("DBUS response error {}", ec.value());
298         messages::internalError(asyncResp->res);
299         return;
300     }
301 
302     if (ledGroupPath.empty() || service.empty())
303     {
304         messages::propertyUnknown(asyncResp->res, "LocationIndicatorActive");
305         return;
306     }
307 
308     setDbusProperty(asyncResp, "LocationIndicatorActive", service, ledGroupPath,
309                     "xyz.openbmc_project.Led.Group", "Asserted", ledState);
310 }
311 
312 /**
313  * @brief Sets identify led group properties
314  *
315  * @param[in] asyncResp     Shared pointer for generating response
316  * message.
317  * @param[in] objPath       Object path on PIM
318  * @param[in] ledState      LED state passed from request
319  *
320  * @return None.
321  */
322 inline void setLocationIndicatorActive(
323     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
324     const std::string& objPath, bool ledState)
325 {
326     BMCWEB_LOG_DEBUG("Set LocationIndicatorActive for {}", objPath);
327     getLedGroupPath(
328         asyncResp, objPath,
329         [asyncResp, ledState](const boost::system::error_code& ec,
330                               const std::string& ledGroupPath,
331                               const std::string& service) {
332             setLedState(asyncResp, ledState, ec, ledGroupPath, service);
333         });
334 }
335 
336 } // namespace redfish
337