Coverage Report

Created: 2026-09-14 06:49

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