1 #include "dbus_to_terminus_effecters.hpp"
2 
3 #include <libpldm/pdr.h>
4 #include <libpldm/platform.h>
5 
6 #include <phosphor-logging/lg2.hpp>
7 #include <xyz/openbmc_project/Common/error.hpp>
8 #include <xyz/openbmc_project/State/Boot/Progress/client.hpp>
9 #include <xyz/openbmc_project/State/OperatingSystem/Status/server.hpp>
10 
11 #include <fstream>
12 
13 PHOSPHOR_LOG2_USING;
14 
15 using namespace pldm::utils;
16 
17 namespace pldm
18 {
19 namespace host_effecters
20 {
21 using InternalFailure =
22     sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
23 
24 constexpr auto hostEffecterJson = "dbus_to_terminus_effecter.json";
25 
26 void HostEffecterParser::populatePropVals(
27     const Json& dBusValues, std::vector<PropertyValue>& propertyValues,
28     const std::string& propertyType)
29 
30 {
31     for (const auto& elem : dBusValues)
32     {
33         auto value = jsonEntryToDbusVal(propertyType, elem);
34         propertyValues.emplace_back(value);
35     }
36 }
37 
38 void HostEffecterParser::parseEffecterJson(const std::string& jsonPath)
39 {
40     fs::path jsonDir(jsonPath);
41     if (!fs::exists(jsonDir) || fs::is_empty(jsonDir))
42     {
43         error("Effecter json file for remote terminus '{PATH}' does not exist.",
44               "PATH", jsonPath);
45         return;
46     }
47 
48     fs::path jsonFilePath = jsonDir / hostEffecterJson;
49     if (!fs::exists(jsonFilePath))
50     {
51         error("Json at path '{PATH}' does not exist.", "PATH", jsonFilePath);
52         throw InternalFailure();
53     }
54 
55     std::ifstream jsonFile(jsonFilePath);
56     auto data = Json::parse(jsonFile, nullptr, false);
57     if (data.is_discarded())
58     {
59         error("Failed to parse json file {PATH}", "PATH", jsonFilePath);
60         throw InternalFailure();
61     }
62     const Json empty{};
63     const std::vector<Json> emptyList{};
64 
65     auto entries = data.value("entries", emptyList);
66     for (const auto& entry : entries)
67     {
68         EffecterInfo effecterInfo;
69         effecterInfo.mctpEid = entry.value("mctp_eid", 0xFF);
70         auto jsonEffecterInfo = entry.value("effecter_info", empty);
71         auto effecterId =
72             jsonEffecterInfo.value("effecterID", PLDM_INVALID_EFFECTER_ID);
73         /* default as PLDM_STATE_EFFECTER_PDR */
74         auto effecterPdrType =
75             jsonEffecterInfo.value("effecterPdrType", PLDM_STATE_EFFECTER_PDR);
76         if (effecterPdrType != PLDM_STATE_EFFECTER_PDR &&
77             effecterPdrType != PLDM_NUMERIC_EFFECTER_PDR)
78         {
79             error(
80                 "Effecter PDRType not supported {TYPE} of effecterID '{EFFECTERID}'",
81                 "TYPE", effecterPdrType, "EFFECTERID", effecterId);
82             continue;
83         }
84         effecterInfo.effecterPdrType = effecterPdrType;
85         effecterInfo.containerId = jsonEffecterInfo.value("containerID", 0);
86         effecterInfo.entityType = jsonEffecterInfo.value("entityType", 0);
87         effecterInfo.entityInstance =
88             jsonEffecterInfo.value("entityInstance", 0);
89         effecterInfo.compEffecterCnt =
90             jsonEffecterInfo.value("compositeEffecterCount", 0);
91         effecterInfo.checkHostState =
92             jsonEffecterInfo.value("checkHostState", true);
93         auto effecters = entry.value("effecters", emptyList);
94 
95         if (effecterPdrType == PLDM_NUMERIC_EFFECTER_PDR)
96         {
97             for (const auto& effecter : effecters)
98             {
99                 DBusNumericEffecterMapping dbusInfo{};
100                 auto jsonDbusInfo = effecter.value("dbus_info", empty);
101                 dbusInfo.dataSize = effecter.value("effecterDataSize", 0);
102                 dbusInfo.unitModifier = effecter.value("unitModifier", 0);
103                 dbusInfo.resolution = effecter.value("resolution", 1);
104                 dbusInfo.offset = effecter.value("offset", 0);
105                 dbusInfo.dbusMap.objectPath =
106                     jsonDbusInfo.value("object_path", "");
107                 dbusInfo.dbusMap.interface =
108                     jsonDbusInfo.value("interface", "");
109                 dbusInfo.dbusMap.propertyName =
110                     jsonDbusInfo.value("property_name", "");
111                 dbusInfo.dbusMap.propertyType =
112                     jsonDbusInfo.value("property_type", "");
113                 /**
114                  * Only support these property type for Numeric Effecter D-Bus
115                  * property:
116                  * "uint8_t", "int16_t",  "uint16_t", "int32_t", "uint32_t",
117                  * "int64_t", "uint64_t", "double"
118                  */
119                 if (!dbusValueNumericTypeNames.contains(
120                         dbusInfo.dbusMap.propertyType))
121                 {
122                     lg2::error(
123                         "Invalid PropertyType {TYPE} of object path {PATH} property name {NAME}",
124                         "TYPE", dbusInfo.dbusMap.propertyType, "PATH",
125                         dbusInfo.dbusMap.objectPath, "NAME",
126                         dbusInfo.dbusMap.propertyName);
127                     continue;
128                 }
129 
130                 dbusInfo.propertyValue =
131                     std::numeric_limits<double>::quiet_NaN();
132                 auto effecterInfoIndex = hostEffecterInfo.size();
133                 auto dbusInfoIndex = effecterInfo.dbusInfo.size();
134                 createHostEffecterMatch(
135                     dbusInfo.dbusMap.objectPath, dbusInfo.dbusMap.interface,
136                     effecterInfoIndex, dbusInfoIndex, effecterId);
137                 effecterInfo.dbusNumericEffecterInfo.emplace_back(
138                     std::move(dbusInfo));
139             }
140             hostEffecterInfo.emplace_back(std::move(effecterInfo));
141             continue;
142         }
143 
144         for (const auto& effecter : effecters)
145         {
146             DBusEffecterMapping dbusInfo{};
147             auto jsonDbusInfo = effecter.value("dbus_info", empty);
148             dbusInfo.dbusMap.objectPath = jsonDbusInfo.value("object_path", "");
149             dbusInfo.dbusMap.interface = jsonDbusInfo.value("interface", "");
150             dbusInfo.dbusMap.propertyName =
151                 jsonDbusInfo.value("property_name", "");
152             dbusInfo.dbusMap.propertyType =
153                 jsonDbusInfo.value("property_type", "");
154             Json propertyValues = jsonDbusInfo["property_values"];
155 
156             populatePropVals(propertyValues, dbusInfo.propertyValues,
157                              dbusInfo.dbusMap.propertyType);
158 
159             const std::vector<uint8_t> emptyStates{};
160             auto state = effecter.value("state", empty);
161             dbusInfo.state.stateSetId = state.value("id", 0);
162             auto states = state.value("state_values", emptyStates);
163             if (dbusInfo.propertyValues.size() != states.size())
164             {
165                 error(
166                     "Number of states do not match with number of D-Bus property values in the json. Object path at '{PATH}' and property '{PROPERTY}' will not be monitored",
167                     "PATH", dbusInfo.dbusMap.objectPath, "PROPERTY",
168                     dbusInfo.dbusMap.propertyName);
169                 continue;
170             }
171             for (const auto& s : states)
172             {
173                 dbusInfo.state.states.emplace_back(s);
174             }
175 
176             auto effecterInfoIndex = hostEffecterInfo.size();
177             auto dbusInfoIndex = effecterInfo.dbusInfo.size();
178             createHostEffecterMatch(
179                 dbusInfo.dbusMap.objectPath, dbusInfo.dbusMap.interface,
180                 effecterInfoIndex, dbusInfoIndex, effecterId);
181             effecterInfo.dbusInfo.emplace_back(std::move(dbusInfo));
182         }
183         hostEffecterInfo.emplace_back(std::move(effecterInfo));
184     }
185 }
186 
187 bool HostEffecterParser::isHostOn(void)
188 {
189     using BootProgress =
190         sdbusplus::client::xyz::openbmc_project::state::boot::Progress<>;
191     constexpr auto hostStatePath = "/xyz/openbmc_project/state/host0";
192     try
193     {
194         auto propVal = dbusHandler->getDbusPropertyVariant(
195             hostStatePath, "BootProgress", BootProgress::interface);
196 
197         using Stages = BootProgress::ProgressStages;
198         auto currHostState = sdbusplus::message::convert_from_string<Stages>(
199                                  std::get<std::string>(propVal))
200                                  .value();
201 
202         if (currHostState != Stages::SystemInitComplete &&
203             currHostState != Stages::OSRunning &&
204             currHostState != Stages::SystemSetup &&
205             currHostState != Stages::OEM)
206         {
207             info(
208                 "Remote terminus is not up/active, current remote terminus state is: '{CURRENT_HOST_STATE}'",
209                 "CURRENT_HOST_STATE", currHostState);
210             return false;
211         }
212     }
213     catch (const sdbusplus::exception_t& e)
214     {
215         error(
216             "Error in getting current remote terminus state. Will still continue to set the remote terminus effecter, error - {ERROR}",
217             "ERROR", e);
218         return false;
219     }
220 
221     return true;
222 }
223 
224 void HostEffecterParser::processHostEffecterChangeNotification(
225     const DbusChgHostEffecterProps& chProperties, size_t effecterInfoIndex,
226     size_t dbusInfoIndex, uint16_t effecterId)
227 {
228     const auto& pdrType = hostEffecterInfo[effecterInfoIndex].effecterPdrType;
229     if (pdrType == PLDM_NUMERIC_EFFECTER_PDR)
230     {
231         processTerminusNumericEffecterChangeNotification(
232             chProperties, effecterInfoIndex, dbusInfoIndex, effecterId);
233         return;
234     }
235     const auto& propertyName = hostEffecterInfo[effecterInfoIndex]
236                                    .dbusInfo[dbusInfoIndex]
237                                    .dbusMap.propertyName;
238 
239     const auto& it = chProperties.find(propertyName);
240 
241     if (it == chProperties.end())
242     {
243         return;
244     }
245 
246     if (effecterId == PLDM_INVALID_EFFECTER_ID)
247     {
248         constexpr auto localOrRemote = false;
249         effecterId = findStateEffecterId(
250             pdrRepo, hostEffecterInfo[effecterInfoIndex].entityType,
251             hostEffecterInfo[effecterInfoIndex].entityInstance,
252             hostEffecterInfo[effecterInfoIndex].containerId,
253             hostEffecterInfo[effecterInfoIndex]
254                 .dbusInfo[dbusInfoIndex]
255                 .state.stateSetId,
256             localOrRemote);
257         if (effecterId == PLDM_INVALID_EFFECTER_ID)
258         {
259             error(
260                 "Effecter ID '{EFFECTERID}' of entity type '{TYPE}', entityInstance '{INSTANCE}' and containerID '{CONTAINER_ID}' not found in pdr repo",
261                 "EFFECTERID", effecterId, "TYPE",
262                 hostEffecterInfo[effecterInfoIndex].entityType, "INSTANCE",
263                 hostEffecterInfo[effecterInfoIndex].entityInstance,
264                 "CONTAINER_ID",
265                 hostEffecterInfo[effecterInfoIndex].containerId);
266             return;
267         }
268     }
269 
270     if (!isHostOn())
271     {
272         return;
273     }
274 
275     uint8_t newState{};
276     try
277     {
278         newState =
279             findNewStateValue(effecterInfoIndex, dbusInfoIndex, it->second);
280     }
281     catch (const std::out_of_range& e)
282     {
283         error("Failed to find new state '{NEW_STATE}' in json, error - {ERROR}",
284               "ERROR", e, "NEW_STATE", newState);
285         return;
286     }
287 
288     std::vector<set_effecter_state_field> stateField;
289     for (uint8_t i = 0; i < hostEffecterInfo[effecterInfoIndex].compEffecterCnt;
290          i++)
291     {
292         if (i == dbusInfoIndex)
293         {
294             stateField.push_back({PLDM_REQUEST_SET, newState});
295         }
296         else
297         {
298             stateField.push_back({PLDM_NO_CHANGE, 0});
299         }
300     }
301     int rc{};
302     try
303     {
304         rc = setHostStateEffecter(effecterInfoIndex, stateField, effecterId);
305     }
306     catch (const std::runtime_error& e)
307     {
308         error(
309             "Failed to set remote terminus state effecter for effecter ID '{EFFECTERID}', error - {ERROR}",
310             "ERROR", e, "EFFECTERID", effecterId);
311         return;
312     }
313     if (rc != PLDM_SUCCESS)
314     {
315         error(
316             "Failed to set the remote terminus state effecter for effecter ID '{EFFECTERID}', response code '{RC}'",
317             "EFFECTERID", effecterId, "RC", rc);
318     }
319 }
320 
321 double HostEffecterParser::adjustValue(double value, double offset,
322                                        double resolution, int8_t modify)
323 {
324     double unitModifier = std::pow(10, signed(modify));
325     return std::round((value - offset) * resolution / unitModifier);
326 }
327 
328 void HostEffecterParser::processTerminusNumericEffecterChangeNotification(
329     const DbusChgHostEffecterProps& chProperties, size_t effecterInfoIndex,
330     size_t dbusInfoIndex, uint16_t effecterId)
331 {
332     const auto& checkHost = hostEffecterInfo[effecterInfoIndex].checkHostState;
333     const auto& propValues = hostEffecterInfo[effecterInfoIndex]
334                                  .dbusNumericEffecterInfo[dbusInfoIndex];
335     const auto& propertyName = propValues.dbusMap.propertyName;
336     const auto& propertyType = propValues.dbusMap.propertyType;
337 
338     if (effecterId == PLDM_INVALID_EFFECTER_ID)
339     {
340         lg2::error(
341             "Dbus to PLDM Numeric Effecter setting requires valid effecter ID. Invalid effecter ID {EFFECTER_ID}",
342             "EFFECTER_ID", effecterId);
343     }
344 
345     if (!dbusValueNumericTypeNames.contains(propertyType))
346     {
347         lg2::error(
348             "DBus Value to PLDM Numeric Effecter setting only supports D-Bus Numeric data type. Invalid type {TYPE}",
349             "TYPE", propertyType);
350         return;
351     }
352 
353     const auto& it = chProperties.find(propertyName);
354 
355     if (it == chProperties.end())
356     {
357         return;
358     }
359 
360     double val = std::numeric_limits<double>::quiet_NaN();
361     if (!pldm::utils::dbusPropValuesToDouble(propertyType, it->second, &val))
362     {
363         lg2::error(
364             "DBus Value to PLDM Numeric Effecter setting only supports Numeric D-Bus data type. Invalid type {TYPE}",
365             "TYPE", propertyType);
366         return;
367     }
368 
369     /* Update the current value of D-Bus interface*/
370     if (!std::isnan(val) && std::isnan(propValues.propertyValue))
371     {
372         hostEffecterInfo[effecterInfoIndex]
373             .dbusNumericEffecterInfo[dbusInfoIndex]
374             .propertyValue = val;
375         return;
376     }
377 
378     /* Bypass the setting when the current value is NA or setting value is NA */
379     if (std::isnan(propValues.propertyValue) || std::isnan(val))
380     {
381         return;
382     }
383 
384     /* Setting value equals the D-Bus value which is real value of effecter */
385     if (val == propValues.propertyValue)
386     {
387         return;
388     }
389 
390     double rawValue = adjustValue(val, propValues.offset, propValues.resolution,
391                                   propValues.unitModifier);
392 
393     if (checkHost && !isHostOn())
394     {
395         return;
396     }
397 
398     try
399     {
400         auto rc = setTerminusNumericEffecter(effecterInfoIndex, effecterId,
401                                              propValues.dataSize, rawValue);
402         if (rc)
403         {
404             error(
405                 "Could not set the numeric effecter ID '{EFFECTERID}' return code '{RC}'",
406                 "EFFECTERID", effecterId, "RC", rc);
407             return;
408         }
409     }
410     catch (const std::runtime_error& e)
411     {
412         error("Could not set numeric effecter ID= '{EFFECTERID}'", "EFFECTERID",
413               effecterId);
414         return;
415     }
416 
417     hostEffecterInfo[effecterInfoIndex]
418         .dbusNumericEffecterInfo[dbusInfoIndex]
419         .propertyValue = val;
420 
421     return;
422 }
423 
424 uint8_t HostEffecterParser::findNewStateValue(
425     size_t effecterInfoIndex, size_t dbusInfoIndex,
426     const PropertyValue& propertyValue)
427 {
428     const auto& propValues = hostEffecterInfo[effecterInfoIndex]
429                                  .dbusInfo[dbusInfoIndex]
430                                  .propertyValues;
431     auto it = std::find(propValues.begin(), propValues.end(), propertyValue);
432     uint8_t newState{};
433     if (it != propValues.end())
434     {
435         auto index = std::distance(propValues.begin(), it);
436         newState = hostEffecterInfo[effecterInfoIndex]
437                        .dbusInfo[dbusInfoIndex]
438                        .state.states[index];
439     }
440     else
441     {
442         throw std::out_of_range("new state not found in json");
443     }
444     return newState;
445 }
446 
447 size_t getEffecterDataSize(uint8_t effecterDataSize)
448 {
449     switch (effecterDataSize)
450     {
451         case PLDM_EFFECTER_DATA_SIZE_UINT8:
452             return sizeof(uint8_t);
453         case PLDM_EFFECTER_DATA_SIZE_SINT8:
454             return sizeof(int8_t);
455         case PLDM_EFFECTER_DATA_SIZE_UINT16:
456             return sizeof(uint16_t);
457         case PLDM_EFFECTER_DATA_SIZE_SINT16:
458             return sizeof(int16_t);
459         case PLDM_EFFECTER_DATA_SIZE_UINT32:
460             return sizeof(uint32_t);
461         case PLDM_EFFECTER_DATA_SIZE_SINT32:
462             return sizeof(int32_t);
463         default:
464             return 0;
465     }
466 }
467 
468 int HostEffecterParser::setTerminusNumericEffecter(
469     size_t effecterInfoIndex, uint16_t effecterId, uint8_t dataSize,
470     double rawValue)
471 {
472     uint8_t& mctpEid = hostEffecterInfo[effecterInfoIndex].mctpEid;
473     auto instanceId = instanceIdDb->next(mctpEid);
474     int rc = PLDM_ERROR;
475     std::vector<uint8_t> requestMsg;
476 
477     /**
478      * PLDM_SET_NUMERIC_EFFECTER_VALUE_MIN_REQ_BYTES = 4. It includes the 1 byte
479      * value for effecterValue as `Table 48 - SetNumericEffecterValue command
480      * format` DSP0248 V1.3.0 So the payload_length of `SetNumericEffecterValue`
481      * request message will be payload_length =
482      * PLDM_SET_NUMERIC_EFFECTER_VALUE_MIN_REQ_BYTES - 1 + sizeof(dataType)
483      */
484     size_t payload_length = PLDM_SET_NUMERIC_EFFECTER_VALUE_MIN_REQ_BYTES - 1 +
485                             getEffecterDataSize(dataSize);
486     requestMsg.resize(sizeof(pldm_msg_hdr) + payload_length);
487     auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
488     switch (dataSize)
489     {
490         case PLDM_EFFECTER_DATA_SIZE_UINT8:
491         {
492             auto value_uint8 = (uint8_t)rawValue;
493             rc = encode_set_numeric_effecter_value_req(
494                 instanceId, effecterId, dataSize,
495                 reinterpret_cast<uint8_t*>(&value_uint8), request,
496                 payload_length);
497             break;
498         }
499         case PLDM_EFFECTER_DATA_SIZE_SINT8:
500         {
501             auto value_int8 = (int8_t)rawValue;
502             rc = encode_set_numeric_effecter_value_req(
503                 instanceId, effecterId, dataSize,
504                 reinterpret_cast<uint8_t*>(&value_int8), request,
505                 payload_length);
506             break;
507         }
508         case PLDM_EFFECTER_DATA_SIZE_UINT16:
509         {
510             auto value_uint16 = (uint16_t)rawValue;
511             rc = encode_set_numeric_effecter_value_req(
512                 instanceId, effecterId, dataSize,
513                 reinterpret_cast<uint8_t*>(&value_uint16), request,
514                 payload_length);
515             break;
516         }
517         case PLDM_EFFECTER_DATA_SIZE_SINT16:
518         {
519             auto value_int16 = (int16_t)rawValue;
520             rc = encode_set_numeric_effecter_value_req(
521                 instanceId, effecterId, dataSize,
522                 reinterpret_cast<uint8_t*>(&value_int16), request,
523                 payload_length);
524             break;
525         }
526         case PLDM_EFFECTER_DATA_SIZE_UINT32:
527         {
528             auto value_uint32 = (uint32_t)rawValue;
529             rc = encode_set_numeric_effecter_value_req(
530                 instanceId, effecterId, dataSize,
531                 reinterpret_cast<uint8_t*>(&value_uint32), request,
532                 payload_length);
533             break;
534         }
535         case PLDM_EFFECTER_DATA_SIZE_SINT32:
536         {
537             auto value_int32 = (int32_t)rawValue;
538             rc = encode_set_numeric_effecter_value_req(
539                 instanceId, effecterId, dataSize,
540                 reinterpret_cast<uint8_t*>(&value_int32), request,
541                 payload_length);
542             break;
543         }
544         default:
545             break;
546     }
547 
548     if (rc)
549     {
550         error(
551             "Failed to encode set numeric effecter request message for effecter ID '{EFFECTERID}' and instanceID '{INSTANCE}' with error code '{RC}'",
552             "EFFECTERID", effecterId, "INSTANCE", instanceId, "RC", lg2::hex,
553             rc);
554 
555         instanceIdDb->free(mctpEid, instanceId);
556         return rc;
557     }
558 
559     auto setNumericEffecterRespHandler = [effecterId](mctp_eid_t /*eid*/,
560                                                       const pldm_msg* response,
561                                                       size_t respMsgLen) {
562         if (response == nullptr || !respMsgLen)
563         {
564             error(
565                 "Failed to receive response for setNumericEffecterValue command");
566             return;
567         }
568         uint8_t completionCode{};
569         auto rc = decode_set_numeric_effecter_value_resp(response, respMsgLen,
570                                                          &completionCode);
571 
572         if (rc)
573         {
574             error(
575                 "Failed to decode set numeric effecter response message for effecter ID '{EFFECTERID}' with error code '{RC}'",
576                 "EFFECTERID", effecterId, "RC", lg2::hex, rc);
577         }
578         if (completionCode)
579         {
580             error(
581                 "Failed to set numeric effecter for effecter ID '{EFFECTERID}' with complete code '{CC}'",
582                 "EFFECTERID", effecterId, "CC", lg2::hex, completionCode);
583         }
584     };
585 
586     rc = handler->registerRequest(
587         mctpEid, instanceId, PLDM_PLATFORM, PLDM_SET_NUMERIC_EFFECTER_VALUE,
588         std::move(requestMsg), std::move(setNumericEffecterRespHandler));
589     if (rc)
590     {
591         error("Failed to send request to set an effecter on Host");
592     }
593     return rc;
594 }
595 
596 int HostEffecterParser::setHostStateEffecter(
597     size_t effecterInfoIndex, std::vector<set_effecter_state_field>& stateField,
598     uint16_t effecterId)
599 {
600     uint8_t& mctpEid = hostEffecterInfo[effecterInfoIndex].mctpEid;
601     uint8_t& compEffCnt = hostEffecterInfo[effecterInfoIndex].compEffecterCnt;
602     auto instanceId = instanceIdDb->next(mctpEid);
603 
604     std::vector<uint8_t> requestMsg(
605         sizeof(pldm_msg_hdr) + sizeof(effecterId) + sizeof(compEffCnt) +
606             sizeof(set_effecter_state_field) * compEffCnt,
607         0);
608     auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
609     auto rc = encode_set_state_effecter_states_req(
610         instanceId, effecterId, compEffCnt, stateField.data(), request);
611 
612     if (rc != PLDM_SUCCESS)
613     {
614         error(
615             "Failed to encode set state effecter states message for effecter ID '{EFFECTERID}' and instanceID '{INSTANCE}' with response code '{RC}'",
616             "EFFECTERID", effecterId, "INSTANCE", instanceId, "RC", lg2::hex,
617             rc);
618         instanceIdDb->free(mctpEid, instanceId);
619         return rc;
620     }
621 
622     auto setStateEffecterStatesRespHandler = [](mctp_eid_t /*eid*/,
623                                                 const pldm_msg* response,
624                                                 size_t respMsgLen) {
625         if (response == nullptr || !respMsgLen)
626         {
627             error(
628                 "Failed to receive response for setting state effecter states.");
629             return;
630         }
631         uint8_t completionCode{};
632         auto rc = decode_set_state_effecter_states_resp(response, respMsgLen,
633                                                         &completionCode);
634         if (rc)
635         {
636             error(
637                 "Failed to decode response of set state effecter states, response code '{RC}'",
638                 "RC", rc);
639             pldm::utils::reportError(
640                 "xyz.openbmc_project.bmc.pldm.SetHostEffecterFailed");
641         }
642         if (completionCode)
643         {
644             error(
645                 "Failed to set a remote terminus effecter, completion code '{CC}'",
646                 "CC", completionCode);
647             pldm::utils::reportError(
648                 "xyz.openbmc_project.bmc.pldm.SetHostEffecterFailed");
649         }
650     };
651 
652     rc = handler->registerRequest(
653         mctpEid, instanceId, PLDM_PLATFORM, PLDM_SET_STATE_EFFECTER_STATES,
654         std::move(requestMsg), std::move(setStateEffecterStatesRespHandler));
655     if (rc)
656     {
657         error(
658             "Failed to send request to set an effecter on remote terminus for effecter ID '{EFFECTERID}', response code '{RC}'",
659             "EFFECTERID", effecterId, "RC", rc);
660     }
661     return rc;
662 }
663 
664 void HostEffecterParser::createHostEffecterMatch(
665     const std::string& objectPath, const std::string& interface,
666     size_t effecterInfoIndex, size_t dbusInfoIndex, uint16_t effecterId)
667 {
668     using namespace sdbusplus::bus::match::rules;
669     effecterInfoMatch.emplace_back(std::make_unique<sdbusplus::bus::match_t>(
670         pldm::utils::DBusHandler::getBus(),
671         propertiesChanged(objectPath, interface),
672         [this, effecterInfoIndex, dbusInfoIndex,
673          effecterId](sdbusplus::message_t& msg) {
674             DbusChgHostEffecterProps props;
675             std::string iface;
676             msg.read(iface, props);
677             processHostEffecterChangeNotification(props, effecterInfoIndex,
678                                                   dbusInfoIndex, effecterId);
679         }));
680 }
681 
682 } // namespace host_effecters
683 } // namespace pldm
684