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