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