1 
2 #include "host_lamp_test.hpp"
3 
4 #include "common/types.hpp"
5 #include "common/utils.hpp"
6 
7 #include <libpldm/entity.h>
8 #include <libpldm/platform.h>
9 #include <libpldm/state_set.h>
10 
11 PHOSPHOR_LOG2_USING;
12 
13 namespace pldm
14 {
15 namespace led
16 {
17 
18 bool HostLampTest::asserted() const
19 {
20     return sdbusplus::xyz::openbmc_project::Led::server::Group::asserted();
21 }
22 
23 bool HostLampTest::asserted(bool value)
24 {
25     // When setting the asserted property to true, need to notify the PHYP to
26     // start lamp test.
27     // When setting the asserted property to true again, need to notify the PHYP
28     // and PHYP will restart the lamp test.
29     // When setting the asserted property to false, just update the asserted
30     // property, do not need to notify the PHYP to stop lamp test, PHYP will
31     // wait for timeout to stop.
32     if (!value &&
33         value ==
34             sdbusplus::xyz::openbmc_project::Led::server::Group::asserted())
35     {
36         return value;
37     }
38 
39     if (value)
40     {
41         if (effecterID == 0)
42         {
43             effecterID = getEffecterID();
44         }
45 
46         if (effecterID != 0)
47         {
48             // Call setHostStateEffecter method to notify PHYP to start lamp
49             // test. If user set Asserted to true again, need to notify PHYP to
50             // start lamptest again.
51             uint8_t rc = setHostStateEffecter(effecterID);
52             if (rc)
53             {
54                 throw sdbusplus::exception::SdBusError(
55                     static_cast<int>(std::errc::invalid_argument),
56                     "Set Host State Effector to start lamp test failed");
57             }
58             else
59             {
60                 return sdbusplus::xyz::openbmc_project::Led::server::Group::
61                     asserted(value);
62             }
63         }
64         else
65         {
66             throw sdbusplus::exception::SdBusError(
67                 static_cast<int>(std::errc::invalid_argument),
68                 "Get Effecter ID failed, effecter = 0");
69         }
70     }
71 
72     return sdbusplus::xyz::openbmc_project::Led::server::Group::asserted(value);
73 }
74 
75 uint16_t HostLampTest::getEffecterID()
76 {
77     uint16_t effecterID = 0;
78 
79     if (!pdrRepo)
80     {
81         return effecterID;
82     }
83 
84     // INDICATOR is a logical entity, so the bit 15 in entity type is set.
85     pdr::EntityType entityType = PLDM_ENTITY_INDICATOR | 0x8000;
86 
87     auto stateEffecterPDRs = pldm::utils::findStateEffecterPDR(
88         mctp_eid, entityType,
89         static_cast<uint16_t>(PLDM_STATE_SET_IDENTIFY_STATE), pdrRepo);
90 
91     if (stateEffecterPDRs.empty())
92     {
93         error(
94             "Lamp Test: The state set PDR can not be found, entityType = {ENTITY_TYP}",
95             "ENTITY_TYP", entityType);
96         return effecterID;
97     }
98 
99     for (const auto& rep : stateEffecterPDRs)
100     {
101         auto pdr = reinterpret_cast<const pldm_state_effecter_pdr*>(rep.data());
102         effecterID = pdr->effecter_id;
103         break;
104     }
105 
106     return effecterID;
107 }
108 
109 uint8_t HostLampTest::setHostStateEffecter(uint16_t effecterID)
110 {
111     constexpr uint8_t effecterCount = 1;
112     auto instanceId = instanceIdDb.next(mctp_eid);
113 
114     std::vector<uint8_t> requestMsg(
115         sizeof(pldm_msg_hdr) + sizeof(effecterID) + sizeof(effecterCount) +
116         sizeof(set_effecter_state_field));
117     auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
118     set_effecter_state_field stateField{PLDM_REQUEST_SET,
119                                         PLDM_STATE_SET_IDENTIFY_STATE_ASSERTED};
120     auto rc = encode_set_state_effecter_states_req(
121         instanceId, effecterID, effecterCount, &stateField, request);
122     if (rc != PLDM_SUCCESS)
123     {
124         instanceIdDb.free(mctp_eid, instanceId);
125         error("Failed to encode_set_state_effecter_states_req, rc = {RC}", "RC",
126               static_cast<int>(rc));
127         return rc;
128     }
129 
130     auto setStateEffecterStatesResponseHandler = [](mctp_eid_t /*eid*/,
131                                                     const pldm_msg* response,
132                                                     size_t respMsgLen) {
133         if (!response || !respMsgLen)
134         {
135             error(
136                 "Failed to receive response for the Set State Effecter States");
137             return;
138         }
139 
140         uint8_t completionCode{};
141         auto rc = decode_set_state_effecter_states_resp(response, respMsgLen,
142                                                         &completionCode);
143 
144         if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS)
145         {
146             error(
147                 "Failed to decode_set_state_effecter_states_resp: rc={RC}, cc={CC}",
148                 "RC", rc, "CC", static_cast<unsigned>(completionCode));
149         }
150     };
151 
152     rc = handler->registerRequest(
153         mctp_eid, instanceId, PLDM_PLATFORM, PLDM_SET_STATE_EFFECTER_STATES,
154         std::move(requestMsg),
155         std::move(setStateEffecterStatesResponseHandler));
156     if (rc != PLDM_SUCCESS)
157     {
158         error("Failed to send the the Set State Effecter States request");
159     }
160 
161     return rc;
162 }
163 
164 } // namespace led
165 } // namespace pldm
166