xref: /openbmc/bmcweb/redfish-core/lib/led.hpp (revision 177612aaa0633cf9d5aef0b763a43135cf552d9b)
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
getIndicatorLedState(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp)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
setIndicatorLedState(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & ledState)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 /**
157  * @brief Retrieves identify system led group properties over dbus
158  *
159  * @param[in] asyncResp     Shared pointer for generating response message.
160  *
161  * @return None.
162  */
getSystemLocationIndicatorActive(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp)163 inline void getSystemLocationIndicatorActive(
164     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
165 {
166     BMCWEB_LOG_DEBUG("Get LocationIndicatorActive");
167     dbus::utility::getProperty<bool>(
168         "xyz.openbmc_project.LED.GroupManager",
169         "/xyz/openbmc_project/led/groups/enclosure_identify_blink",
170         "xyz.openbmc_project.Led.Group", "Asserted",
171         [asyncResp](const boost::system::error_code& ec, const bool blinking) {
172             // Some systems may not have enclosure_identify_blink object so
173             // proceed to get enclosure_identify state.
174             if (ec == boost::system::errc::invalid_argument)
175             {
176                 BMCWEB_LOG_DEBUG(
177                     "Get identity blinking LED failed, mismatch in property type");
178                 messages::internalError(asyncResp->res);
179                 return;
180             }
181 
182             // Blinking ON, no need to check enclosure_identify assert.
183             if (!ec && blinking)
184             {
185                 asyncResp->res.jsonValue["LocationIndicatorActive"] = true;
186                 return;
187             }
188 
189             dbus::utility::getProperty<bool>(
190                 "xyz.openbmc_project.LED.GroupManager",
191                 "/xyz/openbmc_project/led/groups/enclosure_identify",
192                 "xyz.openbmc_project.Led.Group", "Asserted",
193                 [asyncResp](const boost::system::error_code& ec2,
194                             const bool ledOn) {
195                     if (ec2 == boost::system::errc::invalid_argument)
196                     {
197                         BMCWEB_LOG_DEBUG(
198                             "Get enclosure identity led failed, mismatch in property type");
199                         messages::internalError(asyncResp->res);
200                         return;
201                     }
202 
203                     if (ec2)
204                     {
205                         return;
206                     }
207 
208                     asyncResp->res.jsonValue["LocationIndicatorActive"] = ledOn;
209                 });
210         });
211 }
212 
213 /**
214  * @brief Sets identify system led group properties
215  *
216  * @param[in] asyncResp     Shared pointer for generating response message.
217  * @param[in] ledState  LED state passed from request
218  *
219  * @return None.
220  */
setSystemLocationIndicatorActive(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const bool ledState)221 inline void setSystemLocationIndicatorActive(
222     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const bool ledState)
223 {
224     BMCWEB_LOG_DEBUG("Set LocationIndicatorActive");
225 
226     sdbusplus::asio::setProperty(
227         *crow::connections::systemBus, "xyz.openbmc_project.LED.GroupManager",
228         "/xyz/openbmc_project/led/groups/enclosure_identify_blink",
229         "xyz.openbmc_project.Led.Group", "Asserted", ledState,
230         [asyncResp, ledState](const boost::system::error_code& ec) {
231             if (ec)
232             {
233                 // Some systems may not have enclosure_identify_blink object so
234                 // lets set enclosure_identify state also if
235                 // enclosure_identify_blink failed
236                 setDbusProperty(
237                     asyncResp, "LocationIndicatorActive",
238                     "xyz.openbmc_project.LED.GroupManager",
239                     sdbusplus::message::object_path(
240                         "/xyz/openbmc_project/led/groups/enclosure_identify"),
241                     "xyz.openbmc_project.Led.Group", "Asserted", ledState);
242             }
243         });
244 }
245 
handleLedGroupSubtree(const std::string & objPath,const boost::system::error_code & ec,const dbus::utility::MapperGetSubTreeResponse & subtree,const std::function<void (const boost::system::error_code & ec,const std::string & ledGroupPath,const std::string & service)> & callback)246 inline void handleLedGroupSubtree(
247     const std::string& objPath, const boost::system::error_code& ec,
248     const dbus::utility::MapperGetSubTreeResponse& subtree,
249     const std::function<void(const boost::system::error_code& ec,
250                              const std::string& ledGroupPath,
251                              const std::string& service)>& callback)
252 {
253     if (ec)
254     {
255         // Callback will handle the error
256         callback(ec, "", "");
257         return;
258     }
259 
260     if (subtree.empty())
261     {
262         // Callback will handle the error
263         BMCWEB_LOG_DEBUG(
264             "No LED group associated with the specified object path: {}",
265             objPath);
266         callback(ec, "", "");
267         return;
268     }
269 
270     if (subtree.size() > 1)
271     {
272         // Callback will handle the error
273         BMCWEB_LOG_DEBUG(
274             "More than one LED group associated with the object {}: {}",
275             objPath, subtree.size());
276         callback(ec, "", "");
277         return;
278     }
279 
280     const auto& [ledGroupPath, serviceMap] = *subtree.begin();
281     const auto& [service, interfaces] = *serviceMap.begin();
282     callback(ec, ledGroupPath, service);
283 }
284 
getLedGroupPath(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & objPath,std::function<void (const boost::system::error_code & ec,const std::string & ledGroupPath,const std::string & service)> && callback)285 inline void getLedGroupPath(
286     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
287     const std::string& objPath,
288     std::function<void(const boost::system::error_code& ec,
289                        const std::string& ledGroupPath,
290                        const std::string& service)>&& callback)
291 {
292     static constexpr const char* ledObjectPath =
293         "/xyz/openbmc_project/led/groups";
294     sdbusplus::message::object_path ledGroupAssociatedPath =
295         objPath + "/identifying";
296 
297     dbus::utility::getAssociatedSubTree(
298         ledGroupAssociatedPath, sdbusplus::message::object_path(ledObjectPath),
299         0, ledGroupInterface,
300         [asyncResp, objPath, callback{std::move(callback)}](
301             const boost::system::error_code& ec,
302             const dbus::utility::MapperGetSubTreeResponse& subtree) {
303             handleLedGroupSubtree(objPath, ec, subtree, callback);
304         });
305 }
306 
afterGetLedState(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const boost::system::error_code & ec,bool assert)307 inline void afterGetLedState(
308     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
309     const boost::system::error_code& ec, bool assert)
310 {
311     if (ec)
312     {
313         if (ec.value() != EBADR)
314         {
315             BMCWEB_LOG_ERROR("DBUS response error for get ledState {}",
316                              ec.value());
317             messages::internalError(asyncResp->res);
318         }
319         return;
320     }
321 
322     asyncResp->res.jsonValue["LocationIndicatorActive"] = assert;
323 }
324 
getLedState(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const boost::system::error_code & ec,const std::string & ledGroupPath,const std::string & service)325 inline void getLedState(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
326                         const boost::system::error_code& ec,
327                         const std::string& ledGroupPath,
328                         const std::string& service)
329 {
330     if (ec)
331     {
332         if (ec.value() != EBADR)
333         {
334             BMCWEB_LOG_ERROR("DBUS response error {}", ec.value());
335             messages::internalError(asyncResp->res);
336         }
337         return;
338     }
339 
340     if (ledGroupPath.empty() || service.empty())
341     {
342         // No LED group associated, not an error
343         return;
344     }
345 
346     sdbusplus::asio::getProperty<bool>(
347         *crow::connections::systemBus, service, ledGroupPath,
348         "xyz.openbmc_project.Led.Group", "Asserted",
349         std::bind_front(afterGetLedState, asyncResp));
350 }
351 
352 /**
353  * @brief Retrieves identify led group properties over dbus
354  *
355  * @param[in] asyncResp Shared pointer for generating response
356  * message.
357  * @param[in] objPath   Object path on PIM
358  *
359  * @return None.
360  */
getLocationIndicatorActive(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & objPath)361 inline void getLocationIndicatorActive(
362     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
363     const std::string& objPath)
364 {
365     BMCWEB_LOG_DEBUG("Get LocationIndicatorActive for {}", objPath);
366     getLedGroupPath(asyncResp, objPath,
367                     [asyncResp](const boost::system::error_code& ec,
368                                 const std::string& ledGroupPath,
369                                 const std::string& service) {
370                         getLedState(asyncResp, ec, ledGroupPath, service);
371                     });
372 }
373 
setLedState(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,bool ledState,const boost::system::error_code & ec,const std::string & ledGroupPath,const std::string & service)374 inline void setLedState(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
375                         bool ledState, const boost::system::error_code& ec,
376                         const std::string& ledGroupPath,
377                         const std::string& service)
378 {
379     if (ec)
380     {
381         if (ec.value() == EBADR)
382         {
383             messages::propertyUnknown(asyncResp->res,
384                                       "LocationIndicatorActive");
385             return;
386         }
387         BMCWEB_LOG_ERROR("DBUS response error {}", ec.value());
388         messages::internalError(asyncResp->res);
389         return;
390     }
391 
392     if (ledGroupPath.empty() || service.empty())
393     {
394         messages::propertyUnknown(asyncResp->res, "LocationIndicatorActive");
395         return;
396     }
397 
398     setDbusProperty(asyncResp, "LocationIndicatorActive", service, ledGroupPath,
399                     "xyz.openbmc_project.Led.Group", "Asserted", ledState);
400 }
401 
402 /**
403  * @brief Sets identify led group properties
404  *
405  * @param[in] asyncResp     Shared pointer for generating response
406  * message.
407  * @param[in] objPath       Object path on PIM
408  * @param[in] ledState      LED state passed from request
409  *
410  * @return None.
411  */
setLocationIndicatorActive(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & objPath,bool ledState)412 inline void setLocationIndicatorActive(
413     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
414     const std::string& objPath, bool ledState)
415 {
416     BMCWEB_LOG_DEBUG("Set LocationIndicatorActive for {}", objPath);
417     getLedGroupPath(
418         asyncResp, objPath,
419         [asyncResp, ledState](const boost::system::error_code& ec,
420                               const std::string& ledGroupPath,
421                               const std::string& service) {
422             setLedState(asyncResp, ledState, ec, ledGroupPath, service);
423         });
424 }
425 
426 } // namespace redfish
427