1 #include "libpldm/entity.h"
2 #include "libpldm/state_set.h"
3 
4 #include "common/types.hpp"
5 #include "pldm_cmd_helper.hpp"
6 
7 namespace pldmtool
8 {
9 
10 namespace platform
11 {
12 
13 namespace
14 {
15 
16 using namespace pldmtool::helper;
17 std::vector<std::unique_ptr<CommandInterface>> commands;
18 
19 } // namespace
20 
21 using ordered_json = nlohmann::ordered_json;
22 
23 class GetPDR : public CommandInterface
24 {
25   public:
26     ~GetPDR() = default;
27     GetPDR() = delete;
28     GetPDR(const GetPDR&) = delete;
29     GetPDR(GetPDR&&) = default;
30     GetPDR& operator=(const GetPDR&) = delete;
31     GetPDR& operator=(GetPDR&&) = default;
32 
33     using CommandInterface::CommandInterface;
34 
35     explicit GetPDR(const char* type, const char* name, CLI::App* app) :
36         CommandInterface(type, name, app)
37     {
38         app->add_option(
39                "-d,--data", recordHandle,
40                "retrieve individual PDRs from a PDR Repository\n"
41                "eg: The recordHandle value for the PDR to be retrieved and 0 "
42                "means get first PDR in the repository.")
43             ->required();
44     }
45 
46     std::pair<int, std::vector<uint8_t>> createRequestMsg() override
47     {
48         std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
49                                         PLDM_GET_PDR_REQ_BYTES);
50         auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
51 
52         auto rc =
53             encode_get_pdr_req(instanceId, recordHandle, 0, PLDM_GET_FIRSTPART,
54                                UINT16_MAX, 0, request, PLDM_GET_PDR_REQ_BYTES);
55         return {rc, requestMsg};
56     }
57 
58     void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
59     {
60         uint8_t completionCode = 0;
61         uint8_t recordData[UINT16_MAX] = {0};
62         uint32_t nextRecordHndl = 0;
63         uint32_t nextDataTransferHndl = 0;
64         uint8_t transferFlag = 0;
65         uint16_t respCnt = 0;
66         uint8_t transferCRC = 0;
67 
68         auto rc = decode_get_pdr_resp(
69             responsePtr, payloadLength, &completionCode, &nextRecordHndl,
70             &nextDataTransferHndl, &transferFlag, &respCnt, recordData,
71             sizeof(recordData), &transferCRC);
72 
73         if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS)
74         {
75             std::cerr << "Response Message Error: "
76                       << "rc=" << rc << ",cc=" << (int)completionCode
77                       << std::endl;
78             return;
79         }
80 
81         printPDRMsg(nextRecordHndl, respCnt, recordData);
82     }
83 
84   private:
85     const std::map<pldm::pdr::EntityType, std::string> entityType = {
86         {PLDM_ENTITY_COMM_CHANNEL, "Communication Channel"},
87         {PLDM_ENTITY_SYS_FIRMWARE, "System Firmware"},
88         {PLDM_ENTITY_VIRTUAL_MACHINE_MANAGER, "Virtual Machine Manager"},
89         {PLDM_ENTITY_SYSTEM_CHASSIS, "System chassis (main enclosure)"},
90         {PLDM_ENTITY_SYS_BOARD, "System Board"},
91         {PLDM_ENTITY_MEMORY_MODULE, "Memory Module"},
92         {PLDM_ENTITY_PROC_MODULE, "Processor Module"},
93         {PLDM_ENTITY_CHASSIS_FRONT_PANEL_BOARD,
94          "Chassis front panel board (control panel)"},
95         {PLDM_ENTITY_POWER_CONVERTER, "Power converter"},
96         {PLDM_ENTITY_PROC, "Processor"},
97         {PLDM_ENTITY_MGMT_CONTROLLER, "Management Controller"},
98         {PLDM_ENTITY_CONNECTOR, "Connector"},
99         {PLDM_ENTITY_POWER_SUPPLY, "Power Supply"},
100         {11521, "System (logical)"},
101     };
102 
103     const std::map<uint16_t, std::string> stateSet = {
104         {PLDM_STATE_SET_HEALTH_STATE, "Health State"},
105         {PLDM_STATE_SET_AVAILABILITY, "Availability"},
106         {PLDM_STATE_SET_OPERATIONAL_STATUS, "Operational Status"},
107         {PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS,
108          "Operational Running Status"},
109         {PLDM_STATE_SET_PRESENCE, "Presence"},
110         {PLDM_STATE_SET_CONFIGURATION_STATE, "Configuration State"},
111         {PLDM_STATE_SET_LINK_STATE, "Link State"},
112         {PLDM_STATE_SET_SW_TERMINATION_STATUS, "Software Termination Status"},
113         {PLDM_STATE_SET_BOOT_RESTART_CAUSE, "Boot/Restart Cause"},
114         {PLDM_STATE_SET_BOOT_PROGRESS, "Boot Progress"},
115         {PLDM_STATE_SET_SYSTEM_POWER_STATE, "System Power State"},
116     };
117 
118     const std::array<std::string_view, 4> sensorInit = {
119         "noInit", "useInitPDR", "enableSensor", "disableSensor"};
120 
121     const std::array<std::string_view, 4> effecterInit = {
122         "noInit", "useInitPDR", "enableEffecter", "disableEffecter"};
123 
124     const std::map<uint8_t, std::string> pdrType = {
125         {PLDM_TERMINUS_LOCATOR_PDR, "Terminus Locator PDR"},
126         {PLDM_NUMERIC_SENSOR_PDR, "Numeric Sensor PDR"},
127         {PLDM_NUMERIC_SENSOR_INITIALIZATION_PDR,
128          "Numeric Sensor Initialization PDR"},
129         {PLDM_STATE_SENSOR_PDR, "State Sensor PDR"},
130         {PLDM_STATE_SENSOR_INITIALIZATION_PDR,
131          "State Sensor Initialization PDR"},
132         {PLDM_SENSOR_AUXILIARY_NAMES_PDR, "Sensor Auxiliary Names PDR"},
133         {PLDM_OEM_UNIT_PDR, "OEM Unit PDR"},
134         {PLDM_OEM_STATE_SET_PDR, "OEM State Set PDR"},
135         {PLDM_NUMERIC_EFFECTER_PDR, "Numeric Effecter PDR"},
136         {PLDM_NUMERIC_EFFECTER_INITIALIZATION_PDR,
137          "Numeric Effecter Initialization PDR"},
138         {PLDM_STATE_EFFECTER_PDR, "State Effecter PDR"},
139         {PLDM_STATE_EFFECTER_INITIALIZATION_PDR,
140          "State Effecter Initialization PDR"},
141         {PLDM_EFFECTER_AUXILIARY_NAMES_PDR, "Effecter Auxiliary Names PDR"},
142         {PLDM_EFFECTER_OEM_SEMANTIC_PDR, "Effecter OEM Semantic PDR"},
143         {PLDM_PDR_ENTITY_ASSOCIATION, "Entity Association PDR"},
144         {PLDM_ENTITY_AUXILIARY_NAMES_PDR, "Entity Auxiliary Names PDR"},
145         {PLDM_OEM_ENTITY_ID_PDR, "OEM Entity ID PDR"},
146         {PLDM_INTERRUPT_ASSOCIATION_PDR, "Interrupt Association PDR"},
147         {PLDM_EVENT_LOG_PDR, "PLDM Event Log PDR"},
148         {PLDM_PDR_FRU_RECORD_SET, "FRU Record Set PDR"},
149         {PLDM_OEM_DEVICE_PDR, "OEM Device PDR"},
150         {PLDM_OEM_PDR, "OEM PDR"},
151     };
152 
153     std::string getEntityName(pldm::pdr::EntityType type)
154     {
155         try
156         {
157             return entityType.at(type);
158         }
159         catch (const std::out_of_range& e)
160         {
161             return std::to_string(static_cast<unsigned>(type)) + "(OEM)";
162         }
163     }
164 
165     std::string getStateSetName(uint16_t id)
166     {
167         auto typeString = std::to_string(id);
168         try
169         {
170             return stateSet.at(id) + "(" + typeString + ")";
171         }
172         catch (const std::out_of_range& e)
173         {
174             return typeString;
175         }
176     }
177 
178     std::string getPDRType(uint8_t type)
179     {
180         auto typeString = std::to_string(type);
181         try
182         {
183             return pdrType.at(type);
184         }
185         catch (const std::out_of_range& e)
186         {
187             return typeString;
188         }
189     }
190 
191     void printCommonPDRHeader(const pldm_pdr_hdr* hdr, ordered_json& output)
192     {
193         output["recordHandle"] = hdr->record_handle;
194         output["PDRHeaderVersion"] = unsigned(hdr->version);
195         output["PDRType"] = getPDRType(hdr->type);
196         output["recordChangeNumber"] = hdr->record_change_num;
197         output["dataLength"] = hdr->length;
198     }
199 
200     std::string printPossibleStates(uint8_t possibleStatesSize,
201                                     const bitfield8_t* states)
202     {
203         uint8_t possibleStatesPos{};
204         std::string data;
205         auto printStates = [&possibleStatesPos, &data](const bitfield8_t& val) {
206             std::stringstream pstates;
207             for (int i = 0; i < CHAR_BIT; i++)
208             {
209                 if (val.byte & (1 << i))
210                 {
211                     pstates << " " << (possibleStatesPos * CHAR_BIT + i);
212                     data.append(pstates.str());
213                 }
214             }
215             possibleStatesPos++;
216         };
217         std::for_each(states, states + possibleStatesSize, printStates);
218         return data;
219     }
220 
221     void printStateSensorPDR(const uint8_t* data, ordered_json& output)
222     {
223         auto pdr = reinterpret_cast<const pldm_state_sensor_pdr*>(data);
224         output["PLDMTerminusHandle"] = pdr->terminus_handle;
225         output["sensorID"] = pdr->sensor_id;
226         output["entityType"] = getEntityName(pdr->entity_type);
227         output["entityInstanceNumber"] = pdr->entity_instance;
228         output["containerID"] = pdr->container_id;
229         output["sensorInit"] = sensorInit[pdr->sensor_init];
230         output["sensorAuxiliaryNamesPDR"] =
231             (pdr->sensor_auxiliary_names_pdr ? true : false);
232         output["compositeSensorCount"] = unsigned(pdr->composite_sensor_count);
233 
234         auto statesPtr = pdr->possible_states;
235         auto compositeSensorCount = pdr->composite_sensor_count;
236 
237         while (compositeSensorCount--)
238         {
239             auto state = reinterpret_cast<const state_sensor_possible_states*>(
240                 statesPtr);
241             output["stateSetID"] = getStateSetName(state->state_set_id);
242             output["possibleStatesSize"] = getStateSetName(state->state_set_id);
243             output["possibleStates"] =
244                 printPossibleStates(state->possible_states_size, state->states);
245 
246             if (compositeSensorCount)
247             {
248                 statesPtr += sizeof(state_sensor_possible_states) +
249                              state->possible_states_size - 1;
250             }
251         }
252     }
253 
254     void printPDRFruRecordSet(uint8_t* data, ordered_json& output)
255     {
256         if (data == NULL)
257         {
258             return;
259         }
260 
261         data += sizeof(pldm_pdr_hdr);
262         pldm_pdr_fru_record_set* pdr =
263             reinterpret_cast<pldm_pdr_fru_record_set*>(data);
264 
265         output["PLDMTerminusHandle"] = unsigned(pdr->terminus_handle);
266         output["FRURecordSetIdentifier"] = unsigned(pdr->fru_rsi);
267         output["entityType"] = getEntityName(pdr->entity_type);
268         output["entityInstanceNumber"] = unsigned(pdr->entity_instance_num);
269         output["containerID"] = unsigned(pdr->container_id);
270     }
271 
272     void printPDREntityAssociation(uint8_t* data, ordered_json& output)
273     {
274         const std::map<uint8_t, const char*> assocationType = {
275             {PLDM_ENTITY_ASSOCIAION_PHYSICAL, "Physical"},
276             {PLDM_ENTITY_ASSOCIAION_LOGICAL, "Logical"},
277         };
278 
279         if (data == NULL)
280         {
281             return;
282         }
283 
284         data += sizeof(pldm_pdr_hdr);
285         pldm_pdr_entity_association* pdr =
286             reinterpret_cast<pldm_pdr_entity_association*>(data);
287 
288         output["containerID"] = int(pdr->container_id);
289         output["associationType"] = assocationType.at(pdr->association_type);
290         output["containerEntityType"] =
291             getEntityName(pdr->container.entity_type);
292         output["containerEntityInstanceNumber"] =
293             int(pdr->container.entity_instance_num);
294         output["containerEntityContainerID"] =
295             int(pdr->container.entity_container_id);
296         output["containedEntityCount"] =
297             static_cast<unsigned>(pdr->num_children);
298 
299         auto child = reinterpret_cast<pldm_entity*>(&pdr->children[0]);
300         for (int i = 0; i < pdr->num_children; ++i)
301         {
302             output.emplace("containedEntityType[" + std::to_string(i + 1) + "]",
303                            getEntityName(child->entity_type));
304             output.emplace("containedEntityInstanceNumber[" +
305                                std::to_string(i + 1) + "]",
306                            unsigned(child->entity_instance_num));
307             output.emplace("containedEntityContainerID[" +
308                                std::to_string(i + 1) + "]",
309                            unsigned(child->entity_container_id));
310 
311             ++child;
312         }
313     }
314 
315     void printNumericEffecterPDR(uint8_t* data, ordered_json& output)
316     {
317         struct pldm_numeric_effecter_value_pdr* pdr =
318             (struct pldm_numeric_effecter_value_pdr*)data;
319 
320         output["PLDMTerminusHandle"] = int(pdr->terminus_handle);
321         output["effecterID"] = int(pdr->effecter_id);
322         output["entityType"] = int(pdr->entity_type);
323         output["entityInstanceNumber"] = int(pdr->entity_instance);
324         output["containerID"] = int(pdr->container_id);
325         output["effecterSemanticID"] = int(pdr->effecter_semantic_id);
326         output["effecterInit"] = unsigned(pdr->effecter_init);
327         output["effecterAuxiliaryNames"] =
328             (unsigned(pdr->effecter_auxiliary_names) ? true : false);
329         output["baseUnit"] = unsigned(pdr->base_unit);
330         output["unitModifier"] = unsigned(pdr->unit_modifier);
331         output["rateUnit"] = unsigned(pdr->rate_unit);
332         output["baseOEMUnitHandle"] = unsigned(pdr->base_oem_unit_handle);
333         output["auxUnit"] = unsigned(pdr->aux_unit);
334         output["auxUnitModifier"] = unsigned(pdr->aux_unit_modifier);
335         output["auxrateUnit"] = unsigned(pdr->aux_rate_unit);
336         output["auxOEMUnitHandle"] = unsigned(pdr->aux_oem_unit_handle);
337         output["isLinear"] = (unsigned(pdr->is_linear) ? true : false);
338         output["effecterDataSize"] = unsigned(pdr->effecter_data_size);
339         output["resolution"] = unsigned(pdr->resolution);
340         output["offset"] = unsigned(pdr->offset);
341         output["accuracy"] = unsigned(pdr->accuracy);
342         output["plusTolerance"] = unsigned(pdr->plus_tolerance);
343         output["minusTolerance"] = unsigned(pdr->minus_tolerance);
344         output["stateTransitionInterval"] =
345             unsigned(pdr->state_transition_interval);
346         output["TransitionInterval"] = unsigned(pdr->transition_interval);
347 
348         switch (pdr->effecter_data_size)
349         {
350             case PLDM_EFFECTER_DATA_SIZE_UINT8:
351                 output["maxSettable"] = unsigned(pdr->max_set_table.value_u8);
352                 output["minSettable"] = unsigned(pdr->min_set_table.value_u8);
353                 break;
354             case PLDM_EFFECTER_DATA_SIZE_SINT8:
355                 output["maxSettable"] = unsigned(pdr->max_set_table.value_s8);
356                 output["minSettable"] = unsigned(pdr->min_set_table.value_s8);
357                 break;
358             case PLDM_EFFECTER_DATA_SIZE_UINT16:
359                 output["maxSettable"] = unsigned(pdr->max_set_table.value_u16);
360                 output["minSettable"] = unsigned(pdr->min_set_table.value_u16);
361                 break;
362             case PLDM_EFFECTER_DATA_SIZE_SINT16:
363                 output["maxSettable"] = unsigned(pdr->max_set_table.value_s16);
364                 output["minSettable"] = unsigned(pdr->min_set_table.value_s16);
365                 break;
366             case PLDM_EFFECTER_DATA_SIZE_UINT32:
367                 output["maxSettable"] = unsigned(pdr->max_set_table.value_u32);
368                 output["minSettable"] = unsigned(pdr->min_set_table.value_u32);
369                 break;
370             case PLDM_EFFECTER_DATA_SIZE_SINT32:
371                 output["maxSettable"] = unsigned(pdr->max_set_table.value_s32);
372                 output["minSettable"] = unsigned(pdr->min_set_table.value_s32);
373                 break;
374             default:
375                 break;
376         }
377 
378         output["rangeFieldFormat"] = unsigned(pdr->range_field_format);
379         output["rangeFieldSupport"] = unsigned(pdr->range_field_support.byte);
380 
381         switch (pdr->range_field_format)
382         {
383             case PLDM_RANGE_FIELD_FORMAT_UINT8:
384                 output["nominalValue"] = unsigned(pdr->nominal_value.value_u8);
385                 output["normalMax"] = unsigned(pdr->normal_max.value_u8);
386                 output["normalMin"] = unsigned(pdr->normal_min.value_u8);
387                 output["ratedMax"] = unsigned(pdr->rated_max.value_u8);
388                 output["ratedMin"] = unsigned(pdr->rated_min.value_u8);
389                 break;
390             case PLDM_RANGE_FIELD_FORMAT_SINT8:
391                 output["nominalValue"] = unsigned(pdr->nominal_value.value_s8);
392                 output["normalMax"] = unsigned(pdr->normal_max.value_s8);
393                 output["normalMin"] = unsigned(pdr->normal_min.value_s8);
394                 output["ratedMax"] = unsigned(pdr->rated_max.value_s8);
395                 output["ratedMin"] = unsigned(pdr->rated_min.value_s8);
396                 break;
397             case PLDM_RANGE_FIELD_FORMAT_UINT16:
398                 output["nominalValue"] = unsigned(pdr->nominal_value.value_u16);
399                 output["normalMax"] = unsigned(pdr->normal_max.value_u16);
400                 output["normalMin"] = unsigned(pdr->normal_min.value_u16);
401                 output["ratedMax"] = unsigned(pdr->rated_max.value_u16);
402                 output["ratedMin"] = unsigned(pdr->rated_min.value_u16);
403                 break;
404             case PLDM_RANGE_FIELD_FORMAT_SINT16:
405                 output["nominalValue"] = unsigned(pdr->nominal_value.value_s16);
406                 output["normalMax"] = unsigned(pdr->normal_max.value_s16);
407                 output["normalMin"] = unsigned(pdr->normal_min.value_s16);
408                 output["ratedMax"] = unsigned(pdr->rated_max.value_s16);
409                 output["ratedMin"] = unsigned(pdr->rated_min.value_s16);
410                 break;
411             case PLDM_RANGE_FIELD_FORMAT_UINT32:
412                 output["nominalValue"] = unsigned(pdr->nominal_value.value_u32);
413                 output["normalMax"] = unsigned(pdr->normal_max.value_u32);
414                 output["normalMin"] = unsigned(pdr->normal_min.value_u32);
415                 output["ratedMax"] = unsigned(pdr->rated_max.value_u32);
416                 output["ratedMin"] = unsigned(pdr->rated_min.value_u32);
417                 break;
418             case PLDM_RANGE_FIELD_FORMAT_SINT32:
419                 output["nominalValue"] = unsigned(pdr->nominal_value.value_s32);
420                 output["normalMax"] = unsigned(pdr->normal_max.value_s32);
421                 output["normalMin"] = unsigned(pdr->normal_min.value_s32);
422                 output["ratedMax"] = unsigned(pdr->rated_max.value_s32);
423                 output["ratedMin"] = unsigned(pdr->rated_min.value_s32);
424                 break;
425             case PLDM_RANGE_FIELD_FORMAT_REAL32:
426                 output["nominalValue"] = unsigned(pdr->nominal_value.value_f32);
427                 output["normalMax"] = unsigned(pdr->normal_max.value_f32);
428                 output["normalMin"] = unsigned(pdr->normal_min.value_f32);
429                 output["ratedMax"] = unsigned(pdr->rated_max.value_f32);
430                 output["ratedMin"] = unsigned(pdr->rated_min.value_f32);
431                 break;
432             default:
433                 break;
434         }
435     }
436 
437     void printStateEffecterPDR(const uint8_t* data, ordered_json& output)
438     {
439         auto pdr = reinterpret_cast<const pldm_state_effecter_pdr*>(data);
440 
441         output["PLDMTerminusHandle"] = pdr->terminus_handle;
442         output["effecterID"] = pdr->effecter_id;
443         output["entityType"] = getEntityName(pdr->entity_type);
444         output["entityInstanceNumber"] = pdr->entity_instance;
445         output["containerID"] = pdr->container_id;
446         output["effecterSemanticID"] = pdr->effecter_semantic_id;
447         output["effecterInit"] = effecterInit[pdr->effecter_init];
448         output["effecterDescriptionPDR"] =
449             (pdr->has_description_pdr ? true : false);
450         output["compositeEffecterCount"] =
451             unsigned(pdr->composite_effecter_count);
452 
453         auto statesPtr = pdr->possible_states;
454         auto compositeEffecterCount = pdr->composite_effecter_count;
455 
456         while (compositeEffecterCount--)
457         {
458             auto state =
459                 reinterpret_cast<const state_effecter_possible_states*>(
460                     statesPtr);
461 
462             output["stateSetID"] = getStateSetName(state->state_set_id);
463             output["possibleStatesSize"] = (state->possible_states_size);
464             output["possibleStates"] =
465                 printPossibleStates(state->possible_states_size, state->states);
466 
467             if (compositeEffecterCount)
468             {
469                 statesPtr += sizeof(state_effecter_possible_states) +
470                              state->possible_states_size - 1;
471             }
472         }
473     }
474 
475     void printTerminusLocatorPDR(const uint8_t* data, ordered_json& output)
476     {
477         const std::array<std::string_view, 4> terminusLocatorType = {
478             "UID", "MCTP_EID", "SMBusRelative", "systemSoftware"};
479 
480         auto pdr = reinterpret_cast<const pldm_terminus_locator_pdr*>(data);
481 
482         output["PLDMTerminusHandle"] = pdr->terminus_handle;
483         output["validity"] = (pdr->validity ? "valid" : "notValid");
484         output["TID"] = unsigned(pdr->tid);
485         output["containerID"] = pdr->container_id;
486         output["terminusLocatorType"] =
487             terminusLocatorType[pdr->terminus_locator_type];
488         output["terminusLocatorValueSize"] =
489             unsigned(pdr->terminus_locator_value_size);
490 
491         if (pdr->terminus_locator_type == PLDM_TERMINUS_LOCATOR_TYPE_MCTP_EID)
492         {
493             auto locatorValue =
494                 reinterpret_cast<const pldm_terminus_locator_type_mctp_eid*>(
495                     pdr->terminus_locator_value);
496             output["EID"] = unsigned(locatorValue->eid);
497         }
498     }
499 
500     void printPDRMsg(const uint32_t nextRecordHndl, const uint16_t respCnt,
501                      uint8_t* data)
502     {
503         if (data == NULL)
504         {
505             return;
506         }
507 
508         ordered_json output;
509         output["nextRecordHandle"] = nextRecordHndl;
510         output["responseCount"] = respCnt;
511 
512         struct pldm_pdr_hdr* pdr = (struct pldm_pdr_hdr*)data;
513         printCommonPDRHeader(pdr, output);
514 
515         switch (pdr->type)
516         {
517             case PLDM_TERMINUS_LOCATOR_PDR:
518                 printTerminusLocatorPDR(data, output);
519                 break;
520             case PLDM_STATE_SENSOR_PDR:
521                 printStateSensorPDR(data, output);
522                 break;
523             case PLDM_NUMERIC_EFFECTER_PDR:
524                 printNumericEffecterPDR(data, output);
525                 break;
526             case PLDM_STATE_EFFECTER_PDR:
527                 printStateEffecterPDR(data, output);
528                 break;
529             case PLDM_PDR_ENTITY_ASSOCIATION:
530                 printPDREntityAssociation(data, output);
531                 break;
532             case PLDM_PDR_FRU_RECORD_SET:
533                 printPDRFruRecordSet(data, output);
534                 break;
535             default:
536                 break;
537         }
538         pldmtool::helper::DisplayInJson(output);
539     }
540 
541   private:
542     uint32_t recordHandle;
543 };
544 
545 class SetStateEffecter : public CommandInterface
546 {
547   public:
548     ~SetStateEffecter() = default;
549     SetStateEffecter() = delete;
550     SetStateEffecter(const SetStateEffecter&) = delete;
551     SetStateEffecter(SetStateEffecter&&) = default;
552     SetStateEffecter& operator=(const SetStateEffecter&) = delete;
553     SetStateEffecter& operator=(SetStateEffecter&&) = default;
554 
555     // compositeEffecterCount(value: 0x01 to 0x08) * stateField(2)
556     static constexpr auto maxEffecterDataSize = 16;
557 
558     // compositeEffecterCount(value: 0x01 to 0x08)
559     static constexpr auto minEffecterCount = 1;
560     static constexpr auto maxEffecterCount = 8;
561     explicit SetStateEffecter(const char* type, const char* name,
562                               CLI::App* app) :
563         CommandInterface(type, name, app)
564     {
565         app->add_option(
566                "-i, --id", effecterId,
567                "A handle that is used to identify and access the effecter")
568             ->required();
569         app->add_option("-c, --count", effecterCount,
570                         "The number of individual sets of effecter information")
571             ->required();
572         app->add_option(
573                "-d,--data", effecterData,
574                "Set effecter state data\n"
575                "eg: requestSet0 effecterState0 noChange1 dummyState1 ...")
576             ->required();
577     }
578 
579     std::pair<int, std::vector<uint8_t>> createRequestMsg() override
580     {
581         std::vector<uint8_t> requestMsg(
582             sizeof(pldm_msg_hdr) + PLDM_SET_STATE_EFFECTER_STATES_REQ_BYTES);
583         auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
584 
585         if (effecterCount > maxEffecterCount ||
586             effecterCount < minEffecterCount)
587         {
588             std::cerr << "Request Message Error: effecterCount size "
589                       << effecterCount << "is invalid\n";
590             auto rc = PLDM_ERROR_INVALID_DATA;
591             return {rc, requestMsg};
592         }
593 
594         if (effecterData.size() > maxEffecterDataSize)
595         {
596             std::cerr << "Request Message Error: effecterData size "
597                       << effecterData.size() << "is invalid\n";
598             auto rc = PLDM_ERROR_INVALID_DATA;
599             return {rc, requestMsg};
600         }
601 
602         auto stateField = parseEffecterData(effecterData, effecterCount);
603         if (!stateField)
604         {
605             std::cerr << "Failed to parse effecter data, effecterCount size "
606                       << effecterCount << "\n";
607             auto rc = PLDM_ERROR_INVALID_DATA;
608             return {rc, requestMsg};
609         }
610 
611         auto rc = encode_set_state_effecter_states_req(
612             instanceId, effecterId, effecterCount, stateField->data(), request);
613         return {rc, requestMsg};
614     }
615 
616     void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
617     {
618         uint8_t completionCode = 0;
619         auto rc = decode_set_state_effecter_states_resp(
620             responsePtr, payloadLength, &completionCode);
621 
622         if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS)
623         {
624             std::cerr << "Response Message Error: "
625                       << "rc=" << rc << ",cc=" << (int)completionCode << "\n";
626             return;
627         }
628 
629         ordered_json data;
630         data["Response"] = "SUCCESS";
631         pldmtool::helper::DisplayInJson(data);
632     }
633 
634   private:
635     uint16_t effecterId;
636     uint8_t effecterCount;
637     std::vector<uint8_t> effecterData;
638 };
639 
640 class SetNumericEffecterValue : public CommandInterface
641 {
642   public:
643     ~SetNumericEffecterValue() = default;
644     SetNumericEffecterValue() = delete;
645     SetNumericEffecterValue(const SetNumericEffecterValue&) = delete;
646     SetNumericEffecterValue(SetNumericEffecterValue&&) = default;
647     SetNumericEffecterValue& operator=(const SetNumericEffecterValue&) = delete;
648     SetNumericEffecterValue& operator=(SetNumericEffecterValue&&) = default;
649 
650     explicit SetNumericEffecterValue(const char* type, const char* name,
651                                      CLI::App* app) :
652         CommandInterface(type, name, app)
653     {
654         app->add_option(
655                "-i, --id", effecterId,
656                "A handle that is used to identify and access the effecter")
657             ->required();
658         app->add_option("-s, --size", effecterDataSize,
659                         "The bit width and format of the setting value for the "
660                         "effecter. enum value: {uint8, sint8, uint16, sint16, "
661                         "uint32, sint32}\n")
662             ->required();
663         app->add_option("-d,--data", maxEffecterValue,
664                         "The setting value of numeric effecter being "
665                         "requested\n")
666             ->required();
667     }
668 
669     std::pair<int, std::vector<uint8_t>> createRequestMsg() override
670     {
671         std::vector<uint8_t> requestMsg(
672             sizeof(pldm_msg_hdr) +
673             PLDM_SET_NUMERIC_EFFECTER_VALUE_MIN_REQ_BYTES + 3);
674 
675         uint8_t* effecterValue = (uint8_t*)&maxEffecterValue;
676 
677         auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
678         size_t payload_length = PLDM_SET_NUMERIC_EFFECTER_VALUE_MIN_REQ_BYTES;
679 
680         if (effecterDataSize == PLDM_EFFECTER_DATA_SIZE_UINT16 ||
681             effecterDataSize == PLDM_EFFECTER_DATA_SIZE_SINT16)
682         {
683             payload_length = PLDM_SET_NUMERIC_EFFECTER_VALUE_MIN_REQ_BYTES + 1;
684         }
685         if (effecterDataSize == PLDM_EFFECTER_DATA_SIZE_UINT32 ||
686             effecterDataSize == PLDM_EFFECTER_DATA_SIZE_SINT32)
687         {
688             payload_length = PLDM_SET_NUMERIC_EFFECTER_VALUE_MIN_REQ_BYTES + 3;
689         }
690         auto rc = encode_set_numeric_effecter_value_req(
691             0, effecterId, effecterDataSize, effecterValue, request,
692             payload_length);
693 
694         return {rc, requestMsg};
695     }
696 
697     void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
698     {
699         uint8_t completionCode = 0;
700         auto rc = decode_set_numeric_effecter_value_resp(
701             responsePtr, payloadLength, &completionCode);
702 
703         if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS)
704         {
705             std::cerr << "Response Message Error: "
706                       << "rc=" << rc << ",cc=" << (int)completionCode
707                       << std::endl;
708             return;
709         }
710 
711         ordered_json data;
712         data["Response"] = "SUCCESS";
713         pldmtool::helper::DisplayInJson(data);
714     }
715 
716   private:
717     uint16_t effecterId;
718     uint8_t effecterDataSize;
719     uint64_t maxEffecterValue;
720 };
721 
722 void registerCommand(CLI::App& app)
723 {
724     auto platform = app.add_subcommand("platform", "platform type command");
725     platform->require_subcommand(1);
726 
727     auto getPDR =
728         platform->add_subcommand("GetPDR", "get platform descriptor records");
729     commands.push_back(std::make_unique<GetPDR>("platform", "getPDR", getPDR));
730 
731     auto setStateEffecterStates = platform->add_subcommand(
732         "SetStateEffecterStates", "set effecter states");
733     commands.push_back(std::make_unique<SetStateEffecter>(
734         "platform", "setStateEffecterStates", setStateEffecterStates));
735 
736     auto setNumericEffecterValue = platform->add_subcommand(
737         "SetNumericEffecterValue", "set the value for a PLDM Numeric Effecter");
738     commands.push_back(std::make_unique<SetNumericEffecterValue>(
739         "platform", "setNumericEffecterValue", setNumericEffecterValue));
740 }
741 
742 } // namespace platform
743 } // namespace pldmtool
744