1 #include "terminus.hpp" 2 3 #include "dbus_impl_fru.hpp" 4 #include "terminus_manager.hpp" 5 6 #include <libpldm/platform.h> 7 8 #include <common/utils.hpp> 9 10 #include <ranges> 11 12 namespace pldm 13 { 14 namespace platform_mc 15 { 16 17 Terminus::Terminus(pldm_tid_t tid, uint64_t supportedTypes, 18 sdeventplus::Event& event) : 19 initialized(false), maxBufferSize(PLDM_PLATFORM_EVENT_MSG_MAX_BUFFER_SIZE), 20 synchronyConfigurationSupported(0), pollEvent(false), tid(tid), 21 supportedTypes(supportedTypes), event(event) 22 {} 23 24 bool Terminus::doesSupportType(uint8_t type) 25 { 26 return supportedTypes.test(type); 27 } 28 29 bool Terminus::doesSupportCommand(uint8_t type, uint8_t command) 30 { 31 if (!doesSupportType(type)) 32 { 33 return false; 34 } 35 36 try 37 { 38 const size_t idx = type * (PLDM_MAX_CMDS_PER_TYPE / 8) + (command / 8); 39 if (idx >= supportedCmds.size()) 40 { 41 return false; 42 } 43 44 if (supportedCmds[idx] & (1 << (command % 8))) 45 { 46 lg2::info( 47 "PLDM type {TYPE} command {CMD} is supported by terminus {TID}", 48 "TYPE", type, "CMD", command, "TID", getTid()); 49 return true; 50 } 51 } 52 catch (const std::exception& e) 53 { 54 return false; 55 } 56 57 return false; 58 } 59 60 std::optional<std::string_view> Terminus::findTerminusName() 61 { 62 auto it = std::find_if( 63 entityAuxiliaryNamesTbl.begin(), entityAuxiliaryNamesTbl.end(), 64 [](const std::shared_ptr<EntityAuxiliaryNames>& entityAuxiliaryNames) { 65 const auto& [key, entityNames] = *entityAuxiliaryNames; 66 /** 67 * There is only one Overall system container entity in one 68 * terminus. The entity auxiliary name PDR of that terminus with the 69 * that type of containerID will include terminus name. 70 */ 71 return ( 72 entityAuxiliaryNames && 73 key.containerId == PLDM_PLATFORM_ENTITY_SYSTEM_CONTAINER_ID && 74 entityNames.size()); 75 }); 76 77 if (it != entityAuxiliaryNamesTbl.end()) 78 { 79 const auto& [key, entityNames] = **it; 80 if (!entityNames.size()) 81 { 82 return std::nullopt; 83 } 84 return entityNames[0].second; 85 } 86 87 return std::nullopt; 88 } 89 90 bool Terminus::createInventoryPath(std::string tName) 91 { 92 if (tName.empty()) 93 { 94 return false; 95 } 96 97 /* inventory object is created */ 98 if (inventoryItemBoardInft) 99 { 100 return false; 101 } 102 103 inventoryPath = "/xyz/openbmc_project/inventory/system/board/" + tName; 104 try 105 { 106 inventoryItemBoardInft = 107 std::make_unique<pldm::dbus_api::PldmEntityReq>( 108 utils::DBusHandler::getBus(), inventoryPath.c_str()); 109 return true; 110 } 111 catch (const sdbusplus::exception_t& e) 112 { 113 lg2::error( 114 "Failed to create Inventory Board interface for device {PATH}", 115 "PATH", inventoryPath); 116 } 117 118 return false; 119 } 120 121 void Terminus::parseTerminusPDRs() 122 { 123 for (auto& pdr : pdrs) 124 { 125 auto pdrHdr = new (pdr.data()) pldm_pdr_hdr; 126 switch (pdrHdr->type) 127 { 128 case PLDM_SENSOR_AUXILIARY_NAMES_PDR: 129 { 130 auto sensorAuxNames = parseSensorAuxiliaryNamesPDR(pdr); 131 if (!sensorAuxNames) 132 { 133 lg2::error( 134 "Failed to parse PDR with type {TYPE} handle {HANDLE}", 135 "TYPE", pdrHdr->type, "HANDLE", 136 static_cast<uint32_t>(pdrHdr->record_handle)); 137 continue; 138 } 139 sensorAuxiliaryNamesTbl.emplace_back(std::move(sensorAuxNames)); 140 break; 141 } 142 case PLDM_NUMERIC_SENSOR_PDR: 143 { 144 auto parsedPdr = parseNumericSensorPDR(pdr); 145 if (!parsedPdr) 146 { 147 lg2::error( 148 "Failed to parse PDR with type {TYPE} handle {HANDLE}", 149 "TYPE", pdrHdr->type, "HANDLE", 150 static_cast<uint32_t>(pdrHdr->record_handle)); 151 continue; 152 } 153 numericSensorPdrs.emplace_back(std::move(parsedPdr)); 154 break; 155 } 156 case PLDM_COMPACT_NUMERIC_SENSOR_PDR: 157 { 158 auto parsedPdr = parseCompactNumericSensorPDR(pdr); 159 if (!parsedPdr) 160 { 161 lg2::error( 162 "Failed to parse PDR with type {TYPE} handle {HANDLE}", 163 "TYPE", pdrHdr->type, "HANDLE", 164 static_cast<uint32_t>(pdrHdr->record_handle)); 165 continue; 166 } 167 auto sensorAuxNames = parseCompactNumericSensorNames(pdr); 168 if (!sensorAuxNames) 169 { 170 lg2::error( 171 "Failed to parse sensor name PDR with type {TYPE} handle {HANDLE}", 172 "TYPE", pdrHdr->type, "HANDLE", 173 static_cast<uint32_t>(pdrHdr->record_handle)); 174 continue; 175 } 176 compactNumericSensorPdrs.emplace_back(std::move(parsedPdr)); 177 sensorAuxiliaryNamesTbl.emplace_back(std::move(sensorAuxNames)); 178 break; 179 } 180 case PLDM_ENTITY_AUXILIARY_NAMES_PDR: 181 { 182 auto entityNames = parseEntityAuxiliaryNamesPDR(pdr); 183 if (!entityNames) 184 { 185 lg2::error( 186 "Failed to parse sensor name PDR with type {TYPE} handle {HANDLE}", 187 "TYPE", pdrHdr->type, "HANDLE", 188 static_cast<uint32_t>(pdrHdr->record_handle)); 189 continue; 190 } 191 entityAuxiliaryNamesTbl.emplace_back(std::move(entityNames)); 192 break; 193 } 194 default: 195 { 196 lg2::error("Unsupported PDR with type {TYPE} handle {HANDLE}", 197 "TYPE", pdrHdr->type, "HANDLE", 198 static_cast<uint32_t>(pdrHdr->record_handle)); 199 break; 200 } 201 } 202 } 203 204 auto tName = findTerminusName(); 205 if (tName && !tName.value().empty()) 206 { 207 lg2::info("Terminus {TID} has Auxiliary Name {NAME}.", "TID", tid, 208 "NAME", tName.value()); 209 terminusName = static_cast<std::string>(tName.value()); 210 } 211 else 212 { 213 terminusName = std::format("Terminus_{}", tid); 214 } 215 216 if (terminusName.empty() && 217 (numericSensorPdrs.size() || compactNumericSensorPdrs.size())) 218 { 219 lg2::error( 220 "Terminus ID {TID}: DOES NOT have name. Skip Adding sensors.", 221 "TID", tid); 222 return; 223 } 224 225 if (createInventoryPath(terminusName)) 226 { 227 lg2::info("Terminus ID {TID}: Created Inventory path {PATH}.", "TID", 228 tid, "PATH", inventoryPath); 229 } 230 231 addNextSensorFromPDRs(); 232 } 233 234 void Terminus::addNextSensorFromPDRs() 235 { 236 sensorCreationEvent.reset(); 237 238 if (terminusName.empty()) 239 { 240 lg2::error( 241 "Terminus ID {TID}: DOES NOT have name. Skip Adding sensors.", 242 "TID", tid); 243 return; 244 } 245 246 auto pdrIt = sensorPdrIt; 247 248 if (pdrIt < numericSensorPdrs.size()) 249 { 250 const auto& pdr = numericSensorPdrs[pdrIt]; 251 // Defer adding the next Numeric Sensor 252 sensorCreationEvent = std::make_unique<sdeventplus::source::Defer>( 253 event, 254 std::bind(std::mem_fn(&Terminus::addNumericSensor), this, pdr)); 255 } 256 else if (pdrIt < numericSensorPdrs.size() + compactNumericSensorPdrs.size()) 257 { 258 pdrIt -= numericSensorPdrs.size(); 259 const auto& pdr = compactNumericSensorPdrs[pdrIt]; 260 // Defer adding the next Compact Numeric Sensor 261 sensorCreationEvent = std::make_unique<sdeventplus::source::Defer>( 262 event, std::bind(std::mem_fn(&Terminus::addCompactNumericSensor), 263 this, pdr)); 264 } 265 else 266 { 267 sensorPdrIt = 0; 268 return; 269 } 270 271 // Move the iteration to the next sensor PDR 272 sensorPdrIt++; 273 } 274 275 std::shared_ptr<SensorAuxiliaryNames> Terminus::getSensorAuxiliaryNames( 276 SensorID id) 277 { 278 auto it = std::find_if( 279 sensorAuxiliaryNamesTbl.begin(), sensorAuxiliaryNamesTbl.end(), 280 [id]( 281 const std::shared_ptr<SensorAuxiliaryNames>& sensorAuxiliaryNames) { 282 const auto& [sensorId, sensorCnt, sensorNames] = 283 *sensorAuxiliaryNames; 284 return sensorId == id; 285 }); 286 287 if (it != sensorAuxiliaryNamesTbl.end()) 288 { 289 return *it; 290 } 291 return nullptr; 292 }; 293 294 std::shared_ptr<SensorAuxiliaryNames> Terminus::parseSensorAuxiliaryNamesPDR( 295 const std::vector<uint8_t>& pdrData) 296 { 297 constexpr uint8_t nullTerminator = 0; 298 auto pdr = reinterpret_cast<const struct pldm_sensor_auxiliary_names_pdr*>( 299 pdrData.data()); 300 const uint8_t* ptr = pdr->names; 301 std::vector<AuxiliaryNames> sensorAuxNames{}; 302 char16_t alignedBuffer[PLDM_STR_UTF_16_MAX_LEN]; 303 for ([[maybe_unused]] const auto& sensor : 304 std::views::iota(0, static_cast<int>(pdr->sensor_count))) 305 { 306 const uint8_t nameStringCount = static_cast<uint8_t>(*ptr); 307 ptr += sizeof(uint8_t); 308 AuxiliaryNames nameStrings{}; 309 for ([[maybe_unused]] const auto& count : 310 std::views::iota(0, static_cast<int>(nameStringCount))) 311 { 312 std::string_view nameLanguageTag( 313 reinterpret_cast<const char*>(ptr)); 314 ptr += nameLanguageTag.size() + sizeof(nullTerminator); 315 316 int u16NameStringLen = 0; 317 for (int i = 0; ptr[i] != 0 || ptr[i + 1] != 0; i += 2) 318 { 319 u16NameStringLen++; 320 } 321 /* include terminator */ 322 u16NameStringLen++; 323 324 std::fill(std::begin(alignedBuffer), std::end(alignedBuffer), 0); 325 if (u16NameStringLen > PLDM_STR_UTF_16_MAX_LEN) 326 { 327 lg2::error("Sensor name too long."); 328 return nullptr; 329 } 330 memcpy(alignedBuffer, ptr, u16NameStringLen * sizeof(uint16_t)); 331 std::u16string u16NameString(alignedBuffer, u16NameStringLen); 332 ptr += u16NameString.size() * sizeof(uint16_t); 333 std::transform(u16NameString.cbegin(), u16NameString.cend(), 334 u16NameString.begin(), 335 [](uint16_t utf16) { return be16toh(utf16); }); 336 #pragma GCC diagnostic push 337 #pragma GCC diagnostic ignored "-Wdeprecated-declarations" 338 std::string nameString = 339 std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, 340 char16_t>{} 341 .to_bytes(u16NameString); 342 #pragma GCC diagnostic pop 343 nameStrings.emplace_back(std::make_pair( 344 nameLanguageTag, pldm::utils::trimNameForDbus(nameString))); 345 } 346 sensorAuxNames.emplace_back(std::move(nameStrings)); 347 } 348 return std::make_shared<SensorAuxiliaryNames>( 349 pdr->sensor_id, pdr->sensor_count, std::move(sensorAuxNames)); 350 } 351 352 std::shared_ptr<EntityAuxiliaryNames> Terminus::parseEntityAuxiliaryNamesPDR( 353 const std::vector<uint8_t>& pdrData) 354 { 355 auto names_offset = sizeof(struct pldm_pdr_hdr) + 356 PLDM_PDR_ENTITY_AUXILIARY_NAME_PDR_MIN_LENGTH; 357 auto names_size = pdrData.size() - names_offset; 358 359 size_t decodedPdrSize = 360 sizeof(struct pldm_entity_auxiliary_names_pdr) + names_size; 361 auto vPdr = std::vector<char>(decodedPdrSize); 362 auto decodedPdr = new (vPdr.data()) pldm_entity_auxiliary_names_pdr; 363 364 auto rc = decode_entity_auxiliary_names_pdr(pdrData.data(), pdrData.size(), 365 decodedPdr, decodedPdrSize); 366 367 if (rc) 368 { 369 lg2::error( 370 "Failed to decode Entity Auxiliary Name PDR data, error {RC}.", 371 "RC", rc); 372 return nullptr; 373 } 374 375 auto vNames = 376 std::vector<pldm_entity_auxiliary_name>(decodedPdr->name_string_count); 377 decodedPdr->names = vNames.data(); 378 379 rc = decode_pldm_entity_auxiliary_names_pdr_index(decodedPdr); 380 if (rc) 381 { 382 lg2::error("Failed to decode Entity Auxiliary Name, error {RC}.", "RC", 383 rc); 384 return nullptr; 385 } 386 387 AuxiliaryNames nameStrings{}; 388 for (const auto& count : 389 std::views::iota(0, static_cast<int>(decodedPdr->name_string_count))) 390 { 391 std::string_view nameLanguageTag = 392 static_cast<std::string_view>(decodedPdr->names[count].tag); 393 const size_t u16NameStringLen = 394 std::char_traits<char16_t>::length(decodedPdr->names[count].name); 395 std::u16string u16NameString(decodedPdr->names[count].name, 396 u16NameStringLen); 397 std::transform(u16NameString.cbegin(), u16NameString.cend(), 398 u16NameString.begin(), 399 [](uint16_t utf16) { return be16toh(utf16); }); 400 #pragma GCC diagnostic push 401 #pragma GCC diagnostic ignored "-Wdeprecated-declarations" 402 std::string nameString = 403 std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{} 404 .to_bytes(u16NameString); 405 #pragma GCC diagnostic pop 406 nameStrings.emplace_back(std::make_pair( 407 nameLanguageTag, pldm::utils::trimNameForDbus(nameString))); 408 } 409 410 EntityKey key{decodedPdr->container.entity_type, 411 decodedPdr->container.entity_instance_num, 412 decodedPdr->container.entity_container_id}; 413 414 return std::make_shared<EntityAuxiliaryNames>(key, nameStrings); 415 } 416 417 std::shared_ptr<pldm_numeric_sensor_value_pdr> Terminus::parseNumericSensorPDR( 418 const std::vector<uint8_t>& pdr) 419 { 420 const uint8_t* ptr = pdr.data(); 421 auto parsedPdr = std::make_shared<pldm_numeric_sensor_value_pdr>(); 422 auto rc = decode_numeric_sensor_pdr_data(ptr, pdr.size(), parsedPdr.get()); 423 if (rc) 424 { 425 return nullptr; 426 } 427 return parsedPdr; 428 } 429 430 void Terminus::addNumericSensor( 431 const std::shared_ptr<pldm_numeric_sensor_value_pdr> pdr) 432 { 433 if (!pdr) 434 { 435 lg2::error( 436 "Terminus ID {TID}: Skip adding Numeric Sensor - invalid pointer to PDR.", 437 "TID", tid); 438 addNextSensorFromPDRs(); 439 } 440 441 auto sensorId = pdr->sensor_id; 442 auto sensorNames = getSensorNames(sensorId); 443 444 if (sensorNames.empty()) 445 { 446 lg2::error( 447 "Terminus ID {TID}: Failed to get name for Numeric Sensor {SID}", 448 "TID", tid, "SID", sensorId); 449 addNextSensorFromPDRs(); 450 } 451 452 std::string sensorName = sensorNames.front(); 453 454 try 455 { 456 auto sensor = std::make_shared<NumericSensor>( 457 tid, true, pdr, sensorName, inventoryPath); 458 lg2::info("Created NumericSensor {NAME}", "NAME", sensorName); 459 numericSensors.emplace_back(sensor); 460 } 461 catch (const sdbusplus::exception_t& e) 462 { 463 lg2::error( 464 "Failed to create NumericSensor. error - {ERROR} sensorname - {NAME}", 465 "ERROR", e, "NAME", sensorName); 466 } 467 468 addNextSensorFromPDRs(); 469 } 470 471 std::shared_ptr<SensorAuxiliaryNames> Terminus::parseCompactNumericSensorNames( 472 const std::vector<uint8_t>& sPdr) 473 { 474 std::vector<std::vector<std::pair<NameLanguageTag, SensorName>>> 475 sensorAuxNames{}; 476 AuxiliaryNames nameStrings{}; 477 478 auto pdr = 479 reinterpret_cast<const pldm_compact_numeric_sensor_pdr*>(sPdr.data()); 480 481 if (sPdr.size() < 482 (sizeof(pldm_compact_numeric_sensor_pdr) - sizeof(uint8_t))) 483 { 484 return nullptr; 485 } 486 487 if (!pdr->sensor_name_length || 488 (sPdr.size() < (sizeof(pldm_compact_numeric_sensor_pdr) - 489 sizeof(uint8_t) + pdr->sensor_name_length))) 490 { 491 return nullptr; 492 } 493 494 std::string nameString(reinterpret_cast<const char*>(pdr->sensor_name), 495 pdr->sensor_name_length); 496 nameStrings.emplace_back( 497 std::make_pair("en", pldm::utils::trimNameForDbus(nameString))); 498 sensorAuxNames.emplace_back(std::move(nameStrings)); 499 500 return std::make_shared<SensorAuxiliaryNames>(pdr->sensor_id, 1, 501 std::move(sensorAuxNames)); 502 } 503 504 std::shared_ptr<pldm_compact_numeric_sensor_pdr> 505 Terminus::parseCompactNumericSensorPDR(const std::vector<uint8_t>& sPdr) 506 { 507 auto pdr = 508 reinterpret_cast<const pldm_compact_numeric_sensor_pdr*>(sPdr.data()); 509 if (sPdr.size() < sizeof(pldm_compact_numeric_sensor_pdr)) 510 { 511 // Handle error: input data too small to contain valid pdr 512 return nullptr; 513 } 514 auto parsedPdr = std::make_shared<pldm_compact_numeric_sensor_pdr>(); 515 516 parsedPdr->hdr = pdr->hdr; 517 parsedPdr->terminus_handle = pdr->terminus_handle; 518 parsedPdr->sensor_id = pdr->sensor_id; 519 parsedPdr->entity_type = pdr->entity_type; 520 parsedPdr->entity_instance = pdr->entity_instance; 521 parsedPdr->container_id = pdr->container_id; 522 parsedPdr->sensor_name_length = pdr->sensor_name_length; 523 parsedPdr->base_unit = pdr->base_unit; 524 parsedPdr->unit_modifier = pdr->unit_modifier; 525 parsedPdr->occurrence_rate = pdr->occurrence_rate; 526 parsedPdr->range_field_support = pdr->range_field_support; 527 parsedPdr->warning_high = pdr->warning_high; 528 parsedPdr->warning_low = pdr->warning_low; 529 parsedPdr->critical_high = pdr->critical_high; 530 parsedPdr->critical_low = pdr->critical_low; 531 parsedPdr->fatal_high = pdr->fatal_high; 532 parsedPdr->fatal_low = pdr->fatal_low; 533 return parsedPdr; 534 } 535 536 void Terminus::addCompactNumericSensor( 537 const std::shared_ptr<pldm_compact_numeric_sensor_pdr> pdr) 538 { 539 if (!pdr) 540 { 541 lg2::error( 542 "Terminus ID {TID}: Skip adding Compact Numeric Sensor - invalid pointer to PDR.", 543 "TID", tid); 544 addNextSensorFromPDRs(); 545 } 546 547 auto sensorId = pdr->sensor_id; 548 auto sensorNames = getSensorNames(sensorId); 549 550 if (sensorNames.empty()) 551 { 552 lg2::error( 553 "Terminus ID {TID}: Failed to get name for Compact Numeric Sensor {SID}", 554 "TID", tid, "SID", sensorId); 555 addNextSensorFromPDRs(); 556 } 557 558 std::string sensorName = sensorNames.front(); 559 560 try 561 { 562 auto sensor = std::make_shared<NumericSensor>( 563 tid, true, pdr, sensorName, inventoryPath); 564 lg2::info("Created Compact NumericSensor {NAME}", "NAME", sensorName); 565 numericSensors.emplace_back(sensor); 566 } 567 catch (const sdbusplus::exception_t& e) 568 { 569 lg2::error( 570 "Failed to create Compact NumericSensor. error - {ERROR} sensorname - {NAME}", 571 "ERROR", e, "NAME", sensorName); 572 } 573 574 addNextSensorFromPDRs(); 575 } 576 577 std::shared_ptr<NumericSensor> Terminus::getSensorObject(SensorID id) 578 { 579 if (terminusName.empty()) 580 { 581 lg2::error( 582 "Terminus ID {TID}: DOES NOT have terminus name. No numeric sensor object.", 583 "TID", tid); 584 return nullptr; 585 } 586 if (!numericSensors.size()) 587 { 588 lg2::error("Terminus ID {TID} name {NAME}: DOES NOT have sensor.", 589 "TID", tid, "NAME", terminusName); 590 return nullptr; 591 } 592 593 for (auto& sensor : numericSensors) 594 { 595 if (!sensor) 596 { 597 continue; 598 } 599 600 if (sensor->sensorId == id) 601 { 602 return sensor; 603 } 604 } 605 606 return nullptr; 607 } 608 609 /** @brief Check if a pointer is go through end of table 610 * @param[in] table - pointer to FRU record table 611 * @param[in] p - pointer to each record of FRU record table 612 * @param[in] tableSize - FRU table size 613 */ 614 static bool isTableEnd(const uint8_t* table, const uint8_t* p, 615 const size_t tableSize) 616 { 617 auto offset = p - table; 618 return (tableSize - offset) < sizeof(struct pldm_fru_record_data_format); 619 } 620 621 void Terminus::updateInventoryWithFru(const uint8_t* fruData, 622 const size_t fruLen) 623 { 624 auto tmp = getTerminusName(); 625 if (!tmp || tmp.value().empty()) 626 { 627 lg2::error( 628 "Terminus ID {TID}: Failed to update Inventory with Fru Data - error : Terminus name is empty.", 629 "TID", tid); 630 return; 631 } 632 633 if (createInventoryPath(static_cast<std::string>(tmp.value()))) 634 { 635 lg2::info("Terminus ID {TID}: Created Inventory path.", "TID", tid); 636 } 637 638 auto ptr = fruData; 639 while (!isTableEnd(fruData, ptr, fruLen)) 640 { 641 auto record = reinterpret_cast<const pldm_fru_record_data_format*>(ptr); 642 ptr += sizeof(pldm_fru_record_data_format) - 643 sizeof(pldm_fru_record_tlv); 644 645 if (!record->num_fru_fields) 646 { 647 lg2::error( 648 "Invalid number of fields {NUM} of Record ID Type {TYPE} of terminus {TID}", 649 "NUM", record->num_fru_fields, "TYPE", record->record_type, 650 "TID", tid); 651 return; 652 } 653 654 if (record->record_type != PLDM_FRU_RECORD_TYPE_GENERAL) 655 { 656 lg2::error( 657 "Does not support Fru Record ID Type {TYPE} of terminus {TID}", 658 "TYPE", record->record_type, "TID", tid); 659 660 for ([[maybe_unused]] const auto& idx : 661 std::views::iota(0, static_cast<int>(record->num_fru_fields))) 662 { 663 auto tlv = reinterpret_cast<const pldm_fru_record_tlv*>(ptr); 664 ptr += sizeof(pldm_fru_record_tlv) - 1 + tlv->length; 665 } 666 continue; 667 } 668 /* FRU General record type */ 669 for ([[maybe_unused]] const auto& idx : 670 std::views::iota(0, static_cast<int>(record->num_fru_fields))) 671 { 672 auto tlv = reinterpret_cast<const pldm_fru_record_tlv*>(ptr); 673 std::string fruField{}; 674 if (tlv->type != PLDM_FRU_FIELD_TYPE_IANA) 675 { 676 auto strOptional = 677 pldm::utils::fruFieldValuestring(tlv->value, tlv->length); 678 if (!strOptional) 679 { 680 ptr += sizeof(pldm_fru_record_tlv) - 1 + tlv->length; 681 continue; 682 } 683 fruField = strOptional.value(); 684 685 if (fruField.empty()) 686 { 687 ptr += sizeof(pldm_fru_record_tlv) - 1 + tlv->length; 688 continue; 689 } 690 } 691 692 switch (tlv->type) 693 { 694 case PLDM_FRU_FIELD_TYPE_MODEL: 695 inventoryItemBoardInft->model(fruField); 696 break; 697 case PLDM_FRU_FIELD_TYPE_PN: 698 inventoryItemBoardInft->partNumber(fruField); 699 break; 700 case PLDM_FRU_FIELD_TYPE_SN: 701 inventoryItemBoardInft->serialNumber(fruField); 702 break; 703 case PLDM_FRU_FIELD_TYPE_MANUFAC: 704 inventoryItemBoardInft->manufacturer(fruField); 705 break; 706 case PLDM_FRU_FIELD_TYPE_NAME: 707 inventoryItemBoardInft->names({fruField}); 708 break; 709 case PLDM_FRU_FIELD_TYPE_VERSION: 710 inventoryItemBoardInft->version(fruField); 711 break; 712 case PLDM_FRU_FIELD_TYPE_ASSET_TAG: 713 inventoryItemBoardInft->assetTag(fruField); 714 break; 715 case PLDM_FRU_FIELD_TYPE_VENDOR: 716 case PLDM_FRU_FIELD_TYPE_CHASSIS: 717 case PLDM_FRU_FIELD_TYPE_SKU: 718 case PLDM_FRU_FIELD_TYPE_DESC: 719 case PLDM_FRU_FIELD_TYPE_EC_LVL: 720 case PLDM_FRU_FIELD_TYPE_OTHER: 721 break; 722 case PLDM_FRU_FIELD_TYPE_IANA: 723 auto iana = 724 pldm::utils::fruFieldParserU32(tlv->value, tlv->length); 725 if (!iana) 726 { 727 ptr += sizeof(pldm_fru_record_tlv) - 1 + tlv->length; 728 continue; 729 } 730 break; 731 } 732 ptr += sizeof(pldm_fru_record_tlv) - 1 + tlv->length; 733 } 734 } 735 } 736 737 std::vector<std::string> Terminus::getSensorNames(const SensorID& sensorId) 738 { 739 std::vector<std::string> sensorNames; 740 std::string defaultName = 741 std::format("{}_Sensor_{}", terminusName, unsigned(sensorId)); 742 // To ensure there's always a default name at offset 0 743 sensorNames.emplace_back(defaultName); 744 745 auto sensorAuxiliaryNames = getSensorAuxiliaryNames(sensorId); 746 if (!sensorAuxiliaryNames) 747 { 748 return sensorNames; 749 } 750 751 const auto& [id, sensorCount, nameMap] = *sensorAuxiliaryNames; 752 for (const unsigned int& i : 753 std::views::iota(0, static_cast<int>(sensorCount))) 754 { 755 auto sensorName = defaultName; 756 if (i > 0) 757 { 758 // Sensor name at offset 0 will be the default name 759 sensorName += "_" + std::to_string(i); 760 } 761 762 for (const auto& [languageTag, name] : nameMap[i]) 763 { 764 if (languageTag == "en" && !name.empty()) 765 { 766 sensorName = std::format("{}_{}", terminusName, name); 767 } 768 } 769 770 if (i >= sensorNames.size()) 771 { 772 sensorNames.emplace_back(sensorName); 773 } 774 else 775 { 776 sensorNames[i] = sensorName; 777 } 778 } 779 780 return sensorNames; 781 } 782 783 } // namespace platform_mc 784 } // namespace pldm 785