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 std::function<void (bool asserted)> & callback,const boost::system::error_code & ec,bool assert)307 inline void afterGetLedState(
308 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
309 const std::function<void(bool asserted)>& callback,
310 const boost::system::error_code& ec, bool assert)
311 {
312 if (ec)
313 {
314 if (ec.value() != EBADR)
315 {
316 BMCWEB_LOG_ERROR("DBUS response error for get ledState {}",
317 ec.value());
318 messages::internalError(asyncResp->res);
319 }
320 return;
321 }
322
323 callback(assert);
324 }
325
getLedState(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::function<void (bool asserted)> & callback,const boost::system::error_code & ec,const std::string & ledGroupPath,const std::string & service)326 inline void getLedState(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
327 const std::function<void(bool asserted)>& callback,
328 const boost::system::error_code& ec,
329 const std::string& ledGroupPath,
330 const std::string& service)
331 {
332 if (ec)
333 {
334 if (ec.value() != EBADR)
335 {
336 BMCWEB_LOG_ERROR("DBUS response error {}", ec.value());
337 messages::internalError(asyncResp->res);
338 }
339 return;
340 }
341
342 if (ledGroupPath.empty() || service.empty())
343 {
344 // No LED group associated, not an error
345 return;
346 }
347
348 sdbusplus::asio::getProperty<bool>(
349 *crow::connections::systemBus, service, ledGroupPath,
350 "xyz.openbmc_project.Led.Group", "Asserted",
351 std::bind_front(afterGetLedState, asyncResp, callback));
352 }
353
354 /**
355 * @brief Retrieves identify led group properties over dbus
356 *
357 * @param[in] asyncResp Shared pointer for generating response
358 * message.
359 * @param[in] objPath Object path on PIM
360 * @param[in] callback to pass value
361 * @return None.
362 */
363
getLocationIndicatorActive(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & objPath,std::function<void (bool asserted)> && callback)364 inline void getLocationIndicatorActive(
365 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
366 const std::string& objPath, std::function<void(bool asserted)>&& callback)
367 {
368 BMCWEB_LOG_DEBUG("Get LocationIndicatorActive for {}", objPath);
369 getLedGroupPath(
370 asyncResp, objPath,
371 [asyncResp, callback = std::move(callback)](
372 const boost::system::error_code& ec,
373 const std::string& ledGroupPath, const std::string& service) {
374 getLedState(asyncResp, callback, ec, ledGroupPath, service);
375 });
376 }
377
getLocationIndicatorActive(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & objPath)378 inline void getLocationIndicatorActive(
379 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
380 const std::string& objPath)
381 {
382 getLocationIndicatorActive(asyncResp, objPath, [asyncResp](bool asserted) {
383 asyncResp->res.jsonValue["LocationIndicatorActive"] = asserted;
384 });
385 }
386
setLedState(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,bool ledState,const boost::system::error_code & ec,const std::string & ledGroupPath,const std::string & service)387 inline void setLedState(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
388 bool ledState, const boost::system::error_code& ec,
389 const std::string& ledGroupPath,
390 const std::string& service)
391 {
392 if (ec)
393 {
394 if (ec.value() == EBADR)
395 {
396 messages::propertyUnknown(asyncResp->res,
397 "LocationIndicatorActive");
398 return;
399 }
400 BMCWEB_LOG_ERROR("DBUS response error {}", ec.value());
401 messages::internalError(asyncResp->res);
402 return;
403 }
404
405 if (ledGroupPath.empty() || service.empty())
406 {
407 messages::propertyUnknown(asyncResp->res, "LocationIndicatorActive");
408 return;
409 }
410
411 setDbusProperty(asyncResp, "LocationIndicatorActive", service, ledGroupPath,
412 "xyz.openbmc_project.Led.Group", "Asserted", ledState);
413 }
414
415 /**
416 * @brief Sets identify led group properties
417 *
418 * @param[in] asyncResp Shared pointer for generating response
419 * message.
420 * @param[in] objPath Object path on PIM
421 * @param[in] ledState LED state passed from request
422 *
423 * @return None.
424 */
setLocationIndicatorActive(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & objPath,bool ledState)425 inline void setLocationIndicatorActive(
426 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
427 const std::string& objPath, bool ledState)
428 {
429 BMCWEB_LOG_DEBUG("Set LocationIndicatorActive for {}", objPath);
430 getLedGroupPath(
431 asyncResp, objPath,
432 [asyncResp, ledState](const boost::system::error_code& ec,
433 const std::string& ledGroupPath,
434 const std::string& service) {
435 setLedState(asyncResp, ledState, ec, ledGroupPath, service);
436 });
437 }
438
439 } // namespace redfish
440