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         if (assocationType.contains(pdr->association_type))
331         {
332             output["associationType"] =
333                 assocationType.at(pdr->association_type);
334         }
335         else
336         {
337             std::cout << "Get associationType failed.\n";
338         }
339         output["containerEntityType"] =
340             getEntityName(pdr->container.entity_type);
341         output["containerEntityInstanceNumber"] =
342             int(pdr->container.entity_instance_num);
343         output["containerEntityContainerID"] =
344             int(pdr->container.entity_container_id);
345         output["containedEntityCount"] =
346             static_cast<unsigned>(pdr->num_children);
347 
348         auto child = reinterpret_cast<pldm_entity*>(&pdr->children[0]);
349         for (int i = 0; i < pdr->num_children; ++i)
350         {
351             output.emplace("containedEntityType[" + std::to_string(i + 1) + "]",
352                            getEntityName(child->entity_type));
353             output.emplace("containedEntityInstanceNumber[" +
354                                std::to_string(i + 1) + "]",
355                            unsigned(child->entity_instance_num));
356             output.emplace("containedEntityContainerID[" +
357                                std::to_string(i + 1) + "]",
358                            unsigned(child->entity_container_id));
359 
360             ++child;
361         }
362     }
363 
364     void printNumericEffecterPDR(uint8_t* data, ordered_json& output)
365     {
366         struct pldm_numeric_effecter_value_pdr* pdr =
367             (struct pldm_numeric_effecter_value_pdr*)data;
368         if (!pdr)
369         {
370             std::cerr << "Failed to get numeric effecter PDR" << std::endl;
371             return;
372         }
373 
374         output["PLDMTerminusHandle"] = int(pdr->terminus_handle);
375         output["effecterID"] = int(pdr->effecter_id);
376         output["entityType"] = int(pdr->entity_type);
377         output["entityInstanceNumber"] = int(pdr->entity_instance);
378         output["containerID"] = int(pdr->container_id);
379         output["effecterSemanticID"] = int(pdr->effecter_semantic_id);
380         output["effecterInit"] = unsigned(pdr->effecter_init);
381         output["effecterAuxiliaryNames"] =
382             (unsigned(pdr->effecter_auxiliary_names) ? true : false);
383         output["baseUnit"] = unsigned(pdr->base_unit);
384         output["unitModifier"] = unsigned(pdr->unit_modifier);
385         output["rateUnit"] = unsigned(pdr->rate_unit);
386         output["baseOEMUnitHandle"] = unsigned(pdr->base_oem_unit_handle);
387         output["auxUnit"] = unsigned(pdr->aux_unit);
388         output["auxUnitModifier"] = unsigned(pdr->aux_unit_modifier);
389         output["auxrateUnit"] = unsigned(pdr->aux_rate_unit);
390         output["auxOEMUnitHandle"] = unsigned(pdr->aux_oem_unit_handle);
391         output["isLinear"] = (unsigned(pdr->is_linear) ? true : false);
392         output["effecterDataSize"] = unsigned(pdr->effecter_data_size);
393         output["resolution"] = unsigned(pdr->resolution);
394         output["offset"] = unsigned(pdr->offset);
395         output["accuracy"] = unsigned(pdr->accuracy);
396         output["plusTolerance"] = unsigned(pdr->plus_tolerance);
397         output["minusTolerance"] = unsigned(pdr->minus_tolerance);
398         output["stateTransitionInterval"] =
399             unsigned(pdr->state_transition_interval);
400         output["TransitionInterval"] = unsigned(pdr->transition_interval);
401 
402         switch (pdr->effecter_data_size)
403         {
404             case PLDM_EFFECTER_DATA_SIZE_UINT8:
405                 output["maxSettable"] = unsigned(pdr->max_set_table.value_u8);
406                 output["minSettable"] = unsigned(pdr->min_set_table.value_u8);
407                 break;
408             case PLDM_EFFECTER_DATA_SIZE_SINT8:
409                 output["maxSettable"] = unsigned(pdr->max_set_table.value_s8);
410                 output["minSettable"] = unsigned(pdr->min_set_table.value_s8);
411                 break;
412             case PLDM_EFFECTER_DATA_SIZE_UINT16:
413                 output["maxSettable"] = unsigned(pdr->max_set_table.value_u16);
414                 output["minSettable"] = unsigned(pdr->min_set_table.value_u16);
415                 break;
416             case PLDM_EFFECTER_DATA_SIZE_SINT16:
417                 output["maxSettable"] = unsigned(pdr->max_set_table.value_s16);
418                 output["minSettable"] = unsigned(pdr->min_set_table.value_s16);
419                 break;
420             case PLDM_EFFECTER_DATA_SIZE_UINT32:
421                 output["maxSettable"] = unsigned(pdr->max_set_table.value_u32);
422                 output["minSettable"] = unsigned(pdr->min_set_table.value_u32);
423                 break;
424             case PLDM_EFFECTER_DATA_SIZE_SINT32:
425                 output["maxSettable"] = unsigned(pdr->max_set_table.value_s32);
426                 output["minSettable"] = unsigned(pdr->min_set_table.value_s32);
427                 break;
428             default:
429                 break;
430         }
431 
432         output["rangeFieldFormat"] = unsigned(pdr->range_field_format);
433         output["rangeFieldSupport"] = unsigned(pdr->range_field_support.byte);
434 
435         switch (pdr->range_field_format)
436         {
437             case PLDM_RANGE_FIELD_FORMAT_UINT8:
438                 output["nominalValue"] = unsigned(pdr->nominal_value.value_u8);
439                 output["normalMax"] = unsigned(pdr->normal_max.value_u8);
440                 output["normalMin"] = unsigned(pdr->normal_min.value_u8);
441                 output["ratedMax"] = unsigned(pdr->rated_max.value_u8);
442                 output["ratedMin"] = unsigned(pdr->rated_min.value_u8);
443                 break;
444             case PLDM_RANGE_FIELD_FORMAT_SINT8:
445                 output["nominalValue"] = unsigned(pdr->nominal_value.value_s8);
446                 output["normalMax"] = unsigned(pdr->normal_max.value_s8);
447                 output["normalMin"] = unsigned(pdr->normal_min.value_s8);
448                 output["ratedMax"] = unsigned(pdr->rated_max.value_s8);
449                 output["ratedMin"] = unsigned(pdr->rated_min.value_s8);
450                 break;
451             case PLDM_RANGE_FIELD_FORMAT_UINT16:
452                 output["nominalValue"] = unsigned(pdr->nominal_value.value_u16);
453                 output["normalMax"] = unsigned(pdr->normal_max.value_u16);
454                 output["normalMin"] = unsigned(pdr->normal_min.value_u16);
455                 output["ratedMax"] = unsigned(pdr->rated_max.value_u16);
456                 output["ratedMin"] = unsigned(pdr->rated_min.value_u16);
457                 break;
458             case PLDM_RANGE_FIELD_FORMAT_SINT16:
459                 output["nominalValue"] = unsigned(pdr->nominal_value.value_s16);
460                 output["normalMax"] = unsigned(pdr->normal_max.value_s16);
461                 output["normalMin"] = unsigned(pdr->normal_min.value_s16);
462                 output["ratedMax"] = unsigned(pdr->rated_max.value_s16);
463                 output["ratedMin"] = unsigned(pdr->rated_min.value_s16);
464                 break;
465             case PLDM_RANGE_FIELD_FORMAT_UINT32:
466                 output["nominalValue"] = unsigned(pdr->nominal_value.value_u32);
467                 output["normalMax"] = unsigned(pdr->normal_max.value_u32);
468                 output["normalMin"] = unsigned(pdr->normal_min.value_u32);
469                 output["ratedMax"] = unsigned(pdr->rated_max.value_u32);
470                 output["ratedMin"] = unsigned(pdr->rated_min.value_u32);
471                 break;
472             case PLDM_RANGE_FIELD_FORMAT_SINT32:
473                 output["nominalValue"] = unsigned(pdr->nominal_value.value_s32);
474                 output["normalMax"] = unsigned(pdr->normal_max.value_s32);
475                 output["normalMin"] = unsigned(pdr->normal_min.value_s32);
476                 output["ratedMax"] = unsigned(pdr->rated_max.value_s32);
477                 output["ratedMin"] = unsigned(pdr->rated_min.value_s32);
478                 break;
479             case PLDM_RANGE_FIELD_FORMAT_REAL32:
480                 output["nominalValue"] = unsigned(pdr->nominal_value.value_f32);
481                 output["normalMax"] = unsigned(pdr->normal_max.value_f32);
482                 output["normalMin"] = unsigned(pdr->normal_min.value_f32);
483                 output["ratedMax"] = unsigned(pdr->rated_max.value_f32);
484                 output["ratedMin"] = unsigned(pdr->rated_min.value_f32);
485                 break;
486             default:
487                 break;
488         }
489     }
490 
491     void printStateEffecterPDR(const uint8_t* data, ordered_json& output)
492     {
493         auto pdr = reinterpret_cast<const pldm_state_effecter_pdr*>(data);
494 
495         output["PLDMTerminusHandle"] = pdr->terminus_handle;
496         output["effecterID"] = pdr->effecter_id;
497         output["entityType"] = getEntityName(pdr->entity_type);
498         output["entityInstanceNumber"] = pdr->entity_instance;
499         output["containerID"] = pdr->container_id;
500         output["effecterSemanticID"] = pdr->effecter_semantic_id;
501         output["effecterInit"] = effecterInit[pdr->effecter_init];
502         output["effecterDescriptionPDR"] =
503             (pdr->has_description_pdr ? true : false);
504         output["compositeEffecterCount"] =
505             unsigned(pdr->composite_effecter_count);
506 
507         auto statesPtr = pdr->possible_states;
508         auto compEffCount = pdr->composite_effecter_count;
509 
510         while (compEffCount--)
511         {
512             auto state =
513                 reinterpret_cast<const state_effecter_possible_states*>(
514                     statesPtr);
515             output.emplace(("stateSetID[" + std::to_string(compEffCount) + "]"),
516                            getStateSetName(state->state_set_id));
517             output.emplace(
518                 ("possibleStatesSize[" + std::to_string(compEffCount) + "]"),
519                 state->possible_states_size);
520             output.emplace(
521                 ("possibleStates[" + std::to_string(compEffCount) + "]"),
522                 printPossibleStates(state->possible_states_size,
523                                     state->states));
524 
525             if (compEffCount)
526             {
527                 statesPtr += sizeof(state_effecter_possible_states) +
528                              state->possible_states_size - 1;
529             }
530         }
531     }
532 
533     void printTerminusLocatorPDR(const uint8_t* data, ordered_json& output)
534     {
535         const std::array<std::string_view, 4> terminusLocatorType = {
536             "UID", "MCTP_EID", "SMBusRelative", "systemSoftware"};
537 
538         auto pdr = reinterpret_cast<const pldm_terminus_locator_pdr*>(data);
539 
540         output["PLDMTerminusHandle"] = pdr->terminus_handle;
541         output["validity"] = (pdr->validity ? "valid" : "notValid");
542         output["TID"] = unsigned(pdr->tid);
543         output["containerID"] = pdr->container_id;
544         output["terminusLocatorType"] =
545             terminusLocatorType[pdr->terminus_locator_type];
546         output["terminusLocatorValueSize"] =
547             unsigned(pdr->terminus_locator_value_size);
548 
549         if (pdr->terminus_locator_type == PLDM_TERMINUS_LOCATOR_TYPE_MCTP_EID)
550         {
551             auto locatorValue =
552                 reinterpret_cast<const pldm_terminus_locator_type_mctp_eid*>(
553                     pdr->terminus_locator_value);
554             output["EID"] = unsigned(locatorValue->eid);
555         }
556     }
557 
558     void printPDRMsg(const uint32_t nextRecordHndl, const uint16_t respCnt,
559                      uint8_t* data)
560     {
561         if (data == NULL)
562         {
563             std::cerr << "Failed to get PDR message" << std::endl;
564             return;
565         }
566 
567         ordered_json output;
568         output["nextRecordHandle"] = nextRecordHndl;
569         output["responseCount"] = respCnt;
570 
571         struct pldm_pdr_hdr* pdr = (struct pldm_pdr_hdr*)data;
572         if (!pdr)
573         {
574             return;
575         }
576         printCommonPDRHeader(pdr, output);
577 
578         switch (pdr->type)
579         {
580             case PLDM_TERMINUS_LOCATOR_PDR:
581                 printTerminusLocatorPDR(data, output);
582                 break;
583             case PLDM_STATE_SENSOR_PDR:
584                 printStateSensorPDR(data, output);
585                 break;
586             case PLDM_NUMERIC_EFFECTER_PDR:
587                 printNumericEffecterPDR(data, output);
588                 break;
589             case PLDM_STATE_EFFECTER_PDR:
590                 printStateEffecterPDR(data, output);
591                 break;
592             case PLDM_PDR_ENTITY_ASSOCIATION:
593                 printPDREntityAssociation(data, output);
594                 break;
595             case PLDM_PDR_FRU_RECORD_SET:
596                 printPDRFruRecordSet(data, output);
597                 break;
598             default:
599                 break;
600         }
601         pldmtool::helper::DisplayInJson(output);
602     }
603 
604   private:
605     uint32_t recordHandle;
606 };
607 
608 class SetStateEffecter : public CommandInterface
609 {
610   public:
611     ~SetStateEffecter() = default;
612     SetStateEffecter() = delete;
613     SetStateEffecter(const SetStateEffecter&) = delete;
614     SetStateEffecter(SetStateEffecter&&) = default;
615     SetStateEffecter& operator=(const SetStateEffecter&) = delete;
616     SetStateEffecter& operator=(SetStateEffecter&&) = default;
617 
618     // compositeEffecterCount(value: 0x01 to 0x08) * stateField(2)
619     static constexpr auto maxEffecterDataSize = 16;
620 
621     // compositeEffecterCount(value: 0x01 to 0x08)
622     static constexpr auto minEffecterCount = 1;
623     static constexpr auto maxEffecterCount = 8;
624     explicit SetStateEffecter(const char* type, const char* name,
625                               CLI::App* app) :
626         CommandInterface(type, name, app)
627     {
628         app->add_option(
629                "-i, --id", effecterId,
630                "A handle that is used to identify and access the effecter")
631             ->required();
632         app->add_option("-c, --count", effecterCount,
633                         "The number of individual sets of effecter information")
634             ->required();
635         app->add_option(
636                "-d,--data", effecterData,
637                "Set effecter state data\n"
638                "eg: requestSet0 effecterState0 noChange1 dummyState1 ...")
639             ->required();
640     }
641 
642     std::pair<int, std::vector<uint8_t>> createRequestMsg() override
643     {
644         std::vector<uint8_t> requestMsg(
645             sizeof(pldm_msg_hdr) + PLDM_SET_STATE_EFFECTER_STATES_REQ_BYTES);
646         auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
647 
648         if (effecterCount > maxEffecterCount ||
649             effecterCount < minEffecterCount)
650         {
651             std::cerr << "Request Message Error: effecterCount size "
652                       << effecterCount << "is invalid\n";
653             auto rc = PLDM_ERROR_INVALID_DATA;
654             return {rc, requestMsg};
655         }
656 
657         if (effecterData.size() > maxEffecterDataSize)
658         {
659             std::cerr << "Request Message Error: effecterData size "
660                       << effecterData.size() << "is invalid\n";
661             auto rc = PLDM_ERROR_INVALID_DATA;
662             return {rc, requestMsg};
663         }
664 
665         auto stateField = parseEffecterData(effecterData, effecterCount);
666         if (!stateField)
667         {
668             std::cerr << "Failed to parse effecter data, effecterCount size "
669                       << effecterCount << "\n";
670             auto rc = PLDM_ERROR_INVALID_DATA;
671             return {rc, requestMsg};
672         }
673 
674         auto rc = encode_set_state_effecter_states_req(
675             instanceId, effecterId, effecterCount, stateField->data(), request);
676         return {rc, requestMsg};
677     }
678 
679     void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
680     {
681         uint8_t completionCode = 0;
682         auto rc = decode_set_state_effecter_states_resp(
683             responsePtr, payloadLength, &completionCode);
684 
685         if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS)
686         {
687             std::cerr << "Response Message Error: "
688                       << "rc=" << rc << ",cc=" << (int)completionCode << "\n";
689             return;
690         }
691 
692         ordered_json data;
693         data["Response"] = "SUCCESS";
694         pldmtool::helper::DisplayInJson(data);
695     }
696 
697   private:
698     uint16_t effecterId;
699     uint8_t effecterCount;
700     std::vector<uint8_t> effecterData;
701 };
702 
703 class SetNumericEffecterValue : public CommandInterface
704 {
705   public:
706     ~SetNumericEffecterValue() = default;
707     SetNumericEffecterValue() = delete;
708     SetNumericEffecterValue(const SetNumericEffecterValue&) = delete;
709     SetNumericEffecterValue(SetNumericEffecterValue&&) = default;
710     SetNumericEffecterValue& operator=(const SetNumericEffecterValue&) = delete;
711     SetNumericEffecterValue& operator=(SetNumericEffecterValue&&) = default;
712 
713     explicit SetNumericEffecterValue(const char* type, const char* name,
714                                      CLI::App* app) :
715         CommandInterface(type, name, app)
716     {
717         app->add_option(
718                "-i, --id", effecterId,
719                "A handle that is used to identify and access the effecter")
720             ->required();
721         app->add_option("-s, --size", effecterDataSize,
722                         "The bit width and format of the setting value for the "
723                         "effecter. enum value: {uint8, sint8, uint16, sint16, "
724                         "uint32, sint32}\n")
725             ->required();
726         app->add_option("-d,--data", maxEffecterValue,
727                         "The setting value of numeric effecter being "
728                         "requested\n")
729             ->required();
730     }
731 
732     std::pair<int, std::vector<uint8_t>> createRequestMsg() override
733     {
734         std::vector<uint8_t> requestMsg(
735             sizeof(pldm_msg_hdr) +
736             PLDM_SET_NUMERIC_EFFECTER_VALUE_MIN_REQ_BYTES + 3);
737 
738         uint8_t* effecterValue = (uint8_t*)&maxEffecterValue;
739 
740         auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
741         size_t payload_length = PLDM_SET_NUMERIC_EFFECTER_VALUE_MIN_REQ_BYTES;
742 
743         if (effecterDataSize == PLDM_EFFECTER_DATA_SIZE_UINT16 ||
744             effecterDataSize == PLDM_EFFECTER_DATA_SIZE_SINT16)
745         {
746             payload_length = PLDM_SET_NUMERIC_EFFECTER_VALUE_MIN_REQ_BYTES + 1;
747         }
748         if (effecterDataSize == PLDM_EFFECTER_DATA_SIZE_UINT32 ||
749             effecterDataSize == PLDM_EFFECTER_DATA_SIZE_SINT32)
750         {
751             payload_length = PLDM_SET_NUMERIC_EFFECTER_VALUE_MIN_REQ_BYTES + 3;
752         }
753         auto rc = encode_set_numeric_effecter_value_req(
754             0, effecterId, effecterDataSize, effecterValue, request,
755             payload_length);
756 
757         return {rc, requestMsg};
758     }
759 
760     void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
761     {
762         uint8_t completionCode = 0;
763         auto rc = decode_set_numeric_effecter_value_resp(
764             responsePtr, payloadLength, &completionCode);
765 
766         if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS)
767         {
768             std::cerr << "Response Message Error: "
769                       << "rc=" << rc << ",cc=" << (int)completionCode
770                       << std::endl;
771             return;
772         }
773 
774         ordered_json data;
775         data["Response"] = "SUCCESS";
776         pldmtool::helper::DisplayInJson(data);
777     }
778 
779   private:
780     uint16_t effecterId;
781     uint8_t effecterDataSize;
782     uint64_t maxEffecterValue;
783 };
784 
785 class GetStateSensorReadings : public CommandInterface
786 {
787   public:
788     ~GetStateSensorReadings() = default;
789     GetStateSensorReadings() = delete;
790     GetStateSensorReadings(const GetStateSensorReadings&) = delete;
791     GetStateSensorReadings(GetStateSensorReadings&&) = default;
792     GetStateSensorReadings& operator=(const GetStateSensorReadings&) = delete;
793     GetStateSensorReadings& operator=(GetStateSensorReadings&&) = default;
794 
795     explicit GetStateSensorReadings(const char* type, const char* name,
796                                     CLI::App* app) :
797         CommandInterface(type, name, app)
798     {
799         app->add_option(
800                "-i, --sensor_id", sensorId,
801                "Sensor ID that is used to identify and access the sensor")
802             ->required();
803         app->add_option("-r, --rearm", sensorRearm,
804                         "Each bit location in this field corresponds to a "
805                         "particular sensor")
806             ->required();
807     }
808 
809     std::pair<int, std::vector<uint8_t>> createRequestMsg() override
810     {
811         std::vector<uint8_t> requestMsg(
812             sizeof(pldm_msg_hdr) + PLDM_GET_STATE_SENSOR_READINGS_REQ_BYTES);
813         auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
814 
815         uint8_t reserved = 0;
816         bitfield8_t bf;
817         bf.byte = sensorRearm;
818         auto rc = encode_get_state_sensor_readings_req(instanceId, sensorId, bf,
819                                                        reserved, request);
820 
821         return {rc, requestMsg};
822     }
823 
824     void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
825     {
826         uint8_t completionCode = 0;
827         uint8_t compSensorCount = 0;
828         std::array<get_sensor_state_field, 8> stateField{};
829         auto rc = decode_get_state_sensor_readings_resp(
830             responsePtr, payloadLength, &completionCode, &compSensorCount,
831             stateField.data());
832 
833         if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS)
834         {
835             std::cerr << "Response Message Error: "
836                       << "rc=" << rc << ",cc=" << (int)completionCode
837                       << std::endl;
838             return;
839         }
840         ordered_json output;
841         output["compositeSensorCount"] = (int)compSensorCount;
842 
843         for (size_t i = 0; i < compSensorCount; i++)
844         {
845             if (sensorOpState.contains(stateField[i].sensor_op_state))
846             {
847                 output.emplace(("sensorOpState[" + std::to_string(i) + "]"),
848                                sensorOpState.at(stateField[i].sensor_op_state));
849             }
850 
851             if (sensorPresState.contains(stateField[i].present_state))
852             {
853                 output.emplace(("presentState[" + std::to_string(i) + "]"),
854                                sensorPresState.at(stateField[i].present_state));
855             }
856 
857             if (sensorPresState.contains(stateField[i].previous_state))
858             {
859                 output.emplace(
860                     ("previousState[" + std::to_string(i) + "]"),
861                     sensorPresState.at(stateField[i].previous_state));
862             }
863 
864             if (sensorPresState.contains(stateField[i].event_state))
865             {
866                 output.emplace(("eventState[" + std::to_string(i) + "]"),
867                                sensorPresState.at(stateField[i].event_state));
868             }
869         }
870 
871         pldmtool::helper::DisplayInJson(output);
872     }
873 
874   private:
875     uint16_t sensorId;
876     uint8_t sensorRearm;
877 };
878 
879 void registerCommand(CLI::App& app)
880 {
881     auto platform = app.add_subcommand("platform", "platform type command");
882     platform->require_subcommand(1);
883 
884     auto getPDR =
885         platform->add_subcommand("GetPDR", "get platform descriptor records");
886     commands.push_back(std::make_unique<GetPDR>("platform", "getPDR", getPDR));
887 
888     auto setStateEffecterStates = platform->add_subcommand(
889         "SetStateEffecterStates", "set effecter states");
890     commands.push_back(std::make_unique<SetStateEffecter>(
891         "platform", "setStateEffecterStates", setStateEffecterStates));
892 
893     auto setNumericEffecterValue = platform->add_subcommand(
894         "SetNumericEffecterValue", "set the value for a PLDM Numeric Effecter");
895     commands.push_back(std::make_unique<SetNumericEffecterValue>(
896         "platform", "setNumericEffecterValue", setNumericEffecterValue));
897 
898     auto getStateSensorReadings = platform->add_subcommand(
899         "GetStateSensorReadings", "get the state sensor readings");
900     commands.push_back(std::make_unique<GetStateSensorReadings>(
901         "platform", "getStateSensorReadings", getStateSensorReadings));
902 }
903 
904 } // namespace platform
905 } // namespace pldmtool
906