platform-mc: PDR handling
Get PDRs of new terminus if it supports GetPDR PLDM command. It doesn't
handle the event receiver related initialization steps, and either
doesn't support primary PDR repository to maintain terminus locator PDR
information yet.
Added parse PDR member functions to terminus class for parsing Numeric
sensor PDR and sensor auxiliary names PDR.
Added sensor auxiliary names PDR and numeric sensor PDR struct in
libpldm/platform.h
Signed-off-by: Gilbert Chen <gilbert.chen@arm.com>
Signed-off-by: Thu Nguyen <thu@os.amperecomputing.com>
Change-Id: I30a0cc594a3c08fc17f2dad861b5c5d41c80ebdd
diff --git a/platform-mc/terminus.cpp b/platform-mc/terminus.cpp
index 947571b..194583f 100644
--- a/platform-mc/terminus.cpp
+++ b/platform-mc/terminus.cpp
@@ -4,6 +4,8 @@
#include "terminus_manager.hpp"
+#include <ranges>
+
namespace pldm
{
namespace platform_mc
@@ -49,5 +51,243 @@
return false;
}
+void Terminus::parseTerminusPDRs()
+{
+ std::vector<std::shared_ptr<pldm_numeric_sensor_value_pdr>>
+ numericSensorPdrs{};
+ std::vector<std::shared_ptr<pldm_compact_numeric_sensor_pdr>>
+ compactNumericSensorPdrs{};
+
+ for (auto& pdr : pdrs)
+ {
+ auto pdrHdr = reinterpret_cast<pldm_pdr_hdr*>(pdr.data());
+ switch (pdrHdr->type)
+ {
+ case PLDM_SENSOR_AUXILIARY_NAMES_PDR:
+ {
+ auto sensorAuxNames = parseSensorAuxiliaryNamesPDR(pdr);
+ if (!sensorAuxNames)
+ {
+ lg2::error(
+ "Failed to parse PDR with type {TYPE} handle {HANDLE}",
+ "TYPE", pdrHdr->type, "HANDLE",
+ static_cast<uint32_t>(pdrHdr->record_handle));
+ continue;
+ }
+ sensorAuxiliaryNamesTbl.emplace_back(std::move(sensorAuxNames));
+ break;
+ }
+ case PLDM_NUMERIC_SENSOR_PDR:
+ {
+ auto parsedPdr = parseNumericSensorPDR(pdr);
+ if (!parsedPdr)
+ {
+ lg2::error(
+ "Failed to parse PDR with type {TYPE} handle {HANDLE}",
+ "TYPE", pdrHdr->type, "HANDLE",
+ static_cast<uint32_t>(pdrHdr->record_handle));
+ continue;
+ }
+ numericSensorPdrs.emplace_back(std::move(parsedPdr));
+ break;
+ }
+ case PLDM_COMPACT_NUMERIC_SENSOR_PDR:
+ {
+ auto parsedPdr = parseCompactNumericSensorPDR(pdr);
+ if (!parsedPdr)
+ {
+ lg2::error(
+ "Failed to parse PDR with type {TYPE} handle {HANDLE}",
+ "TYPE", pdrHdr->type, "HANDLE",
+ static_cast<uint32_t>(pdrHdr->record_handle));
+ continue;
+ }
+ auto sensorAuxNames = parseCompactNumericSensorNames(pdr);
+ if (!sensorAuxNames)
+ {
+ 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;
+ }
+ compactNumericSensorPdrs.emplace_back(std::move(parsedPdr));
+ sensorAuxiliaryNamesTbl.emplace_back(std::move(sensorAuxNames));
+ break;
+ }
+ default:
+ {
+ lg2::error("Unsupported PDR with type {TYPE} handle {HANDLE}",
+ "TYPE", pdrHdr->type, "HANDLE",
+ static_cast<uint32_t>(pdrHdr->record_handle));
+ break;
+ }
+ }
+ }
+}
+
+std::shared_ptr<SensorAuxiliaryNames>
+ Terminus::getSensorAuxiliaryNames(SensorId id)
+{
+ auto it = std::find_if(
+ sensorAuxiliaryNamesTbl.begin(), sensorAuxiliaryNamesTbl.end(),
+ [id](
+ const std::shared_ptr<SensorAuxiliaryNames>& sensorAuxiliaryNames) {
+ const auto& [sensorId, sensorCnt, sensorNames] = *sensorAuxiliaryNames;
+ return sensorId == id;
+ });
+
+ if (it != sensorAuxiliaryNamesTbl.end())
+ {
+ return *it;
+ }
+ return nullptr;
+};
+
+std::shared_ptr<SensorAuxiliaryNames>
+ Terminus::parseSensorAuxiliaryNamesPDR(const std::vector<uint8_t>& pdrData)
+{
+ constexpr uint8_t nullTerminator = 0;
+ 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{};
+ 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{};
+ for ([[maybe_unused]] const auto& count :
+ std::views::iota(0, static_cast<int>(nameStringCount)))
+ {
+ std::string_view nameLanguageTag(
+ reinterpret_cast<const char*>(ptr));
+ ptr += nameLanguageTag.size() + sizeof(nullTerminator);
+
+ int u16NameStringLen = 0;
+ for (int i = 0; ptr[i] != 0 || ptr[i + 1] != 0; i += 2)
+ {
+ u16NameStringLen++;
+ }
+ /* include terminator */
+ u16NameStringLen++;
+
+ std::fill(std::begin(alignedBuffer), std::end(alignedBuffer), 0);
+ if (u16NameStringLen > PLDM_STR_UTF_16_MAX_LEN)
+ {
+ lg2::error("Sensor name to long.");
+ return nullptr;
+ }
+ memcpy(alignedBuffer, ptr, u16NameStringLen * sizeof(uint16_t));
+ std::u16string u16NameString(alignedBuffer, u16NameStringLen);
+ ptr += (u16NameString.size() + sizeof(nullTerminator)) *
+ sizeof(uint16_t);
+ 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);
+ 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));
+ }
+ sensorAuxNames.emplace_back(std::move(nameStrings));
+ }
+ return std::make_shared<SensorAuxiliaryNames>(
+ pdr->sensor_id, pdr->sensor_count, std::move(sensorAuxNames));
+}
+
+std::shared_ptr<pldm_numeric_sensor_value_pdr>
+ Terminus::parseNumericSensorPDR(const std::vector<uint8_t>& pdr)
+{
+ const uint8_t* ptr = pdr.data();
+ auto parsedPdr = std::make_shared<pldm_numeric_sensor_value_pdr>();
+ auto rc = decode_numeric_sensor_pdr_data(ptr, pdr.size(), parsedPdr.get());
+ if (rc)
+ {
+ return nullptr;
+ }
+ return parsedPdr;
+}
+
+std::shared_ptr<SensorAuxiliaryNames>
+ Terminus::parseCompactNumericSensorNames(const std::vector<uint8_t>& sPdr)
+{
+ std::vector<std::vector<std::pair<NameLanguageTag, SensorName>>>
+ sensorAuxNames{};
+ std::vector<std::pair<NameLanguageTag, SensorName>> nameStrings{};
+ auto pdr =
+ reinterpret_cast<const pldm_compact_numeric_sensor_pdr*>(sPdr.data());
+
+ if (sPdr.size() <
+ (sizeof(pldm_compact_numeric_sensor_pdr) - sizeof(uint8_t)))
+ {
+ return nullptr;
+ }
+
+ if (!pdr->sensor_name_length ||
+ (sPdr.size() < (sizeof(pldm_compact_numeric_sensor_pdr) -
+ sizeof(uint8_t) + pdr->sensor_name_length)))
+ {
+ return nullptr;
+ }
+
+ 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));
+ sensorAuxNames.emplace_back(std::move(nameStrings));
+
+ return std::make_shared<SensorAuxiliaryNames>(pdr->sensor_id, 1,
+ std::move(sensorAuxNames));
+}
+
+std::shared_ptr<pldm_compact_numeric_sensor_pdr>
+ Terminus::parseCompactNumericSensorPDR(const std::vector<uint8_t>& sPdr)
+{
+ auto pdr =
+ reinterpret_cast<const pldm_compact_numeric_sensor_pdr*>(sPdr.data());
+ if (sPdr.size() < sizeof(pldm_compact_numeric_sensor_pdr))
+ {
+ // Handle error: input data too small to contain valid pdr
+ return nullptr;
+ }
+ auto parsedPdr = std::make_shared<pldm_compact_numeric_sensor_pdr>();
+
+ parsedPdr->hdr = pdr->hdr;
+ parsedPdr->terminus_handle = pdr->terminus_handle;
+ parsedPdr->sensor_id = pdr->sensor_id;
+ parsedPdr->entity_type = pdr->entity_type;
+ parsedPdr->entity_instance = pdr->entity_instance;
+ parsedPdr->container_id = pdr->container_id;
+ parsedPdr->sensor_name_length = pdr->sensor_name_length;
+ parsedPdr->base_unit = pdr->base_unit;
+ parsedPdr->unit_modifier = pdr->unit_modifier;
+ parsedPdr->occurrence_rate = pdr->occurrence_rate;
+ parsedPdr->range_field_support = pdr->range_field_support;
+ parsedPdr->warning_high = pdr->warning_high;
+ parsedPdr->warning_low = pdr->warning_low;
+ parsedPdr->critical_high = pdr->critical_high;
+ parsedPdr->critical_low = pdr->critical_low;
+ parsedPdr->fatal_high = pdr->fatal_high;
+ parsedPdr->fatal_low = pdr->fatal_low;
+ return parsedPdr;
+}
+
} // namespace platform_mc
} // namespace pldm