1 #include "common/types.hpp" 2 #include "pldm_cmd_helper.hpp" 3 4 #include <libpldm/entity.h> 5 #include <libpldm/state_set.h> 6 7 #include <cstddef> 8 #include <map> 9 10 #ifdef OEM_IBM 11 #include "oem/ibm/oem_ibm_state_set.hpp" 12 #endif 13 14 using namespace pldm::utils; 15 16 namespace pldmtool 17 { 18 namespace platform 19 { 20 namespace 21 { 22 using namespace pldmtool::helper; 23 24 static const std::map<uint8_t, std::string> sensorPresState{ 25 {PLDM_SENSOR_UNKNOWN, "Sensor Unknown"}, 26 {PLDM_SENSOR_NORMAL, "Sensor Normal"}, 27 {PLDM_SENSOR_WARNING, "Sensor Warning"}, 28 {PLDM_SENSOR_CRITICAL, "Sensor Critical"}, 29 {PLDM_SENSOR_FATAL, "Sensor Fatal"}, 30 {PLDM_SENSOR_LOWERWARNING, "Sensor Lower Warning"}, 31 {PLDM_SENSOR_LOWERCRITICAL, "Sensor Lower Critical"}, 32 {PLDM_SENSOR_LOWERFATAL, "Sensor Lower Fatal"}, 33 {PLDM_SENSOR_UPPERWARNING, "Sensor Upper Warning"}, 34 {PLDM_SENSOR_UPPERCRITICAL, "Sensor Upper Critical"}, 35 {PLDM_SENSOR_UPPERFATAL, "Sensor Upper Fatal"}}; 36 37 static const std::map<uint8_t, std::string> sensorOpState{ 38 {PLDM_SENSOR_ENABLED, "Sensor Enabled"}, 39 {PLDM_SENSOR_DISABLED, "Sensor Disabled"}, 40 {PLDM_SENSOR_UNAVAILABLE, "Sensor Unavailable"}, 41 {PLDM_SENSOR_STATUSUNKOWN, "Sensor Status Unknown"}, 42 {PLDM_SENSOR_FAILED, "Sensor Failed"}, 43 {PLDM_SENSOR_INITIALIZING, "Sensor Sensor Intializing"}, 44 {PLDM_SENSOR_SHUTTINGDOWN, "Sensor Shutting down"}, 45 {PLDM_SENSOR_INTEST, "Sensor Intest"}}; 46 47 std::vector<std::unique_ptr<CommandInterface>> commands; 48 49 } // namespace 50 51 using ordered_json = nlohmann::ordered_json; 52 53 class GetPDR : public CommandInterface 54 { 55 public: 56 ~GetPDR() = default; 57 GetPDR() = delete; 58 GetPDR(const GetPDR&) = delete; 59 GetPDR(GetPDR&&) = default; 60 GetPDR& operator=(const GetPDR&) = delete; 61 GetPDR& operator=(GetPDR&&) = delete; 62 63 using CommandInterface::CommandInterface; 64 65 explicit GetPDR(const char* type, const char* name, CLI::App* app) : 66 CommandInterface(type, name, app) 67 { 68 auto pdrOptionGroup = app->add_option_group( 69 "Required Option", 70 "Retrieve individual PDR, all PDRs, PDRs of a requested type or retrieve all PDRs of the requested terminusID"); 71 pdrOptionGroup->add_option( 72 "-d,--data", recordHandle, 73 "retrieve individual PDRs from a PDR Repository\n" 74 "eg: The recordHandle value for the PDR to be retrieved and 0 " 75 "means get first PDR in the repository."); 76 pdrRecType = ""; 77 pdrOptionGroup->add_option("-t, --type", pdrRecType, 78 "retrieve all PDRs of the requested type\n" 79 "supported types:\n" 80 "[terminusLocator, stateSensor, " 81 "numericEffecter, stateEffecter, " 82 "EntityAssociation, fruRecord, ... ]"); 83 84 getPDRGroupOption = pdrOptionGroup->add_option( 85 "-i, --terminusID", pdrTerminus, 86 "retrieve all PDRs of the requested terminusID\n" 87 "supported IDs:\n [1, 2, 208...]"); 88 89 allPDRs = false; 90 pdrOptionGroup->add_flag("-a, --all", allPDRs, 91 "retrieve all PDRs from a PDR repository"); 92 93 pdrOptionGroup->require_option(1); 94 } 95 96 void parseGetPDROptions() 97 { 98 optTIDSet = false; 99 if (getPDRGroupOption->count() > 0) 100 { 101 optTIDSet = true; 102 getPDRs(); 103 } 104 } 105 106 void getPDRs() 107 { 108 // start the array 109 std::cout << "["; 110 111 recordHandle = 0; 112 do 113 { 114 CommandInterface::exec(); 115 } while (recordHandle != 0); 116 117 // close the array 118 std::cout << "]\n"; 119 120 if (handleFound) 121 { 122 recordHandle = 0; 123 uint32_t prevRecordHandle = 0; 124 do 125 { 126 CommandInterface::exec(); 127 if (recordHandle == prevRecordHandle) 128 { 129 return; 130 } 131 prevRecordHandle = recordHandle; 132 } while (recordHandle != 0); 133 } 134 } 135 136 void exec() override 137 { 138 if (allPDRs || !pdrRecType.empty()) 139 { 140 if (!pdrRecType.empty()) 141 { 142 std::transform(pdrRecType.begin(), pdrRecType.end(), 143 pdrRecType.begin(), tolower); 144 } 145 146 // start the array 147 std::cout << "[\n"; 148 149 // Retrieve all PDR records starting from the first 150 recordHandle = 0; 151 uint32_t prevRecordHandle = 0; 152 std::map<uint32_t, uint32_t> recordsSeen; 153 do 154 { 155 CommandInterface::exec(); 156 // recordHandle is updated to nextRecord when 157 // CommandInterface::exec() is successful. 158 // In case of any error, return. 159 if (recordHandle == prevRecordHandle) 160 { 161 return; 162 } 163 164 // check for circular references. 165 auto result = recordsSeen.emplace(recordHandle, 166 prevRecordHandle); 167 if (!result.second) 168 { 169 std::cerr 170 << "Record handle " << recordHandle 171 << " has multiple references: " << result.first->second 172 << ", " << prevRecordHandle << "\n"; 173 return; 174 } 175 prevRecordHandle = recordHandle; 176 177 if (recordHandle != 0) 178 { 179 // close the array 180 std::cout << ","; 181 } 182 } while (recordHandle != 0); 183 184 // close the array 185 std::cout << "]\n"; 186 } 187 else 188 { 189 CommandInterface::exec(); 190 } 191 } 192 193 std::pair<int, std::vector<uint8_t>> createRequestMsg() override 194 { 195 std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) + 196 PLDM_GET_PDR_REQ_BYTES); 197 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 198 199 auto rc = encode_get_pdr_req(instanceId, recordHandle, 0, 200 PLDM_GET_FIRSTPART, UINT16_MAX, 0, request, 201 PLDM_GET_PDR_REQ_BYTES); 202 return {rc, requestMsg}; 203 } 204 205 void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override 206 { 207 uint8_t completionCode = 0; 208 uint8_t recordData[UINT16_MAX] = {0}; 209 uint32_t nextRecordHndl = 0; 210 uint32_t nextDataTransferHndl = 0; 211 uint8_t transferFlag = 0; 212 uint16_t respCnt = 0; 213 uint8_t transferCRC = 0; 214 215 auto rc = decode_get_pdr_resp( 216 responsePtr, payloadLength, &completionCode, &nextRecordHndl, 217 &nextDataTransferHndl, &transferFlag, &respCnt, recordData, 218 sizeof(recordData), &transferCRC); 219 220 if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS) 221 { 222 std::cerr << "Response Message Error: " 223 << "rc=" << rc << ",cc=" << (int)completionCode 224 << std::endl; 225 return; 226 } 227 228 if (optTIDSet && !handleFound) 229 { 230 terminusHandle = getTerminusHandle(recordData, pdrTerminus); 231 if (terminusHandle.has_value()) 232 { 233 recordHandle = 0; 234 return; 235 } 236 else 237 { 238 recordHandle = nextRecordHndl; 239 return; 240 } 241 } 242 243 else 244 { 245 printPDRMsg(nextRecordHndl, respCnt, recordData, terminusHandle); 246 recordHandle = nextRecordHndl; 247 } 248 } 249 250 private: 251 const std::map<pldm::pdr::EntityType, std::string> entityType = { 252 {PLDM_ENTITY_UNSPECIFIED, "Unspecified"}, 253 {PLDM_ENTITY_OTHER, "Other"}, 254 {PLDM_ENTITY_NETWORK, "Network"}, 255 {PLDM_ENTITY_GROUP, "Group"}, 256 {PLDM_ENTITY_REMOTE_MGMT_COMM_DEVICE, 257 "Remote Management Communication Device"}, 258 {PLDM_ENTITY_EXTERNAL_ENVIRONMENT, "External Environment"}, 259 {PLDM_ENTITY_COMM_CHANNEL, " Communication Channel"}, 260 {PLDM_ENTITY_TERMINUS, "PLDM Terminus"}, 261 {PLDM_ENTITY_PLATFORM_EVENT_LOG, " Platform Event Log"}, 262 {PLDM_ENTITY_KEYPAD, "keypad"}, 263 {PLDM_ENTITY_SWITCH, "Switch"}, 264 {PLDM_ENTITY_PUSHBUTTON, "Pushbutton"}, 265 {PLDM_ENTITY_DISPLAY, "Display"}, 266 {PLDM_ENTITY_INDICATOR, "Indicator"}, 267 {PLDM_ENTITY_SYS_MGMT_SW, "System Management Software"}, 268 {PLDM_ENTITY_SYS_FIRMWARE, "System Firmware"}, 269 {PLDM_ENTITY_OPERATING_SYS, "Operating System"}, 270 {PLDM_ENTITY_VIRTUAL_MACHINE_MANAGER, "Virtual Machine Manager"}, 271 {PLDM_ENTITY_OS_LOADER, "OS Loader"}, 272 {PLDM_ENTITY_DEVICE_DRIVER, "Device Driver"}, 273 {PLDM_ENTITY_MGMT_CONTROLLER_FW, "Management Controller Firmware"}, 274 {PLDM_ENTITY_SYSTEM_CHASSIS, "System chassis (main enclosure)"}, 275 {PLDM_ENTITY_SUB_CHASSIS, "Sub-chassis"}, 276 {PLDM_ENTITY_DISK_DRIVE_BAY, "Disk Drive Bay"}, 277 {PLDM_ENTITY_PERIPHERAL_BAY, "Peripheral Bay"}, 278 {PLDM_ENTITY_DEVICE_BAY, "Device bay"}, 279 {PLDM_ENTITY_DOOR, "Door"}, 280 {PLDM_ENTITY_ACCESS_PANEL, "Access Panel"}, 281 {PLDM_ENTITY_COVER, "Cover"}, 282 {PLDM_ENTITY_BOARD, "Board"}, 283 {PLDM_ENTITY_CARD, "Card"}, 284 {PLDM_ENTITY_MODULE, "Module"}, 285 {PLDM_ENTITY_SYS_MGMT_MODULE, "System management module"}, 286 {PLDM_ENTITY_SYS_BOARD, "System Board"}, 287 {PLDM_ENTITY_MEMORY_BOARD, "Memory Board"}, 288 {PLDM_ENTITY_MEMORY_MODULE, "Memory Module"}, 289 {PLDM_ENTITY_PROC_MODULE, "Processor Module"}, 290 {PLDM_ENTITY_ADD_IN_CARD, "Add-in Card"}, 291 {PLDM_ENTITY_CHASSIS_FRONT_PANEL_BOARD, 292 "Chassis front panel board(control panel)"}, 293 {PLDM_ENTITY_BACK_PANEL_BOARD, "Back panel board"}, 294 {PLDM_ENTITY_POWER_MGMT, "Power management board"}, 295 {PLDM_ENTITY_POWER_SYS_BOARD, "Power system board"}, 296 {PLDM_ENTITY_DRIVE_BACKPLANE, "Drive backplane"}, 297 {PLDM_ENTITY_SYS_INTERNAL_EXPANSION_BOARD, 298 "System internal expansion board"}, 299 {PLDM_ENTITY_OTHER_SYS_BOARD, "Other system board"}, 300 {PLDM_ENTITY_CHASSIS_BACK_PANEL_BOARD, "Chassis back panel board"}, 301 {PLDM_ENTITY_PROCESSING_BLADE, "Processing blade"}, 302 {PLDM_ENTITY_CONNECTIVITY_SWITCH, "Connectivity switch"}, 303 {PLDM_ENTITY_PROC_MEMORY_MODULE, "Processor/Memory Module"}, 304 {PLDM_ENTITY_IO_MODULE, "I/O Module"}, 305 {PLDM_ENTITY_PROC_IO_MODULE, "Processor I/O Module"}, 306 {PLDM_ENTITY_COOLING_DEVICE, "Cooling device"}, 307 {PLDM_ENTITY_COOLING_SUBSYSTEM, "Cooling subsystem"}, 308 {PLDM_ENTITY_COOLING_UNIT, "Cooling Unit"}, 309 {PLDM_ENTITY_FAN, "Fan"}, 310 {PLDM_ENTITY_PELTIER_COOLING_DEVICE, "Peltier Cooling Device"}, 311 {PLDM_ENTITY_LIQUID_COOLING_DEVICE, "Liquid Cooling Device"}, 312 {PLDM_ENTITY_LIQUID_COOLING_SUBSYSTEM, "Liquid Colling Subsystem"}, 313 {PLDM_ENTITY_OTHER_STORAGE_DEVICE, "Other Storage Device"}, 314 {PLDM_ENTITY_FLOPPY_DRIVE, "Floppy Drive"}, 315 {PLDM_ENTITY_FIXED_DISK_HARD_DRIVE, "Hard Drive"}, 316 {PLDM_ENTITY_CD_DRIVE, "CD Drive"}, 317 {PLDM_ENTITY_CD_DVD_DRIVE, "CD/DVD Drive"}, 318 {PLDM_ENTITY_OTHER_SILICON_STORAGE_DEVICE, 319 "Other Silicon Storage Device"}, 320 {PLDM_ENTITY_SOLID_STATE_SRIVE, "Solid State Drive"}, 321 {PLDM_ENTITY_POWER_SUPPLY, "Power supply"}, 322 {PLDM_ENTITY_BATTERY, "Battery"}, 323 {PLDM_ENTITY_SUPER_CAPACITOR, "Super Capacitor"}, 324 {PLDM_ENTITY_POWER_CONVERTER, "Power Converter"}, 325 {PLDM_ENTITY_DC_DC_CONVERTER, "DC-DC Converter"}, 326 {PLDM_ENTITY_AC_MAINS_POWER_SUPPLY, "AC mains power supply"}, 327 {PLDM_ENTITY_DC_MAINS_POWER_SUPPLY, "DC mains power supply"}, 328 {PLDM_ENTITY_PROC, "Processor"}, 329 {PLDM_ENTITY_CHIPSET_COMPONENT, "Chipset Component"}, 330 {PLDM_ENTITY_MGMT_CONTROLLER, "Management Controller"}, 331 {PLDM_ENTITY_PERIPHERAL_CONTROLLER, "Peripheral Controller"}, 332 {PLDM_ENTITY_SEEPROM, "SEEPROM"}, 333 {PLDM_ENTITY_NVRAM_CHIP, "NVRAM Chip"}, 334 {PLDM_ENTITY_FLASH_MEMORY_CHIP, "FLASH Memory chip"}, 335 {PLDM_ENTITY_MEMORY_CHIP, "Memory Chip"}, 336 {PLDM_ENTITY_MEMORY_CONTROLLER, "Memory Controller"}, 337 {PLDM_ENTITY_NETWORK_CONTROLLER, "Network Controller"}, 338 {PLDM_ENTITY_IO_CONTROLLER, "I/O Controller"}, 339 {PLDM_ENTITY_SOUTH_BRIDGE, "South Bridge"}, 340 {PLDM_ENTITY_REAL_TIME_CLOCK, "Real Time Clock (RTC)"}, 341 {PLDM_ENTITY_FPGA_CPLD_DEVICE, "FPGA/CPLD Configurable Logic Device"}, 342 {PLDM_ENTITY_OTHER_BUS, "Other Bus"}, 343 {PLDM_ENTITY_SYS_BUS, "System Bus"}, 344 {PLDM_ENTITY_I2C_BUS, "I2C Bus"}, 345 {PLDM_ENTITY_SMBUS_BUS, "SMBus Bus"}, 346 {PLDM_ENTITY_SPI_BUS, "SPI Bus"}, 347 {PLDM_ENTITY_PCI_BUS, "PCI Bus"}, 348 {PLDM_ENTITY_PCI_EXPRESS_BUS, "PCI Express Bus"}, 349 {PLDM_ENTITY_PECI_BUS, "PECI Bus"}, 350 {PLDM_ENTITY_LPC_BUS, "LPC Bus"}, 351 {PLDM_ENTITY_USB_BUS, "USB Bus"}, 352 {PLDM_ENTITY_FIREWIRE_BUS, "FireWire Bus"}, 353 {PLDM_ENTITY_SCSI_BUS, "SCSI Bus"}, 354 {PLDM_ENTITY_SATA_SAS_BUS, "SATA/SAS Bus"}, 355 {PLDM_ENTITY_PROC_FRONT_SIDE_BUS, "Processor/Front-side Bus"}, 356 {PLDM_ENTITY_INTER_PROC_BUS, "Inter-processor Bus"}, 357 {PLDM_ENTITY_CONNECTOR, "Connector"}, 358 {PLDM_ENTITY_SLOT, "Slot"}, 359 {PLDM_ENTITY_CABLE, "Cable(electrical or optical)"}, 360 {PLDM_ENTITY_INTERCONNECT, "Interconnect"}, 361 {PLDM_ENTITY_PLUG, "Plug"}, 362 {PLDM_ENTITY_SOCKET, "Socket"}, 363 }; 364 365 const std::map<uint16_t, std::string> stateSet = { 366 {PLDM_STATE_SET_HEALTH_STATE, "Health State"}, 367 {PLDM_STATE_SET_AVAILABILITY, "Availability"}, 368 {PLDM_STATE_SET_PREDICTIVE_CONDITION, "Predictive Condition"}, 369 {PLDM_STATE_SET_REDUNDANCY_STATUS, "Redundancy Status"}, 370 {PLDM_STATE_SET_HEALTH_REDUNDANCY_TREND, "Health/Redundancy Trend"}, 371 {PLDM_STATE_SET_GROUP_RESOURCE_LEVEL, "Group Resource Level"}, 372 {PLDM_STATE_SET_REDUNDANCY_ENTITY_ROLE, "Redundancy Entity Role"}, 373 {PLDM_STATE_SET_OPERATIONAL_STATUS, "Operational Status"}, 374 {PLDM_STATE_SET_OPERATIONAL_STRESS_STATUS, "Operational Stress Status"}, 375 {PLDM_STATE_SET_OPERATIONAL_FAULT_STATUS, "Operational Fault Status"}, 376 {PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS, 377 "Operational Running Status"}, 378 {PLDM_STATE_SET_OPERATIONAL_CONNECTION_STATUS, 379 "Operational Connection Status"}, 380 {PLDM_STATE_SET_PRESENCE, "Presence"}, 381 {PLDM_STATE_SET_PERFORMANCE, "Performance"}, 382 {PLDM_STATE_SET_CONFIGURATION_STATE, "Configuration State"}, 383 {PLDM_STATE_SET_CHANGED_CONFIGURATION, "Changed Configuration"}, 384 {PLDM_STATE_SET_IDENTIFY_STATE, "Identify State"}, 385 {PLDM_STATE_SET_VERSION, "Version"}, 386 {PLDM_STATE_SET_ALARM_STATE, "Alarm State"}, 387 {PLDM_STATE_SET_DEVICE_INITIALIZATION, "Device Initialization"}, 388 {PLDM_STATE_SET_THERMAL_TRIP, "Thermal Trip"}, 389 {PLDM_STATE_SET_HEARTBEAT, "Heartbeat"}, 390 {PLDM_STATE_SET_LINK_STATE, "Link State"}, 391 {PLDM_STATE_SET_SMOKE_STATE, "Smoke State"}, 392 {PLDM_STATE_SET_HUMIDITY_STATE, "Humidity State"}, 393 {PLDM_STATE_SET_DOOR_STATE, "Door State"}, 394 {PLDM_STATE_SET_SWITCH_STATE, "Switch State"}, 395 {PLDM_STATE_SET_LOCK_STATE, "Lock State"}, 396 {PLDM_STATE_SET_PHYSICAL_SECURITY, "Physical Security"}, 397 {PLDM_STATE_SET_DOCK_AUTHORIZATION, "Dock Authorization"}, 398 {PLDM_STATE_SET_HW_SECURITY, "Hardware Security"}, 399 {PLDM_STATE_SET_PHYSICAL_COMM_CONNECTION, 400 "Physical Communication Connection"}, 401 {PLDM_STATE_SET_COMM_LEASH_STATUS, "Communication Leash Status"}, 402 {PLDM_STATE_SET_FOREIGN_NW_DETECTION_STATUS, 403 "Foreign Network Detection Status"}, 404 {PLDM_STATE_SET_PASSWORD_PROTECTED_ACCESS_SECURITY, 405 "Password-Protected Access Security"}, 406 {PLDM_STATE_SET_SECURITY_ACCESS_PRIVILEGE_LEVEL, 407 "Security Access –PrivilegeLevel"}, 408 {PLDM_STATE_SET_SESSION_AUDIT, "PLDM Session Audit"}, 409 {PLDM_STATE_SET_SW_TERMINATION_STATUS, "Software Termination Status"}, 410 {PLDM_STATE_SET_STORAGE_MEDIA_ACTIVITY, "Storage Media Activity"}, 411 {PLDM_STATE_SET_BOOT_RESTART_CAUSE, "Boot/Restart Cause"}, 412 {PLDM_STATE_SET_BOOT_RESTART_REQUEST, "Boot/Restart Request"}, 413 {PLDM_STATE_SET_ENTITY_BOOT_STATUS, "Entity Boot Status"}, 414 {PLDM_STATE_SET_BOOT_ERROR_STATUS, "Boot ErrorStatus"}, 415 {PLDM_STATE_SET_BOOT_PROGRESS, "Boot Progress"}, 416 {PLDM_STATE_SET_SYS_FIRMWARE_HANG, "System Firmware Hang"}, 417 {PLDM_STATE_SET_POST_ERRORS, "POST Errors"}, 418 {PLDM_STATE_SET_LOG_FILL_STATUS, "Log Fill Status"}, 419 {PLDM_STATE_SET_LOG_FILTER_STATUS, "Log Filter Status"}, 420 {PLDM_STATE_SET_LOG_TIMESTAMP_CHANGE, "Log Timestamp Change"}, 421 {PLDM_STATE_SET_INTERRUPT_REQUESTED, "Interrupt Requested"}, 422 {PLDM_STATE_SET_INTERRUPT_RECEIVED, "Interrupt Received"}, 423 {PLDM_STATE_SET_DIAGNOSTIC_INTERRUPT_REQUESTED, 424 "Diagnostic Interrupt Requested"}, 425 {PLDM_STATE_SET_DIAGNOSTIC_INTERRUPT_RECEIVED, 426 "Diagnostic Interrupt Received"}, 427 {PLDM_STATE_SET_IO_CHANNEL_CHECK_NMI_REQUESTED, 428 "I/O Channel Check NMI Requested"}, 429 {PLDM_STATE_SET_IO_CHANNEL_CHECK_NMI_RECEIVED, 430 "I/O Channel Check NMI Received"}, 431 {PLDM_STATE_SET_FATAL_NMI_REQUESTED, "Fatal NMI Requested"}, 432 {PLDM_STATE_SET_FATAL_NMI_RECEIVED, "Fatal NMI Received"}, 433 {PLDM_STATE_SET_SOFTWARE_NMI_REQUESTED, "Software NMI Requested"}, 434 {PLDM_STATE_SET_SOFTWARE_NMI_RECEIVED, "Software NMI Received"}, 435 {PLDM_STATE_SET_SMI_REQUESTED, "SMI Requested"}, 436 {PLDM_STATE_SET_SMI_RECEIVED, "SMI Received"}, 437 {PLDM_STATE_SET_PCI_PERR_REQUESTED, "PCI PERR Requested"}, 438 {PLDM_STATE_SET_PCI_PERR_RECEIVED, "PCI PERR Received"}, 439 {PLDM_STATE_SET_PCI_SERR_REQUESTED, "PCI SERR Requested "}, 440 {PLDM_STATE_SET_PCI_SERR_RECEIVED, "PCI SERR Received"}, 441 {PLDM_STATE_SET_BUS_ERROR_STATUS, "Bus Error Status"}, 442 {PLDM_STATE_SET_WATCHDOG_STATUS, "Watchdog Status"}, 443 {PLDM_STATE_SET_POWER_SUPPLY_STATE, "Power Supply State"}, 444 {PLDM_STATE_SET_DEVICE_POWER_STATE, "Device Power State"}, 445 {PLDM_STATE_SET_ACPI_POWER_STATE, "ACPI Power State"}, 446 {PLDM_STATE_SET_BACKUP_POWER_SOURCE, "Backup Power Source"}, 447 {PLDM_STATE_SET_SYSTEM_POWER_STATE, "System Power State "}, 448 {PLDM_STATE_SET_BATTERY_ACTIVITY, "Battery Activity"}, 449 {PLDM_STATE_SET_BATTERY_STATE, "Battery State"}, 450 {PLDM_STATE_SET_PROC_POWER_STATE, "Processor Power State"}, 451 {PLDM_STATE_SET_POWER_PERFORMANCE_STATE, "Power-Performance State"}, 452 {PLDM_STATE_SET_PROC_ERROR_STATUS, "Processor Error Status"}, 453 {PLDM_STATE_SET_BIST_FAILURE_STATUS, "BIST FailureStatus"}, 454 {PLDM_STATE_SET_IBIST_FAILURE_STATUS, "IBIST FailureStatus"}, 455 {PLDM_STATE_SET_PROC_HANG_IN_POST, "Processor Hang in POST"}, 456 {PLDM_STATE_SET_PROC_STARTUP_FAILURE, "Processor Startup Failure"}, 457 {PLDM_STATE_SET_UNCORRECTABLE_CPU_ERROR, "Uncorrectable CPU Error"}, 458 {PLDM_STATE_SET_MACHINE_CHECK_ERROR, "Machine Check Error"}, 459 {PLDM_STATE_SET_CORRECTED_MACHINE_CHECK, "Corrected Machine Check"}, 460 {PLDM_STATE_SET_CACHE_STATUS, "Cache Status"}, 461 {PLDM_STATE_SET_MEMORY_ERROR_STATUS, "Memory Error Status"}, 462 {PLDM_STATE_SET_REDUNDANT_MEMORY_ACTIVITY_STATUS, 463 "Redundant Memory Activity Status"}, 464 {PLDM_STATE_SET_ERROR_DETECTION_STATUS, "Error Detection Status"}, 465 {PLDM_STATE_SET_STUCK_BIT_STATUS, "Stuck Bit Status"}, 466 {PLDM_STATE_SET_SCRUB_STATUS, "Scrub Status"}, 467 {PLDM_STATE_SET_SLOT_OCCUPANCY, "Slot Occupancy"}, 468 {PLDM_STATE_SET_SLOT_STATE, "Slot State"}, 469 }; 470 471 const std::array<std::string_view, 4> sensorInit = { 472 "noInit", "useInitPDR", "enableSensor", "disableSensor"}; 473 474 const std::array<std::string_view, 4> effecterInit = { 475 "noInit", "useInitPDR", "enableEffecter", "disableEffecter"}; 476 477 const std::map<uint8_t, std::string> pdrType = { 478 {PLDM_TERMINUS_LOCATOR_PDR, "Terminus Locator PDR"}, 479 {PLDM_NUMERIC_SENSOR_PDR, "Numeric Sensor PDR"}, 480 {PLDM_NUMERIC_SENSOR_INITIALIZATION_PDR, 481 "Numeric Sensor Initialization PDR"}, 482 {PLDM_STATE_SENSOR_PDR, "State Sensor PDR"}, 483 {PLDM_STATE_SENSOR_INITIALIZATION_PDR, 484 "State Sensor Initialization PDR"}, 485 {PLDM_SENSOR_AUXILIARY_NAMES_PDR, "Sensor Auxiliary Names PDR"}, 486 {PLDM_OEM_UNIT_PDR, "OEM Unit PDR"}, 487 {PLDM_OEM_STATE_SET_PDR, "OEM State Set PDR"}, 488 {PLDM_NUMERIC_EFFECTER_PDR, "Numeric Effecter PDR"}, 489 {PLDM_NUMERIC_EFFECTER_INITIALIZATION_PDR, 490 "Numeric Effecter Initialization PDR"}, 491 {PLDM_STATE_EFFECTER_PDR, "State Effecter PDR"}, 492 {PLDM_STATE_EFFECTER_INITIALIZATION_PDR, 493 "State Effecter Initialization PDR"}, 494 {PLDM_EFFECTER_AUXILIARY_NAMES_PDR, "Effecter Auxiliary Names PDR"}, 495 {PLDM_EFFECTER_OEM_SEMANTIC_PDR, "Effecter OEM Semantic PDR"}, 496 {PLDM_PDR_ENTITY_ASSOCIATION, "Entity Association PDR"}, 497 {PLDM_ENTITY_AUXILIARY_NAMES_PDR, "Entity Auxiliary Names PDR"}, 498 {PLDM_OEM_ENTITY_ID_PDR, "OEM Entity ID PDR"}, 499 {PLDM_INTERRUPT_ASSOCIATION_PDR, "Interrupt Association PDR"}, 500 {PLDM_EVENT_LOG_PDR, "PLDM Event Log PDR"}, 501 {PLDM_PDR_FRU_RECORD_SET, "FRU Record Set PDR"}, 502 {PLDM_OEM_DEVICE_PDR, "OEM Device PDR"}, 503 {PLDM_OEM_PDR, "OEM PDR"}, 504 }; 505 506 static inline const std::map<uint8_t, std::string> setThermalTrip{ 507 {PLDM_STATE_SET_THERMAL_TRIP_STATUS_NORMAL, "Normal"}, 508 {PLDM_STATE_SET_THERMAL_TRIP_STATUS_THERMAL_TRIP, "Thermal Trip"}}; 509 510 static inline const std::map<uint8_t, std::string> setIdentifyState{ 511 {PLDM_STATE_SET_IDENTIFY_STATE_UNASSERTED, "Identify State Unasserted"}, 512 {PLDM_STATE_SET_IDENTIFY_STATE_ASSERTED, "Identify State Asserted"}}; 513 514 static inline const std::map<uint8_t, std::string> setBootProgressState{ 515 {PLDM_STATE_SET_BOOT_PROG_STATE_NOT_ACTIVE, "Boot Not Active"}, 516 {PLDM_STATE_SET_BOOT_PROG_STATE_COMPLETED, "Boot Completed"}, 517 {PLDM_STATE_SET_BOOT_PROG_STATE_MEM_INITIALIZATION, 518 "Memory Initialization"}, 519 {PLDM_STATE_SET_BOOT_PROG_STATE_SEC_PROC_INITIALIZATION, 520 "Secondary Processor(s) Initialization"}, 521 {PLDM_STATE_SET_BOOT_PROG_STATE_PCI_RESORUCE_CONFIG, 522 "PCI Resource Configuration"}, 523 {PLDM_STATE_SET_BOOT_PROG_STATE_STARTING_OP_SYS, 524 "Starting Operating System"}, 525 {PLDM_STATE_SET_BOOT_PROG_STATE_BASE_BOARD_INITIALIZATION, 526 "Baseboard Initialization"}, 527 {PLDM_STATE_SET_BOOT_PROG_STATE_PRIMARY_PROC_INITIALIZATION, 528 "Primary Processor Initialization"}, 529 {PLDM_STATE_SET_BOOT_PROG_STATE_OSSTART, "OSStart"}}; 530 531 static inline const std::map<uint8_t, std::string> setOpFaultStatus{ 532 {PLDM_STATE_SET_OPERATIONAL_FAULT_STATUS_NORMAL, "Normal"}, 533 {PLDM_STATE_SET_OPERATIONAL_FAULT_STATUS_STRESSED, "Stressed"}}; 534 535 static inline const std::map<uint8_t, std::string> setSysPowerState{ 536 {PLDM_STATE_SET_SYS_POWER_STATE_OFF_SOFT_GRACEFUL, 537 "Off-Soft Graceful"}}; 538 539 static inline const std::map<uint8_t, std::string> setSWTerminationStatus{ 540 {PLDM_SW_TERM_GRACEFUL_RESTART_REQUESTED, 541 "Graceful Restart Requested"}}; 542 543 static inline const std::map<uint8_t, std::string> setAvailability{ 544 {PLDM_STATE_SET_AVAILABILITY_REBOOTING, "Rebooting"}}; 545 546 static inline const std::map<uint8_t, std::string> setHealthState{ 547 {PLDM_STATE_SET_HEALTH_STATE_NORMAL, "Normal"}, 548 {PLDM_STATE_SET_HEALTH_STATE_NON_CRITICAL, "Non-Critical"}, 549 {PLDM_STATE_SET_HEALTH_STATE_CRITICAL, "Critical"}, 550 {PLDM_STATE_SET_HEALTH_STATE_FATAL, "Fatal"}, 551 {PLDM_STATE_SET_HEALTH_STATE_UPPER_NON_CRITICAL, "Upper Non-Critical"}, 552 {PLDM_STATE_SET_HEALTH_STATE_LOWER_NON_CRITICAL, "Lower Non-Critical"}, 553 {PLDM_STATE_SET_HEALTH_STATE_UPPER_CRITICAL, "Upper Critical"}, 554 {PLDM_STATE_SET_HEALTH_STATE_LOWER_CRITICAL, "Lower Critical"}, 555 {PLDM_STATE_SET_HEALTH_STATE_UPPER_FATAL, "Upper Fatal"}, 556 {PLDM_STATE_SET_HEALTH_STATE_LOWER_FATAL, "Lower Fatal"}}; 557 558 static inline const std::map<uint8_t, std::string> 559 setOperationalRunningState{ 560 {PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_STARTING, "Starting"}, 561 {PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_STOPPING, "Stopping"}, 562 {PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_STOPPED, "Stopped"}, 563 {PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_IN_SERVICE, 564 "In Service"}, 565 {PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_ABORTED, "Aborted"}, 566 {PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_DORMANT, "Dormant"}}; 567 568 static inline const std::map<uint16_t, const std::map<uint8_t, std::string>> 569 populatePStateMaps{ 570 {PLDM_STATE_SET_THERMAL_TRIP, setThermalTrip}, 571 {PLDM_STATE_SET_IDENTIFY_STATE, setIdentifyState}, 572 {PLDM_STATE_SET_BOOT_PROGRESS, setBootProgressState}, 573 {PLDM_STATE_SET_OPERATIONAL_FAULT_STATUS, setOpFaultStatus}, 574 {PLDM_STATE_SET_SYSTEM_POWER_STATE, setSysPowerState}, 575 {PLDM_STATE_SET_SW_TERMINATION_STATUS, setSWTerminationStatus}, 576 {PLDM_STATE_SET_AVAILABILITY, setAvailability}, 577 {PLDM_STATE_SET_HEALTH_STATE, setHealthState}, 578 {PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS, 579 setOperationalRunningState}, 580 }; 581 582 const std::map<std::string, uint8_t> strToPdrType = { 583 {"terminuslocator", PLDM_TERMINUS_LOCATOR_PDR}, 584 {"statesensor", PLDM_STATE_SENSOR_PDR}, 585 {"numericeffecter", PLDM_NUMERIC_EFFECTER_PDR}, 586 {"stateeffecter", PLDM_STATE_EFFECTER_PDR}, 587 {"entityassociation", PLDM_PDR_ENTITY_ASSOCIATION}, 588 {"frurecord", PLDM_PDR_FRU_RECORD_SET}, 589 // Add other types 590 }; 591 592 bool isLogicalBitSet(const uint16_t entity_type) 593 { 594 return entity_type & 0x8000; 595 } 596 597 uint16_t getEntityTypeForLogicalEntity(const uint16_t logical_entity_type) 598 { 599 return logical_entity_type & 0x7FFF; 600 } 601 602 std::string getEntityName(pldm::pdr::EntityType type) 603 { 604 uint16_t entityNumber = type; 605 std::string entityName = "[Physical] "; 606 607 if (isLogicalBitSet(type)) 608 { 609 entityName = "[Logical] "; 610 entityNumber = getEntityTypeForLogicalEntity(type); 611 } 612 613 try 614 { 615 return entityName + entityType.at(entityNumber); 616 } 617 catch (const std::out_of_range& e) 618 { 619 auto OemString = 620 std::to_string(static_cast<unsigned>(entityNumber)); 621 if (type >= PLDM_OEM_ENTITY_TYPE_START && 622 type <= PLDM_OEM_ENTITY_TYPE_END) 623 { 624 #ifdef OEM_IBM 625 if (OemIBMEntityType.contains(entityNumber)) 626 { 627 return entityName + OemIBMEntityType.at(entityNumber) + 628 "(OEM)"; 629 } 630 #endif 631 return entityName + OemString + "(OEM)"; 632 } 633 return OemString; 634 } 635 } 636 637 std::string getStateSetName(uint16_t id) 638 { 639 auto typeString = std::to_string(id); 640 try 641 { 642 return stateSet.at(id) + "(" + typeString + ")"; 643 } 644 catch (const std::out_of_range& e) 645 { 646 return typeString; 647 } 648 } 649 650 std::vector<std::string> 651 getStateSetPossibleStateNames(uint16_t stateId, 652 const std::vector<uint8_t>& value) 653 { 654 std::vector<std::string> data{}; 655 std::map<uint8_t, std::string> stateNameMaps; 656 657 for (auto& s : value) 658 { 659 std::map<uint8_t, std::string> stateNameMaps; 660 auto pstr = std::to_string(s); 661 662 #ifdef OEM_IBM 663 if (stateId >= PLDM_OEM_STATE_SET_ID_START && 664 stateId < PLDM_OEM_STATE_SET_ID_END) 665 { 666 if (populateOemIBMStateMaps.contains(stateId)) 667 { 668 const std::map<uint8_t, std::string> stateNames = 669 populateOemIBMStateMaps.at(stateId); 670 stateNameMaps.insert(stateNames.begin(), stateNames.end()); 671 } 672 } 673 #endif 674 if (populatePStateMaps.contains(stateId)) 675 { 676 const std::map<uint8_t, std::string> stateNames = 677 populatePStateMaps.at(stateId); 678 stateNameMaps.insert(stateNames.begin(), stateNames.end()); 679 } 680 if (stateNameMaps.contains(s)) 681 { 682 data.push_back(stateNameMaps.at(s) + "(" + pstr + ")"); 683 } 684 else 685 { 686 data.push_back(pstr); 687 } 688 } 689 return data; 690 } 691 692 std::string getPDRType(uint8_t type) 693 { 694 auto typeString = std::to_string(type); 695 try 696 { 697 return pdrType.at(type); 698 } 699 catch (const std::out_of_range& e) 700 { 701 return typeString; 702 } 703 } 704 705 void printCommonPDRHeader(const pldm_pdr_hdr* hdr, ordered_json& output) 706 { 707 output["recordHandle"] = hdr->record_handle; 708 output["PDRHeaderVersion"] = unsigned(hdr->version); 709 output["PDRType"] = getPDRType(hdr->type); 710 output["recordChangeNumber"] = hdr->record_change_num; 711 output["dataLength"] = hdr->length; 712 } 713 714 std::vector<uint8_t> printPossibleStates(uint8_t possibleStatesSize, 715 const bitfield8_t* states) 716 { 717 uint8_t possibleStatesPos{}; 718 std::vector<uint8_t> data{}; 719 auto printStates = [&possibleStatesPos, &data](const bitfield8_t& val) { 720 std::stringstream pstates; 721 for (int i = 0; i < CHAR_BIT; i++) 722 { 723 if (val.byte & (1 << i)) 724 { 725 pstates << (possibleStatesPos * CHAR_BIT + i); 726 data.push_back( 727 static_cast<uint8_t>(std::stoi(pstates.str()))); 728 pstates.str(""); 729 } 730 } 731 possibleStatesPos++; 732 }; 733 std::for_each(states, states + possibleStatesSize, printStates); 734 return data; 735 } 736 737 void printStateSensorPDR(const uint8_t* data, ordered_json& output) 738 { 739 auto pdr = reinterpret_cast<const pldm_state_sensor_pdr*>(data); 740 output["PLDMTerminusHandle"] = pdr->terminus_handle; 741 output["sensorID"] = pdr->sensor_id; 742 output["entityType"] = getEntityName(pdr->entity_type); 743 output["entityInstanceNumber"] = pdr->entity_instance; 744 output["containerID"] = pdr->container_id; 745 output["sensorInit"] = sensorInit[pdr->sensor_init]; 746 output["sensorAuxiliaryNamesPDR"] = 747 (pdr->sensor_auxiliary_names_pdr ? true : false); 748 output["compositeSensorCount"] = unsigned(pdr->composite_sensor_count); 749 750 auto statesPtr = pdr->possible_states; 751 auto compCount = pdr->composite_sensor_count; 752 753 while (compCount--) 754 { 755 auto state = reinterpret_cast<const state_sensor_possible_states*>( 756 statesPtr); 757 output.emplace(("stateSetID[" + std::to_string(compCount) + "]"), 758 getStateSetName(state->state_set_id)); 759 output.emplace( 760 ("possibleStatesSize[" + std::to_string(compCount) + "]"), 761 state->possible_states_size); 762 output.emplace( 763 ("possibleStates[" + std::to_string(compCount) + "]"), 764 getStateSetPossibleStateNames( 765 state->state_set_id, 766 printPossibleStates(state->possible_states_size, 767 state->states))); 768 769 if (compCount) 770 { 771 statesPtr += sizeof(state_sensor_possible_states) + 772 state->possible_states_size - 1; 773 } 774 } 775 } 776 777 void printPDRFruRecordSet(uint8_t* data, ordered_json& output) 778 { 779 if (data == NULL) 780 { 781 return; 782 } 783 784 data += sizeof(pldm_pdr_hdr); 785 pldm_pdr_fru_record_set* pdr = 786 reinterpret_cast<pldm_pdr_fru_record_set*>(data); 787 if (!pdr) 788 { 789 std::cerr << "Failed to get the FRU record set PDR" << std::endl; 790 return; 791 } 792 793 output["PLDMTerminusHandle"] = unsigned(pdr->terminus_handle); 794 output["FRURecordSetIdentifier"] = unsigned(pdr->fru_rsi); 795 output["entityType"] = getEntityName(pdr->entity_type); 796 output["entityInstanceNumber"] = unsigned(pdr->entity_instance_num); 797 output["containerID"] = unsigned(pdr->container_id); 798 } 799 800 void printPDREntityAssociation(uint8_t* data, ordered_json& output) 801 { 802 const std::map<uint8_t, const char*> assocationType = { 803 {PLDM_ENTITY_ASSOCIAION_PHYSICAL, "Physical"}, 804 {PLDM_ENTITY_ASSOCIAION_LOGICAL, "Logical"}, 805 }; 806 807 if (data == NULL) 808 { 809 return; 810 } 811 812 data += sizeof(pldm_pdr_hdr); 813 pldm_pdr_entity_association* pdr = 814 reinterpret_cast<pldm_pdr_entity_association*>(data); 815 if (!pdr) 816 { 817 std::cerr << "Failed to get the PDR eneity association" 818 << std::endl; 819 return; 820 } 821 822 output["containerID"] = int(pdr->container_id); 823 if (assocationType.contains(pdr->association_type)) 824 { 825 output["associationType"] = 826 assocationType.at(pdr->association_type); 827 } 828 else 829 { 830 std::cout << "Get associationType failed.\n"; 831 } 832 output["containerEntityType"] = 833 getEntityName(pdr->container.entity_type); 834 output["containerEntityInstanceNumber"] = 835 int(pdr->container.entity_instance_num); 836 output["containerEntityContainerID"] = 837 int(pdr->container.entity_container_id); 838 output["containedEntityCount"] = 839 static_cast<unsigned>(pdr->num_children); 840 841 auto child = reinterpret_cast<pldm_entity*>(&pdr->children[0]); 842 for (int i = 0; i < pdr->num_children; ++i) 843 { 844 output.emplace("containedEntityType[" + std::to_string(i + 1) + "]", 845 getEntityName(child->entity_type)); 846 output.emplace("containedEntityInstanceNumber[" + 847 std::to_string(i + 1) + "]", 848 unsigned(child->entity_instance_num)); 849 output.emplace("containedEntityContainerID[" + 850 std::to_string(i + 1) + "]", 851 unsigned(child->entity_container_id)); 852 853 ++child; 854 } 855 } 856 857 void printNumericEffecterPDR(uint8_t* data, ordered_json& output) 858 { 859 struct pldm_numeric_effecter_value_pdr* pdr = 860 (struct pldm_numeric_effecter_value_pdr*)data; 861 if (!pdr) 862 { 863 std::cerr << "Failed to get numeric effecter PDR" << std::endl; 864 return; 865 } 866 867 output["PLDMTerminusHandle"] = int(pdr->terminus_handle); 868 output["effecterID"] = int(pdr->effecter_id); 869 output["entityType"] = int(pdr->entity_type); 870 output["entityInstanceNumber"] = int(pdr->entity_instance); 871 output["containerID"] = int(pdr->container_id); 872 output["effecterSemanticID"] = int(pdr->effecter_semantic_id); 873 output["effecterInit"] = unsigned(pdr->effecter_init); 874 output["effecterAuxiliaryNames"] = 875 (unsigned(pdr->effecter_auxiliary_names) ? true : false); 876 output["baseUnit"] = unsigned(pdr->base_unit); 877 output["unitModifier"] = unsigned(pdr->unit_modifier); 878 output["rateUnit"] = unsigned(pdr->rate_unit); 879 output["baseOEMUnitHandle"] = unsigned(pdr->base_oem_unit_handle); 880 output["auxUnit"] = unsigned(pdr->aux_unit); 881 output["auxUnitModifier"] = unsigned(pdr->aux_unit_modifier); 882 output["auxrateUnit"] = unsigned(pdr->aux_rate_unit); 883 output["auxOEMUnitHandle"] = unsigned(pdr->aux_oem_unit_handle); 884 output["isLinear"] = (unsigned(pdr->is_linear) ? true : false); 885 output["effecterDataSize"] = unsigned(pdr->effecter_data_size); 886 output["resolution"] = unsigned(pdr->resolution); 887 output["offset"] = unsigned(pdr->offset); 888 output["accuracy"] = unsigned(pdr->accuracy); 889 output["plusTolerance"] = unsigned(pdr->plus_tolerance); 890 output["minusTolerance"] = unsigned(pdr->minus_tolerance); 891 output["stateTransitionInterval"] = 892 unsigned(pdr->state_transition_interval); 893 output["TransitionInterval"] = unsigned(pdr->transition_interval); 894 895 switch (pdr->effecter_data_size) 896 { 897 case PLDM_EFFECTER_DATA_SIZE_UINT8: 898 output["maxSettable"] = unsigned(pdr->max_settable.value_u8); 899 output["minSettable"] = unsigned(pdr->min_settable.value_u8); 900 break; 901 case PLDM_EFFECTER_DATA_SIZE_SINT8: 902 output["maxSettable"] = unsigned(pdr->max_settable.value_s8); 903 output["minSettable"] = unsigned(pdr->min_settable.value_s8); 904 break; 905 case PLDM_EFFECTER_DATA_SIZE_UINT16: 906 output["maxSettable"] = unsigned(pdr->max_settable.value_u16); 907 output["minSettable"] = unsigned(pdr->min_settable.value_u16); 908 break; 909 case PLDM_EFFECTER_DATA_SIZE_SINT16: 910 output["maxSettable"] = unsigned(pdr->max_settable.value_s16); 911 output["minSettable"] = unsigned(pdr->min_settable.value_s16); 912 break; 913 case PLDM_EFFECTER_DATA_SIZE_UINT32: 914 output["maxSettable"] = unsigned(pdr->max_settable.value_u32); 915 output["minSettable"] = unsigned(pdr->min_settable.value_u32); 916 break; 917 case PLDM_EFFECTER_DATA_SIZE_SINT32: 918 output["maxSettable"] = unsigned(pdr->max_settable.value_s32); 919 output["minSettable"] = unsigned(pdr->min_settable.value_s32); 920 break; 921 default: 922 break; 923 } 924 925 output["rangeFieldFormat"] = unsigned(pdr->range_field_format); 926 output["rangeFieldSupport"] = unsigned(pdr->range_field_support.byte); 927 928 switch (pdr->range_field_format) 929 { 930 case PLDM_RANGE_FIELD_FORMAT_UINT8: 931 output["nominalValue"] = unsigned(pdr->nominal_value.value_u8); 932 output["normalMax"] = unsigned(pdr->normal_max.value_u8); 933 output["normalMin"] = unsigned(pdr->normal_min.value_u8); 934 output["ratedMax"] = unsigned(pdr->rated_max.value_u8); 935 output["ratedMin"] = unsigned(pdr->rated_min.value_u8); 936 break; 937 case PLDM_RANGE_FIELD_FORMAT_SINT8: 938 output["nominalValue"] = unsigned(pdr->nominal_value.value_s8); 939 output["normalMax"] = unsigned(pdr->normal_max.value_s8); 940 output["normalMin"] = unsigned(pdr->normal_min.value_s8); 941 output["ratedMax"] = unsigned(pdr->rated_max.value_s8); 942 output["ratedMin"] = unsigned(pdr->rated_min.value_s8); 943 break; 944 case PLDM_RANGE_FIELD_FORMAT_UINT16: 945 output["nominalValue"] = unsigned(pdr->nominal_value.value_u16); 946 output["normalMax"] = unsigned(pdr->normal_max.value_u16); 947 output["normalMin"] = unsigned(pdr->normal_min.value_u16); 948 output["ratedMax"] = unsigned(pdr->rated_max.value_u16); 949 output["ratedMin"] = unsigned(pdr->rated_min.value_u16); 950 break; 951 case PLDM_RANGE_FIELD_FORMAT_SINT16: 952 output["nominalValue"] = unsigned(pdr->nominal_value.value_s16); 953 output["normalMax"] = unsigned(pdr->normal_max.value_s16); 954 output["normalMin"] = unsigned(pdr->normal_min.value_s16); 955 output["ratedMax"] = unsigned(pdr->rated_max.value_s16); 956 output["ratedMin"] = unsigned(pdr->rated_min.value_s16); 957 break; 958 case PLDM_RANGE_FIELD_FORMAT_UINT32: 959 output["nominalValue"] = unsigned(pdr->nominal_value.value_u32); 960 output["normalMax"] = unsigned(pdr->normal_max.value_u32); 961 output["normalMin"] = unsigned(pdr->normal_min.value_u32); 962 output["ratedMax"] = unsigned(pdr->rated_max.value_u32); 963 output["ratedMin"] = unsigned(pdr->rated_min.value_u32); 964 break; 965 case PLDM_RANGE_FIELD_FORMAT_SINT32: 966 output["nominalValue"] = unsigned(pdr->nominal_value.value_s32); 967 output["normalMax"] = unsigned(pdr->normal_max.value_s32); 968 output["normalMin"] = unsigned(pdr->normal_min.value_s32); 969 output["ratedMax"] = unsigned(pdr->rated_max.value_s32); 970 output["ratedMin"] = unsigned(pdr->rated_min.value_s32); 971 break; 972 case PLDM_RANGE_FIELD_FORMAT_REAL32: 973 output["nominalValue"] = unsigned(pdr->nominal_value.value_f32); 974 output["normalMax"] = unsigned(pdr->normal_max.value_f32); 975 output["normalMin"] = unsigned(pdr->normal_min.value_f32); 976 output["ratedMax"] = unsigned(pdr->rated_max.value_f32); 977 output["ratedMin"] = unsigned(pdr->rated_min.value_f32); 978 break; 979 default: 980 break; 981 } 982 } 983 984 void printStateEffecterPDR(const uint8_t* data, ordered_json& output) 985 { 986 auto pdr = reinterpret_cast<const pldm_state_effecter_pdr*>(data); 987 988 output["PLDMTerminusHandle"] = pdr->terminus_handle; 989 output["effecterID"] = pdr->effecter_id; 990 output["entityType"] = getEntityName(pdr->entity_type); 991 output["entityInstanceNumber"] = pdr->entity_instance; 992 output["containerID"] = pdr->container_id; 993 output["effecterSemanticID"] = pdr->effecter_semantic_id; 994 output["effecterInit"] = effecterInit[pdr->effecter_init]; 995 output["effecterDescriptionPDR"] = (pdr->has_description_pdr ? true 996 : false); 997 output["compositeEffecterCount"] = 998 unsigned(pdr->composite_effecter_count); 999 1000 auto statesPtr = pdr->possible_states; 1001 auto compEffCount = pdr->composite_effecter_count; 1002 1003 while (compEffCount--) 1004 { 1005 auto state = 1006 reinterpret_cast<const state_effecter_possible_states*>( 1007 statesPtr); 1008 output.emplace(("stateSetID[" + std::to_string(compEffCount) + "]"), 1009 getStateSetName(state->state_set_id)); 1010 output.emplace( 1011 ("possibleStatesSize[" + std::to_string(compEffCount) + "]"), 1012 state->possible_states_size); 1013 output.emplace( 1014 ("possibleStates[" + std::to_string(compEffCount) + "]"), 1015 getStateSetPossibleStateNames( 1016 state->state_set_id, 1017 printPossibleStates(state->possible_states_size, 1018 state->states))); 1019 1020 if (compEffCount) 1021 { 1022 statesPtr += sizeof(state_effecter_possible_states) + 1023 state->possible_states_size - 1; 1024 } 1025 } 1026 } 1027 1028 bool checkTerminusHandle(const uint8_t* data, 1029 std::optional<uint16_t> terminusHandle) 1030 { 1031 struct pldm_pdr_hdr* pdr = (struct pldm_pdr_hdr*)data; 1032 1033 if (pdr->type == PLDM_TERMINUS_LOCATOR_PDR) 1034 { 1035 auto tlpdr = 1036 reinterpret_cast<const pldm_terminus_locator_pdr*>(data); 1037 1038 if (tlpdr->terminus_handle != terminusHandle) 1039 { 1040 return true; 1041 } 1042 } 1043 else if (pdr->type == PLDM_STATE_SENSOR_PDR) 1044 { 1045 auto sensor = reinterpret_cast<const pldm_state_sensor_pdr*>(data); 1046 1047 if (sensor->terminus_handle != terminusHandle) 1048 { 1049 return true; 1050 } 1051 } 1052 else if (pdr->type == PLDM_NUMERIC_EFFECTER_PDR) 1053 { 1054 auto numericEffecter = 1055 reinterpret_cast<const pldm_numeric_effecter_value_pdr*>(data); 1056 1057 if (numericEffecter->terminus_handle != terminusHandle) 1058 { 1059 return true; 1060 } 1061 } 1062 1063 else if (pdr->type == PLDM_STATE_EFFECTER_PDR) 1064 { 1065 auto stateEffecter = 1066 reinterpret_cast<const pldm_state_effecter_pdr*>(data); 1067 if (stateEffecter->terminus_handle != terminusHandle) 1068 { 1069 return true; 1070 } 1071 } 1072 else if (pdr->type == PLDM_PDR_FRU_RECORD_SET) 1073 { 1074 data += sizeof(pldm_pdr_hdr); 1075 auto fru = reinterpret_cast<const pldm_pdr_fru_record_set*>(data); 1076 1077 if (fru->terminus_handle != terminusHandle) 1078 { 1079 return true; 1080 } 1081 } 1082 else 1083 { 1084 // Entity association PDRs does not have terminus handle 1085 return true; 1086 } 1087 1088 return false; 1089 } 1090 1091 void printTerminusLocatorPDR(const uint8_t* data, ordered_json& output) 1092 { 1093 const std::array<std::string_view, 4> terminusLocatorType = { 1094 "UID", "MCTP_EID", "SMBusRelative", "systemSoftware"}; 1095 1096 auto pdr = reinterpret_cast<const pldm_terminus_locator_pdr*>(data); 1097 1098 output["PLDMTerminusHandle"] = pdr->terminus_handle; 1099 output["validity"] = (pdr->validity ? "valid" : "notValid"); 1100 output["TID"] = unsigned(pdr->tid); 1101 output["containerID"] = pdr->container_id; 1102 output["terminusLocatorType"] = 1103 terminusLocatorType[pdr->terminus_locator_type]; 1104 output["terminusLocatorValueSize"] = 1105 unsigned(pdr->terminus_locator_value_size); 1106 1107 if (pdr->terminus_locator_type == PLDM_TERMINUS_LOCATOR_TYPE_MCTP_EID) 1108 { 1109 auto locatorValue = 1110 reinterpret_cast<const pldm_terminus_locator_type_mctp_eid*>( 1111 pdr->terminus_locator_value); 1112 output["EID"] = unsigned(locatorValue->eid); 1113 } 1114 } 1115 1116 std::optional<uint16_t> getTerminusHandle(uint8_t* data, 1117 std::optional<uint8_t> tid) 1118 { 1119 struct pldm_pdr_hdr* pdr = (struct pldm_pdr_hdr*)data; 1120 if (pdr->type == PLDM_TERMINUS_LOCATOR_PDR) 1121 { 1122 auto pdr = reinterpret_cast<const pldm_terminus_locator_pdr*>(data); 1123 if (pdr->tid == tid) 1124 { 1125 handleFound = true; 1126 return pdr->terminus_handle; 1127 } 1128 } 1129 return std::nullopt; 1130 } 1131 1132 void printPDRMsg(uint32_t& nextRecordHndl, const uint16_t respCnt, 1133 uint8_t* data, std::optional<uint16_t> terminusHandle) 1134 { 1135 if (data == NULL) 1136 { 1137 std::cerr << "Failed to get PDR message" << std::endl; 1138 return; 1139 } 1140 1141 ordered_json output; 1142 output["nextRecordHandle"] = nextRecordHndl; 1143 output["responseCount"] = respCnt; 1144 1145 struct pldm_pdr_hdr* pdr = (struct pldm_pdr_hdr*)data; 1146 if (!pdr) 1147 { 1148 return; 1149 } 1150 1151 if (!pdrRecType.empty()) 1152 { 1153 // Need to return if the requested PDR type 1154 // is not supported 1155 if (!strToPdrType.contains(pdrRecType)) 1156 { 1157 std::cerr << "PDR type '" << pdrRecType 1158 << "' is not supported or invalid\n"; 1159 // PDR type not supported, setting next record handle to 0 1160 // to avoid looping through all PDR records 1161 nextRecordHndl = 0; 1162 return; 1163 } 1164 1165 // Do not print PDR record if the current record 1166 // PDR type does not match with requested type 1167 if (pdr->type != strToPdrType.at(pdrRecType)) 1168 { 1169 return; 1170 } 1171 } 1172 1173 if (pdrTerminus.has_value()) 1174 { 1175 if (checkTerminusHandle(data, terminusHandle)) 1176 { 1177 std::cerr << "The Terminus handle doesn't match return" 1178 << std::endl; 1179 return; 1180 } 1181 } 1182 1183 printCommonPDRHeader(pdr, output); 1184 1185 switch (pdr->type) 1186 { 1187 case PLDM_TERMINUS_LOCATOR_PDR: 1188 printTerminusLocatorPDR(data, output); 1189 break; 1190 case PLDM_STATE_SENSOR_PDR: 1191 printStateSensorPDR(data, output); 1192 break; 1193 case PLDM_NUMERIC_EFFECTER_PDR: 1194 printNumericEffecterPDR(data, output); 1195 break; 1196 case PLDM_STATE_EFFECTER_PDR: 1197 printStateEffecterPDR(data, output); 1198 break; 1199 case PLDM_PDR_ENTITY_ASSOCIATION: 1200 printPDREntityAssociation(data, output); 1201 break; 1202 case PLDM_PDR_FRU_RECORD_SET: 1203 printPDRFruRecordSet(data, output); 1204 break; 1205 default: 1206 break; 1207 } 1208 pldmtool::helper::DisplayInJson(output); 1209 } 1210 1211 private: 1212 bool optTIDSet = false; 1213 uint32_t recordHandle; 1214 bool allPDRs; 1215 std::string pdrRecType; 1216 std::optional<uint8_t> pdrTerminus; 1217 std::optional<uint16_t> terminusHandle; 1218 bool handleFound = false; 1219 CLI::Option* getPDRGroupOption = nullptr; 1220 }; 1221 1222 class SetStateEffecter : public CommandInterface 1223 { 1224 public: 1225 ~SetStateEffecter() = default; 1226 SetStateEffecter() = delete; 1227 SetStateEffecter(const SetStateEffecter&) = delete; 1228 SetStateEffecter(SetStateEffecter&&) = default; 1229 SetStateEffecter& operator=(const SetStateEffecter&) = delete; 1230 SetStateEffecter& operator=(SetStateEffecter&&) = delete; 1231 1232 // compositeEffecterCount(value: 0x01 to 0x08) * stateField(2) 1233 static constexpr auto maxEffecterDataSize = 16; 1234 1235 // compositeEffecterCount(value: 0x01 to 0x08) 1236 static constexpr auto minEffecterCount = 1; 1237 static constexpr auto maxEffecterCount = 8; 1238 explicit SetStateEffecter(const char* type, const char* name, 1239 CLI::App* app) : 1240 CommandInterface(type, name, app) 1241 { 1242 app->add_option( 1243 "-i, --id", effecterId, 1244 "A handle that is used to identify and access the effecter") 1245 ->required(); 1246 app->add_option("-c, --count", effecterCount, 1247 "The number of individual sets of effecter information") 1248 ->required(); 1249 app->add_option( 1250 "-d,--data", effecterData, 1251 "Set effecter state data\n" 1252 "eg: requestSet0 effecterState0 noChange1 dummyState1 ...") 1253 ->required(); 1254 } 1255 1256 std::pair<int, std::vector<uint8_t>> createRequestMsg() override 1257 { 1258 std::vector<uint8_t> requestMsg( 1259 sizeof(pldm_msg_hdr) + PLDM_SET_STATE_EFFECTER_STATES_REQ_BYTES); 1260 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 1261 1262 if (effecterCount > maxEffecterCount || 1263 effecterCount < minEffecterCount) 1264 { 1265 std::cerr << "Request Message Error: effecterCount size " 1266 << effecterCount << "is invalid\n"; 1267 auto rc = PLDM_ERROR_INVALID_DATA; 1268 return {rc, requestMsg}; 1269 } 1270 1271 if (effecterData.size() > maxEffecterDataSize) 1272 { 1273 std::cerr << "Request Message Error: effecterData size " 1274 << effecterData.size() << "is invalid\n"; 1275 auto rc = PLDM_ERROR_INVALID_DATA; 1276 return {rc, requestMsg}; 1277 } 1278 1279 auto stateField = parseEffecterData(effecterData, effecterCount); 1280 if (!stateField) 1281 { 1282 std::cerr << "Failed to parse effecter data, effecterCount size " 1283 << effecterCount << "\n"; 1284 auto rc = PLDM_ERROR_INVALID_DATA; 1285 return {rc, requestMsg}; 1286 } 1287 1288 auto rc = encode_set_state_effecter_states_req( 1289 instanceId, effecterId, effecterCount, stateField->data(), request); 1290 return {rc, requestMsg}; 1291 } 1292 1293 void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override 1294 { 1295 uint8_t completionCode = 0; 1296 auto rc = decode_set_state_effecter_states_resp( 1297 responsePtr, payloadLength, &completionCode); 1298 1299 if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS) 1300 { 1301 std::cerr << "Response Message Error: " 1302 << "rc=" << rc << ",cc=" << (int)completionCode << "\n"; 1303 return; 1304 } 1305 1306 ordered_json data; 1307 data["Response"] = "SUCCESS"; 1308 pldmtool::helper::DisplayInJson(data); 1309 } 1310 1311 private: 1312 uint16_t effecterId; 1313 uint8_t effecterCount; 1314 std::vector<uint8_t> effecterData; 1315 }; 1316 1317 class SetNumericEffecterValue : public CommandInterface 1318 { 1319 public: 1320 ~SetNumericEffecterValue() = default; 1321 SetNumericEffecterValue() = delete; 1322 SetNumericEffecterValue(const SetNumericEffecterValue&) = delete; 1323 SetNumericEffecterValue(SetNumericEffecterValue&&) = default; 1324 SetNumericEffecterValue& operator=(const SetNumericEffecterValue&) = delete; 1325 SetNumericEffecterValue& operator=(SetNumericEffecterValue&&) = delete; 1326 1327 explicit SetNumericEffecterValue(const char* type, const char* name, 1328 CLI::App* app) : 1329 CommandInterface(type, name, app) 1330 { 1331 app->add_option( 1332 "-i, --id", effecterId, 1333 "A handle that is used to identify and access the effecter") 1334 ->required(); 1335 app->add_option("-s, --size", effecterDataSize, 1336 "The bit width and format of the setting value for the " 1337 "effecter. enum value: {uint8, sint8, uint16, sint16, " 1338 "uint32, sint32}\n") 1339 ->required(); 1340 app->add_option("-d,--data", maxEffecterValue, 1341 "The setting value of numeric effecter being " 1342 "requested\n") 1343 ->required(); 1344 } 1345 1346 std::pair<int, std::vector<uint8_t>> createRequestMsg() override 1347 { 1348 std::vector<uint8_t> requestMsg( 1349 sizeof(pldm_msg_hdr) + 1350 PLDM_SET_NUMERIC_EFFECTER_VALUE_MIN_REQ_BYTES + 3); 1351 1352 uint8_t* effecterValue = (uint8_t*)&maxEffecterValue; 1353 1354 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 1355 size_t payload_length = PLDM_SET_NUMERIC_EFFECTER_VALUE_MIN_REQ_BYTES; 1356 1357 if (effecterDataSize == PLDM_EFFECTER_DATA_SIZE_UINT16 || 1358 effecterDataSize == PLDM_EFFECTER_DATA_SIZE_SINT16) 1359 { 1360 payload_length = PLDM_SET_NUMERIC_EFFECTER_VALUE_MIN_REQ_BYTES + 1; 1361 } 1362 if (effecterDataSize == PLDM_EFFECTER_DATA_SIZE_UINT32 || 1363 effecterDataSize == PLDM_EFFECTER_DATA_SIZE_SINT32) 1364 { 1365 payload_length = PLDM_SET_NUMERIC_EFFECTER_VALUE_MIN_REQ_BYTES + 3; 1366 } 1367 auto rc = encode_set_numeric_effecter_value_req( 1368 0, effecterId, effecterDataSize, effecterValue, request, 1369 payload_length); 1370 1371 return {rc, requestMsg}; 1372 } 1373 1374 void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override 1375 { 1376 uint8_t completionCode = 0; 1377 auto rc = decode_set_numeric_effecter_value_resp( 1378 responsePtr, payloadLength, &completionCode); 1379 1380 if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS) 1381 { 1382 std::cerr << "Response Message Error: " 1383 << "rc=" << rc << ",cc=" << (int)completionCode 1384 << std::endl; 1385 return; 1386 } 1387 1388 ordered_json data; 1389 data["Response"] = "SUCCESS"; 1390 pldmtool::helper::DisplayInJson(data); 1391 } 1392 1393 private: 1394 uint16_t effecterId; 1395 uint8_t effecterDataSize; 1396 uint64_t maxEffecterValue; 1397 }; 1398 1399 class GetStateSensorReadings : public CommandInterface 1400 { 1401 public: 1402 ~GetStateSensorReadings() = default; 1403 GetStateSensorReadings() = delete; 1404 GetStateSensorReadings(const GetStateSensorReadings&) = delete; 1405 GetStateSensorReadings(GetStateSensorReadings&&) = default; 1406 GetStateSensorReadings& operator=(const GetStateSensorReadings&) = delete; 1407 GetStateSensorReadings& operator=(GetStateSensorReadings&&) = delete; 1408 1409 explicit GetStateSensorReadings(const char* type, const char* name, 1410 CLI::App* app) : 1411 CommandInterface(type, name, app) 1412 { 1413 app->add_option( 1414 "-i, --sensor_id", sensorId, 1415 "Sensor ID that is used to identify and access the sensor") 1416 ->required(); 1417 app->add_option("-r, --rearm", sensorRearm, 1418 "Each bit location in this field corresponds to a " 1419 "particular sensor") 1420 ->required(); 1421 } 1422 1423 std::pair<int, std::vector<uint8_t>> createRequestMsg() override 1424 { 1425 std::vector<uint8_t> requestMsg( 1426 sizeof(pldm_msg_hdr) + PLDM_GET_STATE_SENSOR_READINGS_REQ_BYTES); 1427 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 1428 1429 uint8_t reserved = 0; 1430 bitfield8_t bf; 1431 bf.byte = sensorRearm; 1432 auto rc = encode_get_state_sensor_readings_req(instanceId, sensorId, bf, 1433 reserved, request); 1434 1435 return {rc, requestMsg}; 1436 } 1437 1438 void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override 1439 { 1440 uint8_t completionCode = 0; 1441 uint8_t compSensorCount = 0; 1442 std::array<get_sensor_state_field, 8> stateField{}; 1443 auto rc = decode_get_state_sensor_readings_resp( 1444 responsePtr, payloadLength, &completionCode, &compSensorCount, 1445 stateField.data()); 1446 1447 if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS) 1448 { 1449 std::cerr << "Response Message Error: " 1450 << "rc=" << rc << ",cc=" << (int)completionCode 1451 << std::endl; 1452 return; 1453 } 1454 ordered_json output; 1455 output["compositeSensorCount"] = (int)compSensorCount; 1456 1457 for (size_t i = 0; i < compSensorCount; i++) 1458 { 1459 if (sensorOpState.contains(stateField[i].sensor_op_state)) 1460 { 1461 output.emplace(("sensorOpState[" + std::to_string(i) + "]"), 1462 sensorOpState.at(stateField[i].sensor_op_state)); 1463 } 1464 1465 if (sensorPresState.contains(stateField[i].present_state)) 1466 { 1467 output.emplace(("presentState[" + std::to_string(i) + "]"), 1468 sensorPresState.at(stateField[i].present_state)); 1469 } 1470 1471 if (sensorPresState.contains(stateField[i].previous_state)) 1472 { 1473 output.emplace( 1474 ("previousState[" + std::to_string(i) + "]"), 1475 sensorPresState.at(stateField[i].previous_state)); 1476 } 1477 1478 if (sensorPresState.contains(stateField[i].event_state)) 1479 { 1480 output.emplace(("eventState[" + std::to_string(i) + "]"), 1481 sensorPresState.at(stateField[i].event_state)); 1482 } 1483 } 1484 1485 pldmtool::helper::DisplayInJson(output); 1486 } 1487 1488 private: 1489 uint16_t sensorId; 1490 uint8_t sensorRearm; 1491 }; 1492 1493 void registerCommand(CLI::App& app) 1494 { 1495 auto platform = app.add_subcommand("platform", "platform type command"); 1496 platform->require_subcommand(1); 1497 1498 auto getPDR = platform->add_subcommand("GetPDR", 1499 "get platform descriptor records"); 1500 commands.push_back(std::make_unique<GetPDR>("platform", "getPDR", getPDR)); 1501 1502 auto setStateEffecterStates = platform->add_subcommand( 1503 "SetStateEffecterStates", "set effecter states"); 1504 commands.push_back(std::make_unique<SetStateEffecter>( 1505 "platform", "setStateEffecterStates", setStateEffecterStates)); 1506 1507 auto setNumericEffecterValue = platform->add_subcommand( 1508 "SetNumericEffecterValue", "set the value for a PLDM Numeric Effecter"); 1509 commands.push_back(std::make_unique<SetNumericEffecterValue>( 1510 "platform", "setNumericEffecterValue", setNumericEffecterValue)); 1511 1512 auto getStateSensorReadings = platform->add_subcommand( 1513 "GetStateSensorReadings", "get the state sensor readings"); 1514 commands.push_back(std::make_unique<GetStateSensorReadings>( 1515 "platform", "getStateSensorReadings", getStateSensorReadings)); 1516 } 1517 1518 void parseGetPDROption() 1519 { 1520 for (const auto& command : commands) 1521 { 1522 if (command.get()->getPLDMType() == "platform" && 1523 command.get()->getCommandName() == "getPDR") 1524 { 1525 auto getPDR = dynamic_cast<GetPDR*>(command.get()); 1526 getPDR->parseGetPDROptions(); 1527 } 1528 } 1529 } 1530 1531 } // namespace platform 1532 } // namespace pldmtool 1533