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