platform-mc: Terminus name handling

`PLDM-stack: Adding sensor monitoring section` design spec details that
the `Terminus name` is required to create the terminus's sensors,
states, effecters... D-Bus interfaces and `Terminus Name` can be
encoded in the Terminus's `Entity Auxiliary Names PDR` or in the MCTP
Entity-manager endpoint EID configuration file.
[1] https://gerrit.openbmc.org/c/openbmc/docs/+/47252/34/designs/pldm-stack.md#433

Section `28.18 Entity Auxiliary Names PDR` in DSP0248 V1.2.2 details
about the PDRs response for the name of one PLDM entity. When the
containerID is `0x0000` this entity is `Overall system` or `top most
containing entity`. The name of this entity will can be used as
`Terminus name`.

Support parsing `Entity Auxiliary Names PDR` and find the `Terminus
name` if it is reponsed in the terminus' PDRs. `Terminus Name` string
will be assigned to local variable and can be used as prefix for
sensors, state, effecters... names.

Signed-off-by: Thu Nguyen <thu@os.amperecomputing.com>
Change-Id: I701537c48651b9de86de77941b752e30de112916
diff --git a/platform-mc/terminus.cpp b/platform-mc/terminus.cpp
index 194583f..2892dc1 100644
--- a/platform-mc/terminus.cpp
+++ b/platform-mc/terminus.cpp
@@ -4,6 +4,8 @@
 
 #include "terminus_manager.hpp"
 
+#include <common/utils.hpp>
+
 #include <ranges>
 
 namespace pldm
@@ -51,6 +53,35 @@
     return false;
 }
 
+std::optional<std::string_view> Terminus::findTerminusName()
+{
+    auto it = std::find_if(
+        entityAuxiliaryNamesTbl.begin(), entityAuxiliaryNamesTbl.end(),
+        [](const std::shared_ptr<EntityAuxiliaryNames>& entityAuxiliaryNames) {
+        const auto& [key, entityNames] = *entityAuxiliaryNames;
+        /**
+         * There is only one Overal system container entity in one terminus.
+         * The entity auxiliary name PDR of that terminus with the that type of
+         * containerID will include terminus name.
+         **/
+        return (entityAuxiliaryNames &&
+                key.containerId == PLDM_PLATFORM_ENTITY_SYSTEM_CONTAINER_ID &&
+                entityNames.size());
+    });
+
+    if (it != entityAuxiliaryNamesTbl.end())
+    {
+        const auto& [key, entityNames] = **it;
+        if (!entityNames.size())
+        {
+            return std::nullopt;
+        }
+        return entityNames[0].second;
+    }
+
+    return std::nullopt;
+}
+
 void Terminus::parseTerminusPDRs()
 {
     std::vector<std::shared_ptr<pldm_numeric_sensor_value_pdr>>
@@ -115,6 +146,20 @@
                 sensorAuxiliaryNamesTbl.emplace_back(std::move(sensorAuxNames));
                 break;
             }
+            case PLDM_ENTITY_AUXILIARY_NAMES_PDR:
+            {
+                auto entityNames = parseEntityAuxiliaryNamesPDR(pdr);
+                if (!entityNames)
+                {
+                    lg2::error(
+                        "Failed to parse sensor name PDR with type {TYPE} handle {HANDLE}",
+                        "TYPE", pdrHdr->type, "HANDLE",
+                        static_cast<uint32_t>(pdrHdr->record_handle));
+                    continue;
+                }
+                entityAuxiliaryNamesTbl.emplace_back(std::move(entityNames));
+                break;
+            }
             default:
             {
                 lg2::error("Unsupported PDR with type {TYPE} handle {HANDLE}",
@@ -124,6 +169,14 @@
             }
         }
     }
+
+    auto tName = findTerminusName();
+    if (tName && !tName.value().empty())
+    {
+        lg2::info("Terminus {TID} has Auxiliary Name {NAME}.", "TID", tid,
+                  "NAME", tName.value());
+        terminusName = static_cast<std::string>(tName.value());
+    }
 }
 
 std::shared_ptr<SensorAuxiliaryNames>
@@ -151,15 +204,14 @@
     auto pdr = reinterpret_cast<const struct pldm_sensor_auxiliary_names_pdr*>(
         pdrData.data());
     const uint8_t* ptr = pdr->names;
