xref: /openbmc/bmcweb/features/redfish/lib/led.hpp (revision 7066dc58dd7c3b56e0f224458e9190be8d758771)
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_view>
24 #include <utility>
25 
26 namespace redfish
27 {
28 static constexpr std::array<std::string_view, 1> ledGroupInterface = {
29     "xyz.openbmc_project.Led.Group"};
30 /**
31  * @brief Retrieves identify led group properties over dbus
32  *
33  * @param[in] asyncResp     Shared pointer for generating response message.
34  *
35  * @return None.
36  */
37 // TODO (Gunnar): Remove IndicatorLED after enough time has passed
38 inline void getIndicatorLedState(
39     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
40 {
41     BMCWEB_LOG_DEBUG("Get led groups");
42     dbus::utility::getProperty<bool>(
43         "xyz.openbmc_project.LED.GroupManager",
44         "/xyz/openbmc_project/led/groups/enclosure_identify_blink",
45         "xyz.openbmc_project.Led.Group", "Asserted",
46         [asyncResp](const boost::system::error_code& ec, const bool blinking) {
47             // Some systems may not have enclosure_identify_blink object so
48             // proceed to get enclosure_identify state.
49             if (ec == boost::system::errc::invalid_argument)
50             {
51                 BMCWEB_LOG_DEBUG(
52                     "Get identity blinking LED failed, mismatch in property type");
53                 messages::internalError(asyncResp->res);
54                 return;
55             }
56 
57             // Blinking ON, no need to check enclosure_identify assert.
58             if (!ec && blinking)
59             {
60                 asyncResp->res.jsonValue["IndicatorLED"] =
61                     chassis::IndicatorLED::Blinking;
62                 return;
63             }
64 
65             dbus::utility::getProperty<bool>(
66                 "xyz.openbmc_project.LED.GroupManager",
67                 "/xyz/openbmc_project/led/groups/enclosure_identify",
68                 "xyz.openbmc_project.Led.Group", "Asserted",
69                 [asyncResp](const boost::system::error_code& ec2,
70                             const bool ledOn) {
71                     if (ec2 == boost::system::errc::invalid_argument)
72                     {
73                         BMCWEB_LOG_DEBUG(
74                             "Get enclosure identity led failed, mismatch in property type");
75                         messages::internalError(asyncResp->res);
76                         return;
77                     }
78 
79                     if (ec2)
80                     {
81                         return;
82                     }
83 
84                     if (ledOn)
85                     {
86                         asyncResp->res.jsonValue["IndicatorLED"] =
87                             chassis::IndicatorLED::Lit;
88                     }
89                     else
90                     {
91                         asyncResp->res.jsonValue["IndicatorLED"] =
92                             chassis::IndicatorLED::Off;
93                     }
94                 });
95         });
96 }
97 
98 /**
99  * @brief Sets identify led group properties
100  *
101  * @param[in] asyncResp     Shared pointer for generating response message.
102  * @param[in] ledState  LED state passed from request
103  *
104  * @return None.
105  */
106 // TODO (Gunnar): Remove IndicatorLED after enough time has passed
107 inline void setIndicatorLedState(
108     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
109     const std::string& ledState)
110 {
111     BMCWEB_LOG_DEBUG("Set led groups");
112     bool ledOn = false;
113     bool ledBlinkng = false;
114 
115     if (ledState == "Lit")
116     {
117         ledOn = true;
118     }
119     else if (ledState == "Blinking")
120     {
121         ledBlinkng = true;
122     }
123     else if (ledState != "Off")
124     {
125         messages::propertyValueNotInList(asyncResp->res, ledState,
126                                          "IndicatorLED");
127         return;
128     }
129 
130     sdbusplus::asio::setProperty(
131         *crow::connections::systemBus, "xyz.openbmc_project.LED.GroupManager",
132         "/xyz/openbmc_project/led/groups/enclosure_identify_blink",
133         "xyz.openbmc_project.Led.Group", "Asserted", ledBlinkng,
134         [asyncResp, ledOn,
135          ledBlinkng](const boost::system::error_code& ec) mutable {
136             if (ec)
137             {
138                 // Some systems may not have enclosure_identify_blink object so
139                 // Lets set enclosure_identify state to true if Blinking is
140                 // true.
141                 if (ledBlinkng)
142                 {
143                     ledOn = true;
144                 }
145             }
146             setDbusProperty(
147                 asyncResp, "IndicatorLED",
148                 "xyz.openbmc_project.LED.GroupManager",
149                 sdbusplus::message::object_path(
150                     "/xyz/openbmc_project/led/groups/enclosure_identify"),
151                 "xyz.openbmc_project.Led.Group", "Asserted", ledBlinkng);
152         });
153 }
154 
155 /**
156  * @brief Retrieves identify system led group properties over dbus
157  *
158  * @param[in] asyncResp     Shared pointer for generating response message.
159  *
160  * @return None.
161  */
162 inline void getSystemLocationIndicatorActive(
163     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
164 {
165     BMCWEB_LOG_DEBUG("Get LocationIndicatorActive");
166     dbus::utility::getProperty<bool>(
167         "xyz.openbmc_project.LED.GroupManager",
168         "/xyz/openbmc_project/led/groups/enclosure_identify_blink",
169         "xyz.openbmc_project.Led.Group", "Asserted",
170         [asyncResp](const boost::system::error_code& ec, const bool blinking) {
171             // Some systems may not have enclosure_identify_blink object so
172             // proceed to get enclosure_identify state.
173             if (ec == boost::system::errc::invalid_argument)
174             {
175                 BMCWEB_LOG_DEBUG(
176                     "Get identity blinking LED failed, mismatch in property type");
177                 messages::internalError(asyncResp->res);
178                 return;
179             }
180 
181             // Blinking ON, no need to check enclosure_identify assert.
182             if (!ec && blinking)
183             {
184                 asyncResp->res.jsonValue["LocationIndicatorActive"] = true;
185                 return;
186             }
187 
188             dbus::utility::getProperty<bool>(
189                 "xyz.openbmc_project.LED.GroupManager",
190                 "/xyz/openbmc_project/led/groups/enclosure_identify",
191                 "xyz.openbmc_project.Led.Group", "Asserted",
192                 [asyncResp](const boost::system::error_code& ec2,
193                             const bool ledOn) {
194                     if (ec2 == boost::system::errc::invalid_argument)
195                     {
196                         BMCWEB_LOG_DEBUG(
197                             "Get enclosure identity led failed, mismatch in property type");
198                         messages::internalError(asyncResp->res);
199                         return;
200                     }
201 
202                     if (ec2)
203                     {
204                         return;
205                     }
206 
207                     asyncResp->res.jsonValue["LocationIndicatorActive"] = ledOn;
208                 });
209         });
210 }
211 
212 /**
213  * @brief Sets identify system led group properties
214  *
215  * @param[in] asyncResp     Shared pointer for generating response message.
216  * @param[in] ledState  LED state passed from request
217  *
218  * @return None.
219  */
220 inline void setSystemLocationIndicatorActive(
221     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const bool ledState)
222 {
223     BMCWEB_LOG_DEBUG("Set LocationIndicatorActive");
224 
225     sdbusplus::asio::setProperty(
226         *crow::connections::systemBus, "xyz.openbmc_project.LED.GroupManager",
227         "/xyz/openbmc_project/led/groups/enclosure_identify_blink",
228         "xyz.openbmc_project.Led.Group", "Asserted", ledState,
229         [asyncResp, ledState](const boost::system::error_code& ec) {
230             if (ec)
231             {
232                 // Some systems may not have enclosure_identify_blink object so
233                 // lets set enclosure_identify state also if
234                 // enclosure_identify_blink failed
235                 setDbusProperty(
236                     asyncResp, "LocationIndicatorActive",
237                     "xyz.openbmc_project.LED.GroupManager",
238                     sdbusplus::message::object_path(
239                         "/xyz/openbmc_project/led/groups/enclosure_identify"),
240                     "xyz.openbmc_project.Led.Group", "Asserted", ledState);
241             }
242         });
243 }
244 
245 inline void handleLedGroupSubtree(
246     const std::string& objPath, const boost::system::error_code& ec,
247     const dbus::utility::MapperGetSubTreeResponse& subtree,
248     const std::function<void(const boost::system::error_code& ec,
249                              const std::string& ledGroupPath,
250                              const std::string& service)>& callback)
251 {
252     if (ec)
253     {
254         // Callback will handle the error
255         callback(ec, "", "");
256         return;
257     }
258 
259     if (subtree.empty())
260     {
261         // Callback will handle the error
262         BMCWEB_LOG_DEBUG(
263             "No LED group associated with the specified object path: {}",
264             objPath);
265         callback(ec, "", "");
266         return;
267     }
268 
269     if (subtree.size() > 1)
270     {
271         // Callback will handle the error
272         BMCWEB_LOG_DEBUG(
273             "More than one LED group associated with the object {}: {}",
274             objPath, subtree.size());
275         callback(ec, "", "");
276         return;
277     }
278 
279     const auto& [ledGroupPath, serviceMap] = *subtree.begin();
280     const auto& [service, interfaces] = *serviceMap.begin();
281     callback(ec, ledGroupPath, service);
282 }
283 
284 inline void getLedGroupPath(
285     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
286     const std::string& objPath,
287     std::function<void(const boost::system::error_code& ec,
288                        const std::string& ledGroupPath,
289                        const std::string& service)>&& callback)
290 {
291     static constexpr const char* ledObjectPath =
292         "/xyz/openbmc_project/led/groups";
293     sdbusplus::message::object_path ledGroupAssociatedPath =
294         objPath + "/identifying";
295 
296     dbus::utility::getAssociatedSubTree(
297         ledGroupAssociatedPath, sdbusplus::message::object_path(ledObjectPath),
298         0, ledGroupInterface,
299         [asyncResp, objPath, callback{std::move(callback)}](
300             const boost::system::error_code& ec,
301             const dbus::utility::MapperGetSubTreeResponse& subtree) {
302             handleLedGroupSubtree(objPath, ec, subtree, callback);
303         });
304 }
305 
306 inline void afterGetLedState(
307     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
308     const boost::system::error_code& ec, bool assert)
309 {
310     if (ec)
311     {
312         if (ec.value() != EBADR)
313         {
314             BMCWEB_LOG_ERROR("DBUS response error for get ledState {}",
315                              ec.value());
316             messages::internalError(asyncResp->res);
317         }
318         return;
319     }
320 
321     asyncResp->res.jsonValue["LocationIndicatorActive"] = assert;
322 }
323 
324 inline void getLedState(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
325                         const boost::system::error_code& ec,
326                         const std::string& ledGroupPath,
327                         const std::string& service)
328 {
329     if (ec)
330     {
331         if (ec.value() != EBADR)
332         {
333             BMCWEB_LOG_ERROR("DBUS response error {}", ec.value());
334             messages::internalError(asyncResp->res);
335         }
336         return;
337     }
338 
339     if (ledGroupPath.empty() || service.empty())
340     {
341         // No LED group associated, not an error
342         return;
343     }
344 
345     sdbusplus::asio::getProperty<bool>(
346         *crow::connections::systemBus, service, ledGroupPath,
347         "xyz.openbmc_project.Led.Group", "Asserted",
348         std::bind_front(afterGetLedState, asyncResp));
349 }
350 
351 /**
352  * @brief Retrieves identify led group properties over dbus
353  *
354  * @param[in] asyncResp Shared pointer for generating response
355  * message.
356  * @param[in] objPath   Object path on PIM
357  *
358  * @return None.
359  */
360 inline void getLocationIndicatorActive(
361     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
362     const std::string& objPath)
363 {
364     BMCWEB_LOG_DEBUG("Get LocationIndicatorActive for {}", objPath);
365     getLedGroupPath(asyncResp, objPath,
366                     [asyncResp](const boost::system::error_code& ec,
367                                 const std::string& ledGroupPath,
368                                 const std::string& service) {
369                         getLedState(asyncResp, ec, ledGroupPath, service);
370                     });
371 }
372 
373 inline void setLedState(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
374                         bool ledState, const boost::system::error_code& ec,
375                         const std::string& ledGroupPath,
376                         const std::string& service)
377 {
378     if (ec)
379     {
380         if (ec.value() == EBADR)
381         {
382             messages::propertyUnknown(asyncResp->res,
383                                       "LocationIndicatorActive");
384             return;
385         }
386         BMCWEB_LOG_ERROR("DBUS response error {}", ec.value());
387         messages::internalError(asyncResp->res);
388         return;
389     }
390 
391     if (ledGroupPath.empty() || service.empty())
392     {
393         messages::propertyUnknown(asyncResp->res, "LocationIndicatorActive");
394         return;
395     }
396 
397     setDbusProperty(asyncResp, "LocationIndicatorActive", service, ledGroupPath,
398                     "xyz.openbmc_project.Led.Group", "Asserted", ledState);
399 }
400 
401 /**
402  * @brief Sets identify led group properties
403  *
404  * @param[in] asyncResp     Shared pointer for generating response
405  * message.
406  * @param[in] objPath       Object path on PIM
407  * @param[in] ledState      LED state passed from request
408  *
409  * @return None.
410  */
411 inline void setLocationIndicatorActive(
412     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
413     const std::string& objPath, bool ledState)
414 {
415     BMCWEB_LOG_DEBUG("Set LocationIndicatorActive for {}", objPath);
416     getLedGroupPath(
417         asyncResp, objPath,
418         [asyncResp, ledState](const boost::system::error_code& ec,
419                               const std::string& ledGroupPath,
420                               const std::string& service) {
421             setLedState(asyncResp, ledState, ec, ledGroupPath, service);
422         });
423 }
424 
425 } // namespace redfish
426