-    std::vector<std::vector<std::pair<NameLanguageTag, SensorName>>>
-        sensorAuxNames{};
+    std::vector<AuxiliaryNames> sensorAuxNames{};
     char16_t alignedBuffer[PLDM_STR_UTF_16_MAX_LEN];
     for ([[maybe_unused]] const auto& sensor :
          std::views::iota(0, static_cast<int>(pdr->sensor_count)))
     {
         const uint8_t nameStringCount = static_cast<uint8_t>(*ptr);
         ptr += sizeof(uint8_t);
-        std::vector<std::pair<NameLanguageTag, SensorName>> nameStrings{};
+        AuxiliaryNames nameStrings{};
         for ([[maybe_unused]] const auto& count :
              std::views::iota(0, static_cast<int>(nameStringCount)))
         {
@@ -192,14 +244,8 @@
                 std::wstring_convert<std::codecvt_utf8_utf16<char16_t>,
                                      char16_t>{}
                     .to_bytes(u16NameString);
-            std::replace(nameString.begin(), nameString.end(), ' ', '_');
-            auto nullTerminatorPos = nameString.find('\0');
-            if (nullTerminatorPos != std::string::npos)
-            {
-                nameString.erase(nullTerminatorPos);
-            }
-            nameStrings.emplace_back(
-                std::make_pair(nameLanguageTag, nameString));
+            nameStrings.emplace_back(std::make_pair(
+                nameLanguageTag, pldm::utils::trimNameForDbus(nameString)));
         }
         sensorAuxNames.emplace_back(std::move(nameStrings));
     }
@@ -207,6 +253,69 @@
         pdr->sensor_id, pdr->sensor_count, std::move(sensorAuxNames));
 }
 
+std::shared_ptr<EntityAuxiliaryNames>
+    Terminus::parseEntityAuxiliaryNamesPDR(const std::vector<uint8_t>& pdrData)
+{
+    auto names_offset = sizeof(struct pldm_pdr_hdr) +
+                        PLDM_PDR_ENTITY_AUXILIARY_NAME_PDR_MIN_LENGTH;
+    auto names_size = pdrData.size() - names_offset;
+
+    size_t decodedPdrSize = sizeof(struct pldm_entity_auxiliary_names_pdr) +
+                            names_size;
+    auto vPdr = std::vector<char>(decodedPdrSize);
+    auto decodedPdr =
+        reinterpret_cast<struct pldm_entity_auxiliary_names_pdr*>(vPdr.data());
+
+    auto rc = decode_entity_auxiliary_names_pdr(pdrData.data(), pdrData.size(),
+                                                decodedPdr, decodedPdrSize);
+
+    if (rc)
+    {
+        lg2::error(
+            "Failed to decode Entity Auxiliary Name PDR data, error {RC}.",
+            "RC", rc);
+        return nullptr;
+    }
+
+    auto vNames =
+        std::vector<pldm_entity_auxiliary_name>(decodedPdr->name_string_count);
+    decodedPdr->names = vNames.data();
+
+    rc = decode_pldm_entity_auxiliary_names_pdr_index(decodedPdr);
+    if (rc)
+    {
+        lg2::error("Failed to decode Entity Auxiliary Name, error {RC}.", "RC",
+                   rc);
+        return nullptr;
+    }
+
+    AuxiliaryNames nameStrings{};
+    for (const auto& count :
+         std::views::iota(0, static_cast<int>(decodedPdr->name_string_count)))
+    {
+        std::string_view nameLanguageTag =
+            static_cast<std::string_view>(decodedPdr->names[count].tag);
+        const size_t u16NameStringLen =
+            std::char_traits<char16_t>::length(decodedPdr->names[count].name);
+        std::u16string u16NameString(decodedPdr->names[count].name,
+                                     u16NameStringLen);
+        std::transform(u16NameString.cbegin(), u16NameString.cend(),
+                       u16NameString.begin(),
+                       [](uint16_t utf16) { return be16toh(utf16); });
+        std::string nameString =
+            std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}
+                .to_bytes(u16NameString);
+        nameStrings.emplace_back(std::make_pair(
+            nameLanguageTag, pldm::utils::trimNameForDbus(nameString)));
+    }
+
+    EntityKey key{decodedPdr->container.entity_type,
+                  decodedPdr->container.entity_instance_num,
+                  decodedPdr->container.entity_container_id};
+
+    return std::make_shared<EntityAuxiliaryNames>(key, nameStrings);
+}
+
 std::shared_ptr<pldm_numeric_sensor_value_pdr>
     Terminus::parseNumericSensorPDR(const std::vector<uint8_t>& pdr)
 {
@@ -225,7 +334,7 @@
 {
     std::vector<std::vector<std::pair<NameLanguageTag, SensorName>>>
         sensorAuxNames{};
-    std::vector<std::pair<NameLanguageTag, SensorName>> nameStrings{};
+    AuxiliaryNames nameStrings{};
     auto pdr =
         reinterpret_cast<const pldm_compact_numeric_sensor_pdr*>(sPdr.data());
 
@@ -244,13 +353,8 @@
 
     std::string nameString(reinterpret_cast<const char*>(pdr->sensor_name),
                            pdr->sensor_name_length);
-    std::replace(nameString.begin(), nameString.end(), ' ', '_');
-    auto nullTerminatorPos = nameString.find('\0');
-    if (nullTerminatorPos != std::string::npos)
-    {
-        nameString.erase(nullTerminatorPos);
-    }
-    nameStrings.emplace_back(std::make_pair("en", nameString));
+    nameStrings.emplace_back(
+        std::make_pair("en", pldm::utils::trimNameForDbus(nameString)));
     sensorAuxNames.emplace_back(std::move(nameStrings));
 
     return std::make_shared<SensorAuxiliaryNames>(pdr->sensor_id, 1,