Files
OpenBMC/meta-luxshare/recipes-phosphor/logging/phosphor-logging/0001-parse-message-when-sel-is-created.patch
T
2026-04-23 17:07:55 +08:00

1090 lines
34 KiB
Diff
Executable File

From bbc1ef63af759ef39c4f430f1040fe8ef8201d1c Mon Sep 17 00:00:00 2001
From: roly <Rolyli.Li@luxshare-ict.com>
Date: Thu, 12 Dec 2024 13:35:12 +0800
Subject: [PATCH] parse message when sel is created
---
elog_entry.hpp | 3 +
log_manager.cpp | 128 ++++++++++++-
log_manager.hpp | 15 ++
meson.build | 10 +
sel_message.cpp | 481 ++++++++++++++++++++++++++++++++++++++++++++++++
sel_message.hpp | 166 +++++++++++++++++
sensors.cpp | 119 ++++++++++++
sensors.hpp | 44 +++++
8 files changed, 964 insertions(+), 2 deletions(-)
create mode 100644 sel_message.cpp
create mode 100644 sel_message.hpp
create mode 100644 sensors.cpp
create mode 100644 sensors.hpp
diff --git a/elog_entry.hpp b/elog_entry.hpp
index 87cc7ea..822fb1a 100644
--- a/elog_entry.hpp
+++ b/elog_entry.hpp
@@ -148,6 +148,9 @@ class Entry : public EntryIfaces
*/
sdbusplus::message::unix_fd getEntry() override;
+ /** @brief The original sensor name */
+ std::string originalSensorName;
+
private:
/** @brief This entry's associations */
AssociationList assocs = {};
diff --git a/log_manager.cpp b/log_manager.cpp
index d3a50cd..2bfab30 100644
--- a/log_manager.cpp
+++ b/log_manager.cpp
@@ -232,12 +232,24 @@ void Manager::createEntry(std::string errMsg, Entry::Level errLvl,
AssociationList objects{};
processMetadata(errMsg, additionalData, objects);
+ std::string originalSensorName;
+ auto result = processSel(additionalData, errLvl, originalSensorName);
+
+ std::get<2>(result) ? additionalData.emplace_back("ASSERT_ALARM=1")
+ : additionalData.emplace_back("ASSERT_ALARM=0");
+
+ additionalData.emplace_back(
+ "SEVERITY_CONF=" +
+ std::to_string(static_cast<uint8_t>(std::get<3>(result))));
auto e = std::make_unique<Entry>(
busLog, objPath, entryId,
ms, // Milliseconds since 1970
- errLvl, std::move(errMsg), std::move(additionalData),
- std::move(objects), fwVersion, getEntrySerializePath(entryId), *this);
+ std::get<1>(result), std::move(std::get<0>(result)),
+ std::move(additionalData), std::move(objects), fwVersion,
+ getEntrySerializePath(entryId), *this);
+
+ e->originalSensorName = originalSensorName;
serialize(*e);
@@ -641,6 +653,118 @@ void Manager::createWithFFDC(
createEntry(message, severity, ad, ffdc);
}
+std::tuple<std::string, Entry::Level, bool, sel::message::AlarmType>
+ Manager::processSel(const std::vector<std::string>& additionalData,
+ Entry::Level defaultLevel,
+ std::string& originalSensorName)
+{
+ std::string_view eventDir;
+ std::string_view sensorData;
+ std::string sensorPath;
+ std::string_view recordTypeStr;
+ std::string msg;
+ std::string generatorId;
+ std::string sensorName;
+
+ if (additionalData.empty())
+ {
+ return std::make_tuple(msg, defaultLevel, true,
+ sel::message::AlarmType::NORMAL);
+ }
+
+ for (std::string_view ite : additionalData)
+ {
+ auto pos = ite.find_first_of('=');
+ if (pos == std::string::npos)
+ {
+ continue;
+ }
+
+ auto tempData = ite.substr(0, pos);
+ if (tempData == "EVENT_DIR")
+ {
+ eventDir = ite.substr(pos + 1);
+ }
+ else if (tempData == "SENSOR_DATA")
+ {
+ sensorData = ite.substr(pos + 1);
+ }
+ else if (tempData == "SENSOR_PATH")
+ {
+ sensorPath = ite.substr(pos + 1);
+ }
+ else if (tempData == "RECORD_TYPE")
+ {
+ recordTypeStr = ite.substr(pos + 1);
+ }
+ else if (tempData == "GENERATOR_ID")
+ {
+ generatorId = ite.substr(pos + 1);
+ }
+ }
+
+ uint8_t recordType = 0;
+ if (!recordTypeStr.empty())
+ {
+ std::from_chars(recordTypeStr.begin(), recordTypeStr.end(), recordType);
+ }
+
+ sel::message::AlarmType alarm = sel::message::AlarmType::NORMAL;
+ sel::message::AlarmType confAlarm = sel::message::AlarmType::NORMAL;
+
+ bool assert = true;
+ if (recordType >= 0xc0)
+ {
+ // TODO parse oem sel
+ }
+ else
+ {
+ auto sensorInfo = sensors::SensorManager::getSensorInfo(sensorPath);
+ if (sensorInfo == std::nullopt)
+ {
+ msg = "reserved #0xff | | ";
+ msg += assert ? "Asserted" : "Deasserted";
+ return std::make_tuple(msg, defaultLevel, true,
+ sel::message::AlarmType::NORMAL);
+ }
+ auto sensorReadingType = sensorInfo->readingType;
+ auto sensorType = sensorInfo->sensorType;
+ sensorName = sensorInfo->sensorName;
+ originalSensorName = sensorName;
+ uint8_t value = 0;
+ std::from_chars(eventDir.begin(), eventDir.end(), value, 10);
+ assert = (value == 0) ? false : true;
+
+ msg = sel::message::getSystemSelMessage(sensorPath, sensorType,
+ sensorReadingType, sensorData,
+ sensorName, assert);
+ auto alarmValue = sel::message::getSystemSelAlarm(
+ sensorPath, sensorType, sensorReadingType, sensorData, assert);
+ alarm = alarmValue.first;
+ confAlarm = alarmValue.second;
+ }
+
+ bool assertAlarm = assert;
+ Entry::Level severity = defaultLevel;
+ switch (alarm)
+ {
+ case sel::message::AlarmType::NONCRITICAL:
+ severity = Entry::Level::Warning;
+ break;
+ case sel::message::AlarmType::CRITICAL:
+ severity = Entry::Level::Error;
+ break;
+ case sel::message::AlarmType::NONRECOV:
+ severity = Entry::Level::Alert;
+ break;
+ default:
+ assertAlarm = !assert;
+ break;
+ }
+
+ return std::make_tuple(msg, severity, assertAlarm, confAlarm);
+}
+
} // namespace internal
} // namespace logging
} // namespace phosphor
diff --git a/log_manager.hpp b/log_manager.hpp
index 275530e..0b9056f 100644
--- a/log_manager.hpp
+++ b/log_manager.hpp
@@ -2,6 +2,8 @@
#include "elog_block.hpp"
#include "elog_entry.hpp"
+#include "sel_message.hpp"
+#include "sensors.hpp"
#include "xyz/openbmc_project/Collection/DeleteAll/server.hpp"
#include "xyz/openbmc_project/Logging/Create/server.hpp"
#include "xyz/openbmc_project/Logging/Entry/server.hpp"
@@ -307,6 +309,19 @@ class Manager : public details::ServerObject<details::ManagerIface>
*/
void checkAndQuiesceHost();
+ /** @brief Parse sel.
+ * @param[in] additionalData - list of metadata (in key=value format)
+ * @param[in] defaultLevel - default severity
+ *
+ * @return std::string - the message string
+ * Entry::Level - the alarm level
+ * bool - true: assert alarm, false: deassert alarm
+ * sel::message::AlarmType - the alarm level in config
+ */
+ std::tuple<std::string, Entry::Level, bool, sel::message::AlarmType>
+ processSel(const std::vector<std::string>& additionalData,
+ Entry::Level defaultLevel, std::string& originalSensorName);
+
/** @brief Persistent sdbusplus DBus bus connection. */
sdbusplus::bus_t& busLog;
diff --git a/meson.build b/meson.build
index 2add463..4f3f8d0 100644
--- a/meson.build
+++ b/meson.build
@@ -60,6 +60,12 @@ if not has_cereal
cereal_dep = cereal_proj.dependency('cereal')
endif
+if cpp.has_header('nlohmann/json.hpp')
+ nlohmann_json_dep = declare_dependency()
+else
+ nlohmann_json_dep = dependency('nlohmann-json')
+endif
+ipmitool_dep = cpp.find_library('ipmitool')
# Generate sdbus++ files.
generated_sources = []
generated_others = []
@@ -128,6 +134,8 @@ log_manager_sources = [
'elog_serialize.cpp',
'extensions.cpp',
'log_manager.cpp',
+ 'sel_message.cpp',
+ 'sensors.cpp',
'util.cpp',
)
]
@@ -138,6 +146,8 @@ log_manager_deps = [
phosphor_logging_dep,
sdbusplus_dep,
sdeventplus_dep,
+ nlohmann_json_dep,
+ ipmitool_dep,
]
executable('phosphor-log-manager',
log_manager_sources,
diff --git a/sel_message.cpp b/sel_message.cpp
new file mode 100644
index 0000000..8952cec
--- /dev/null
+++ b/sel_message.cpp
@@ -0,0 +1,481 @@
+extern "C"
+{
+#include <ipmitool/ipmi_sel_desc.h>
+}
+#include "sel_message.hpp"
+#include "sensors.hpp"
+
+#include <algorithm>
+#include <cmath>
+#include <format>
+#include <iostream>
+#include <regex>
+#include <sstream>
+#include <unordered_map>
+
+namespace sel
+{
+namespace message
+{
+
+enum class SensorUnits : uint8_t
+{
+ unspecified = 0x0,
+ degreesC = 0x1,
+ volts = 0x4,
+ amps = 0x5,
+ watts = 0x6,
+ rpm = 0x12,
+};
+
+const static std::map<std::string, SensorUnits> sensorUnits = {
+ {"temperature", SensorUnits::degreesC},
+ {"voltage", SensorUnits::volts},
+ {"current", SensorUnits::amps},
+ {"fan_tach", SensorUnits::rpm},
+ {"power", SensorUnits::watts}};
+
+inline uint8_t bit(uint8_t bit)
+{
+ return 1 << bit;
+}
+
+inline std::string getSensorTypeDesc(uint8_t sensorType)
+{
+ if (sensorType <= SENSOR_TYPE_MAX)
+ {
+ return sensor_type_desc[sensorType];
+ }
+ return "";
+}
+
+inline std::optional<std::pair<uint8_t, std::string>>
+ getEventDataTypeDesc(uint8_t eventData, struct ipmi_event_data_types* evt)
+{
+ struct ipmi_event_data_types* event = nullptr;
+ if (evt == nullptr)
+ {
+ return std::nullopt;
+ }
+ event = evt;
+ size_t num_types = 0;
+
+ switch (event->flag)
+ {
+ case HDD_NVME_STATUS_EVT2:
+ {
+ return std::nullopt;
+ }
+ case EXPANDER_ERR_EVT2:
+ {
+ return std::nullopt;
+ }
+ case EXPANDER_ERR_EVT3:
+ {
+ return std::nullopt;
+ }
+ case RETIMER_ERR_EVT2:
+ {
+ return std::make_pair(event->data,
+ ", Retimer " + std::to_string(eventData));
+ }
+ case POWER_FAULT_EVT2:
+ {
+ return std::nullopt;
+ }
+ case BMC_BOOT_EVT2:
+ {
+ num_types = sizeof(BMC_BOOT_evt2) /
+ sizeof(struct ipmi_event_data_types);
+ break;
+ }
+ case BMC_BOOT_EVT3:
+ {
+ num_types = sizeof(BMC_BOOT_evt3) /
+ sizeof(struct ipmi_event_data_types);
+ break;
+ }
+ case LEAKAGE_EVT2:
+ {
+ num_types = sizeof(Leakage_evt2) /
+ sizeof(struct ipmi_event_data_types);
+ break;
+ }
+ case FW_UPDATE_EVT2:
+ {
+ num_types = sizeof(FW_Update_evt2) /
+ sizeof(struct ipmi_event_data_types);
+ break;
+ }
+ case FW_UPDATE_EVT3:
+ {
+ num_types = sizeof(FW_Update_evt3) /
+ sizeof(struct ipmi_event_data_types);
+ break;
+ }
+ default:
+ break;
+ }
+
+ for (size_t i = 0; i < num_types; i++)
+ {
+ if (event->data == eventData)
+ {
+ return std::make_pair(event->data, evt[i].desc);
+ }
+ event++;
+ }
+ return std::nullopt;
+}
+
+inline std::string getEventDesc(SensorRecord rec)
+{
+ uint8_t code = 0xFF;
+ std::optional<std::pair<uint8_t, std::string>> evtOpt2;
+ std::optional<std::pair<uint8_t, std::string>> evtOpt3;
+
+ auto getEventTypes = [rec, &code]() {
+ if (rec.eventType == 0x6F)
+ {
+ code = rec.sensorType;
+ return sensor_specific_event_types;
+ }
+ else if (rec.eventType == 0x03 && rec.sensorType == 0x15)
+ {
+ code = rec.eventType;
+ return sensor_retimer_event_types;
+ }
+ else
+ {
+ code = rec.eventType;
+ return generic_event_types;
+ }
+ };
+
+ for (auto ite = getEventTypes(); ite->desc != nullptr; ite++)
+ {
+ if (ite->code != code || ite->offset != (rec.eventData1 & 0x0F))
+ {
+ continue;
+ }
+
+ if (ite->evt2)
+ {
+ evtOpt2 = getEventDataTypeDesc(rec.eventData2, ite->evt2);
+ }
+ if ((evtOpt2 != std::nullopt) && ite->evt3)
+ {
+ evtOpt3 = getEventDataTypeDesc(rec.eventData3, ite->evt3);
+ }
+
+ auto data = (evtOpt2 != std::nullopt) ? evtOpt2->first : ite->data;
+ if ((ite->data == ALL_OFFSETS_SPECIFIED) ||
+ ((rec.eventData1 & 0xC0) && (data == rec.eventData2)))
+ {
+ std::string msg =
+ std::string(ite->desc) +
+ (evtOpt2 != std::nullopt ? (evtOpt2->second) : "") +
+ (evtOpt3 != std::nullopt ? (evtOpt3->second) : "");
+ if (rec.eventType == 0x6F && rec.sensorType == 0x13)
+ {
+ msg += std::format(", BDF: {0:02x}.{1:02x}.{2:02x}",
+ rec.eventData2, rec.eventData3 >> 3,
+ rec.eventData3 & 0x07);
+ }
+
+ else if (rec.eventType == 0x03 && rec.sensorType == 0x09)
+ {
+ if (rec.eventData2 == 0xFF)
+ {
+ msg += ", ErrorType: Power-on timeout";
+ }
+ else if (rec.eventData2 >= SIZE_OF_POWER_FAULT)
+ {
+ msg += ", ErrorType: Unknown";
+ }
+ else
+ {
+ msg +=
+ ", ErrorType: " +
+ std::string(sensor_power_fault[rec.eventData2 & 0x0F]);
+ }
+ }
+
+ else if (rec.eventType == 0x6F && code == 0x0D)
+ {
+ msg += std::format(", Drive Slot({:02d})", rec.eventData2);
+ }
+ else if (rec.eventType == 0x07 &&
+ (rec.sensorType == 0x04 || rec.sensorType == 0x21))
+ {
+ msg = ite->desc;
+ }
+ else if (rec.eventType == 0x6F && code == 0x1B)
+ {
+ msg += std::format(", PSU PDB Cable{:d}", rec.eventData2);
+ }
+ return msg;
+ }
+ }
+
+ return "";
+}
+
+inline std::vector<uint8_t> convertVec(std::string_view str)
+{
+ std::vector<uint8_t> ret;
+ auto len = str.size() / 2;
+ ret.reserve(len);
+ for (size_t i = 0; i < len; ++i)
+ {
+ uint8_t value;
+ std::from_chars(str.begin() + i * 2, str.begin() + (i + 1) * 2, value,
+ 16);
+ ret.emplace_back(value);
+ }
+ return ret;
+}
+
+inline std::string getBacdEvents(const std::vector<uint8_t>& event)
+{
+ std::string msg;
+ for (const auto& item : sensor_oem_bacd_types)
+ {
+ if (item.flag == 3 && (event[item.flag] & bit(item.code)))
+ {
+ msg += ", " + std::string(item.desc);
+ }
+ else if (item.flag == 2 && event[item.flag] == item.code)
+ {
+ msg += ", " + std::string(item.desc);
+ }
+ }
+
+ return msg;
+}
+
+inline std::string getPprEvents(const std::vector<uint8_t>& event)
+{
+ std::string msg;
+ msg += ", CPU" + std::to_string(event[2]) + " Channel" +
+ std::to_string(event[3]) + " Dimm" + std::to_string(event[4]);
+
+ for (const auto& item : sensor_oem_ppr_types)
+ {
+ if (event[item.flag] == item.code && item.desc != nullptr)
+ {
+ msg += " " + std::string(item.desc);
+ }
+ }
+
+ return msg;
+}
+
+inline std::pair<AlarmType, AlarmType>
+ parseThresholdSelSeverity(uint8_t eventData1, bool assert)
+{
+ auto ite = thresholdAlarmTypes.find(eventData1);
+ if (ite != thresholdAlarmTypes.end())
+ {
+ return std::make_pair(
+ assert ? ite->second.assertAlarm : ite->second.deassertAlarm,
+ ite->second.assertAlarm > ite->second.deassertAlarm
+ ? ite->second.assertAlarm
+ : ite->second.deassertAlarm);
+ }
+ return std::make_pair(AlarmType::NORMAL, AlarmType::NORMAL);
+}
+
+inline std::pair<AlarmType, AlarmType> parseSpecificSensorSelSeverity(
+ [[maybe_unused]] const std::string& sensorPath, uint8_t sensorType,
+ uint8_t eventData1, uint8_t eventData2, bool assert)
+{
+ for (const auto& ite : specificAlarmTypes)
+ {
+ if (ite.sensorType == sensorType && ite.offset == eventData1)
+ {
+ if (ite.evt2.size() == 0 ||
+ (ite.evt2.size() > 0 &&
+ std::find(ite.evt2.begin(), ite.evt2.end(), eventData2) !=
+ ite.evt2.end()))
+ {
+ return std::make_pair(
+ assert ? ite.assertAlarm : ite.deassertAlarm,
+ ite.assertAlarm > ite.deassertAlarm ? ite.assertAlarm
+ : ite.deassertAlarm);
+ }
+ }
+ }
+ return std::make_pair(AlarmType::NORMAL, AlarmType::NORMAL);
+}
+
+inline std::pair<AlarmType, AlarmType>
+ parseDiscreteGenericSelSeverity(uint8_t sensorType, uint8_t eventType,
+ uint8_t eventData1, uint8_t eventData2,
+ bool assert)
+{
+ for (const auto& ite : discreteAlarmTypes)
+ {
+ if (ite.sensorType == sensorType && ite.eventType == eventType &&
+ ite.offset == eventData1)
+ {
+ if (ite.evt2.size() == 0 ||
+ (ite.evt2.size() > 0 &&
+ std::find(ite.evt2.begin(), ite.evt2.end(), eventData2) !=
+ ite.evt2.end()))
+ {
+ return std::make_pair(
+ assert ? ite.assertAlarm : ite.deassertAlarm,
+ ite.assertAlarm > ite.deassertAlarm ? ite.assertAlarm
+ : ite.deassertAlarm);
+ }
+ break;
+ }
+ }
+ return std::make_pair(AlarmType::NORMAL, AlarmType::NORMAL);
+}
+
+inline double scaleIPMIValueToDouble(const double value, const int16_t mValue,
+ const int8_t rExp, const int16_t bValue,
+ const int8_t bExp)
+{
+ double result =
+ (double)(((mValue * value) + (bValue * std::pow(10, bExp))) *
+ std::pow(10, rExp));
+ return result;
+}
+
+inline std::string getUnitDesc(const std::string& path)
+{
+ SensorUnits unitType = SensorUnits::unspecified;
+ size_t typeEnd = path.rfind("/");
+ if (typeEnd == std::string::npos)
+ {
+ return unit_desc[static_cast<uint8_t>(unitType)];
+ }
+ size_t typeStart = path.rfind("/", typeEnd - 1);
+ if (typeStart == std::string::npos)
+ {
+ return unit_desc[static_cast<uint8_t>(unitType)];
+ }
+ // Start at the character after the '/'
+ typeStart++;
+ std::string typeStr = path.substr(typeStart, typeEnd - typeStart);
+
+ auto it = sensorUnits.find(typeStr);
+ if (it != sensorUnits.end())
+ {
+ unitType = it->second;
+ }
+
+ if (static_cast<uint8_t>(unitType) <= UNIT_TYPE_MAX)
+ {
+ return unit_desc[static_cast<uint8_t>(unitType)];
+ }
+ else
+ {
+ return unit_desc[static_cast<uint8_t>(SensorUnits::unspecified)];
+ }
+}
+
+inline std::string getThresholdDesc(const std::string sensorPath,
+ SensorRecord rec)
+{
+ std::string msg;
+ msg = "Reading ";
+ auto scaleParam = sensors::SensorManager::getSensorScaleParam(sensorPath);
+ if (scaleParam.size() < 5)
+ {
+ // Not found or the sensor config is not expected
+ return "";
+ }
+
+ int16_t mValue = static_cast<int16_t>(scaleParam[2]);
+ int16_t bValue = static_cast<int16_t>(scaleParam[3]);
+ int8_t bExp = static_cast<int8_t>(scaleParam[4]);
+ int8_t rExp = static_cast<int8_t>(scaleParam[5]);
+ auto triggerReading = scaleIPMIValueToDouble(rec.eventData2, mValue, rExp,
+ bValue, bExp);
+ auto thresholdReading = scaleIPMIValueToDouble(rec.eventData3, mValue, rExp,
+ bValue, bExp);
+ msg += (triggerReading == (int)triggerReading)
+ ? std::format("{0:.0f} ", triggerReading)
+ : std::format("{0:.2f} ", triggerReading);
+ msg += (rec.eventData1 & 0xf) % 2 ? ">" : "<";
+ msg += " Threshold " + ((thresholdReading == (int)thresholdReading)
+ ? std::format("{0:.0f} ", thresholdReading)
+ : std::format("{0:.2f} ", thresholdReading));
+
+ msg += getUnitDesc(sensorPath);
+
+ return msg;
+}
+
+std::string getSystemSelMessage(const std::string& sensorPath,
+ uint8_t sensorType, uint8_t sensorReadingType,
+ std::string_view sensorData,
+ const std::string& sensorName, bool assert)
+{
+ std::string msg;
+ SensorRecord rec;
+ std::from_chars(sensorData.begin(), sensorData.begin() + 2, rec.eventData1,
+ 16);
+ std::from_chars(sensorData.begin() + 2, sensorData.begin() + 4,
+ rec.eventData2, 16);
+ std::from_chars(sensorData.begin() + 4, sensorData.begin() + 6,
+
+ rec.eventData3, 16);
+ rec.eventType = sensorReadingType;
+ rec.sensorType = sensorType;
+
+ auto sensorTypeDesc = getSensorTypeDesc(sensorType);
+ msg += sensorTypeDesc + " " + sensorName + " | ";
+
+ msg += getEventDesc(rec);
+ msg += " | ";
+ msg += assert ? "Asserted" : "Deasserted";
+
+ if (rec.eventType == 0x01)
+ {
+ auto thresholdDesc = getThresholdDesc(sensorPath, rec);
+ msg += " | " + thresholdDesc;
+ }
+
+ return msg;
+}
+
+std::pair<AlarmType, AlarmType> getSystemSelAlarm(const std::string& sensorPath,
+ uint8_t sensorType,
+ uint8_t eventType,
+ std::string_view sensorData,
+ bool assert)
+{
+ uint8_t eventData1;
+ uint8_t eventData2;
+ std::from_chars(sensorData.begin(), sensorData.begin() + 2, eventData1, 16);
+ std::from_chars(sensorData.begin() + 2, sensorData.begin() + 4, eventData2,
+ 16);
+ eventData1 &= 0x0F;
+
+ if (EventType(eventType) == EventType::THRESHOLD_SENSOR_TYPE)
+ {
+ return parseThresholdSelSeverity(eventData1, assert);
+ }
+ else if (EventType(eventType) == EventType::SPECIFIC_SENSOR_TYPE)
+ {
+ return parseSpecificSensorSelSeverity(sensorPath, sensorType,
+ eventData1, eventData2, assert);
+ }
+ else if (EventType(eventType) >= EventType::GENERIC_START_SENSOR_TYPE &&
+ EventType(eventType) <= EventType::GENERIC_END_SENSOR_TYPE)
+ {
+ return parseDiscreteGenericSelSeverity(sensorType, eventType,
+ eventData1, eventData2, assert);
+ }
+ else
+ {
+ return std::make_pair(AlarmType::NORMAL, AlarmType::NORMAL);
+ }
+}
+} // namespace message
+} // namespace sel
diff --git a/sel_message.hpp b/sel_message.hpp
new file mode 100644
index 0000000..167ee24
--- /dev/null
+++ b/sel_message.hpp
@@ -0,0 +1,166 @@
+#pragma once
+
+#include <array>
+#include <cstdint>
+#include <map>
+#include <string>
+#include <string_view>
+#include <vector>
+
+namespace sel
+{
+namespace message
+{
+
+struct SensorRecord
+{
+ uint8_t sensorType;
+ uint8_t eventType;
+ uint8_t eventData1;
+ uint8_t eventData2;
+ uint8_t eventData3;
+};
+
+std::string getSystemSelMessage(const std::string& sensorPath,
+ uint8_t sensorType, uint8_t sensorReadingType,
+ std::string_view sensorData,
+ const std::string& sensorName, bool assert);
+const std::vector<uint8_t> null_alarm = {};
+enum class AlarmType
+{
+ NORMAL = 0,
+ NONCRITICAL = 1,
+ CRITICAL = 2,
+ NONRECOV = 4,
+};
+enum class EventType
+{
+ UNSPECIFY_SENSOR_TYPE = 0x00,
+ THRESHOLD_SENSOR_TYPE = 0x01,
+ GENERIC_START_SENSOR_TYPE = 0x02,
+ GENERIC_END_SENSOR_TYPE = 0x0C,
+ SPECIFIC_SENSOR_TYPE = 0x6F,
+ OEM_START_SENSOR_TYPE = 0x70,
+ OEM_END_SENSOR_TYPE = 0x7F
+};
+struct threshold_alarm_types
+{
+ AlarmType assertAlarm = AlarmType::NORMAL;
+ AlarmType deassertAlarm = AlarmType::NORMAL;
+};
+struct discrete_alarm_types
+{
+ uint8_t sensorType;
+ uint8_t eventType;
+ uint8_t offset;
+ AlarmType assertAlarm = AlarmType::NORMAL;
+ AlarmType deassertAlarm = AlarmType::NORMAL;
+ const std::vector<uint8_t>& evt2 = null_alarm;
+};
+struct specific_alarm_types
+{
+ uint8_t sensorType;
+ uint8_t offset;
+ AlarmType assertAlarm = AlarmType::NORMAL;
+ AlarmType deassertAlarm = AlarmType::NORMAL;
+ const std::vector<uint8_t>& evt2 = null_alarm;
+};
+
+const std::map<uint8_t, threshold_alarm_types> thresholdAlarmTypes = {
+ {0x00, {AlarmType::NONCRITICAL}}, {0x02, {AlarmType::CRITICAL}},
+ {0x04, {AlarmType::NONRECOV}}, {0x07, {AlarmType::NONCRITICAL}},
+ {0x09, {AlarmType::CRITICAL}}, {0x0b, {AlarmType::NONRECOV}}};
+
+const std::vector<uint8_t> power_fault_alarm_evt2 = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
+
+constexpr std::array<discrete_alarm_types, 16> discreteAlarmTypes = {
+ {{0x04, 0x07, 0x00, AlarmType::NORMAL, AlarmType::CRITICAL},
+ {0x04, 0x07, 0x01, AlarmType::CRITICAL},
+ {0x04, 0x08, 0x00, AlarmType::CRITICAL},
+ {0x04, 0x08, 0x01, AlarmType::NORMAL, AlarmType::CRITICAL},
+ {0x08, 0x0B, 0x00, AlarmType::NORMAL, AlarmType::CRITICAL},
+ {0x08, 0x0B, 0x01, AlarmType::CRITICAL},
+ {0x09, 0x03, 0x00, AlarmType::NORMAL, AlarmType::CRITICAL,
+ power_fault_alarm_evt2},
+ {0x09, 0x03, 0x01, AlarmType::CRITICAL, AlarmType::NORMAL,
+ power_fault_alarm_evt2},
+ {0x15, 0x03, 0x00, AlarmType::NORMAL, AlarmType::NONCRITICAL},
+ {0x15, 0x03, 0x01, AlarmType::NONCRITICAL},
+ {0x19, 0x07, 0x00, AlarmType::NORMAL, AlarmType::CRITICAL},
+ {0x19, 0x07, 0x01, AlarmType::CRITICAL},
+ {0x21, 0x08, 0x00, AlarmType::CRITICAL},
+ {0x21, 0x08, 0x01, AlarmType::NORMAL, AlarmType::CRITICAL},
+ {0x24, 0x07, 0x00, AlarmType::NORMAL, AlarmType::CRITICAL},
+ {0x24, 0x07, 0x01, AlarmType::CRITICAL}}};
+
+const std::vector<uint8_t> system_firmware_critical_alarm_evt2 = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+ 0x07, 0x08, 0x09, 0x0B, 0x0C, 0x0D};
+
+const std::vector<uint8_t> system_firmware_noncritical_alarm_evt2 = {0x0A};
+
+const std::vector<uint8_t> hcurr_connector_alarm_evt2 = {0x00, 0x01};
+
+constexpr std::array<specific_alarm_types, 49> specificAlarmTypes = {{
+ {0x07, 0x00, AlarmType::CRITICAL},
+ {0x07, 0x01, AlarmType::NONCRITICAL},
+ {0x07, 0x03, AlarmType::CRITICAL},
+ {0x07, 0x05, AlarmType::NONCRITICAL},
+ {0x07, 0x07, AlarmType::NORMAL, AlarmType::CRITICAL},
+ {0x07, 0x08, AlarmType::CRITICAL},
+ {0x07, 0x0A, AlarmType::NONCRITICAL},
+ {0x07, 0x0B, AlarmType::CRITICAL},
+ {0x07, 0x0C, AlarmType::NONCRITICAL},
+ {0x08, 0x00, AlarmType::NORMAL, AlarmType::CRITICAL},
+ {0x08, 0x01, AlarmType::CRITICAL},
+ {0x08, 0x02, AlarmType::NONCRITICAL},
+ {0x08, 0x03, AlarmType::CRITICAL},
+ {0x08, 0x05, AlarmType::CRITICAL},
+ {0x08, 0x06, AlarmType::CRITICAL},
+ {0x0C, 0x00, AlarmType::NORMAL},
+ {0x0C, 0x01, AlarmType::CRITICAL},
+ {0x0C, 0x02, AlarmType::NONCRITICAL},
+ {0x0C, 0x03, AlarmType::NONCRITICAL},
+ {0x0C, 0x04, AlarmType::CRITICAL},
+ {0x0C, 0x05, AlarmType::NONCRITICAL},
+ {0x0C, 0x08, AlarmType::NONCRITICAL},
+ {0x0C, 0x0A, AlarmType::CRITICAL},
+ {0x0D, 0x00, AlarmType::NORMAL, AlarmType::CRITICAL},
+ {0x0D, 0x01, AlarmType::CRITICAL},
+ {0x0F, 0x00, AlarmType::CRITICAL, AlarmType::NORMAL,
+ system_firmware_critical_alarm_evt2},
+ {0x0F, 0x00, AlarmType::NONCRITICAL, AlarmType::NORMAL,
+ system_firmware_noncritical_alarm_evt2},
+ {0x10, 0x02},
+ {0x13, 0x04, AlarmType::CRITICAL},
+ {0x13, 0x05, AlarmType::CRITICAL},
+ {0x13, 0x07, AlarmType::NORMAL},
+ {0x13, 0x08, AlarmType::CRITICAL},
+ {0x13, 0x0A, AlarmType::CRITICAL},
+ {0x13, 0x0B, AlarmType::CRITICAL},
+ {0x14, 0x00},
+ {0x14, 0x01},
+ {0x14, 0x02},
+ {0x1B, 0x01, AlarmType::CRITICAL, AlarmType::NORMAL,
+ hcurr_connector_alarm_evt2},
+ {0x1D, 0x00},
+ {0x1D, 0x01},
+ {0x1D, 0x02},
+ {0x1E, 0x00, AlarmType::NORMAL},
+ {0x1E, 0x01},
+ {0x1E, 0x02},
+ {0x1E, 0x03},
+ {0x1F, 0x06},
+ {0x22, 0x00},
+ {0x22, 0x05},
+ {0x2B, 0x07, AlarmType::NORMAL, AlarmType::CRITICAL},
+}};
+
+std::pair<AlarmType, AlarmType> getSystemSelAlarm(const std::string& sensorPath,
+ uint8_t sensorType,
+ uint8_t eventType,
+ std::string_view sensorData,
+ bool assert);
+} // namespace message
+} // namespace sel
diff --git a/sensors.cpp b/sensors.cpp
new file mode 100644
index 0000000..01a559e
--- /dev/null
+++ b/sensors.cpp
@@ -0,0 +1,119 @@
+#include "sensors.hpp"
+
+#include <nlohmann/json.hpp>
+#include <phosphor-logging/lg2.hpp>
+#include <sdbusplus/bus.hpp>
+
+#include <filesystem>
+#include <fstream>
+#include <iostream>
+
+namespace sensors
+{
+
+static constexpr auto sensorJsonPath =
+ "/usr/share/ipmi-providers/sensor-data-record.json";
+
+SensorMessages loadSensorFromJson()
+{
+ try
+ {
+ const std::filesystem::path path(sensorJsonPath);
+ SensorMessages sensorMessages;
+ const nlohmann::json empty{};
+ nlohmann::json js;
+ if (!std::filesystem::exists(path) || std::filesystem::is_empty(path))
+ {
+ std::cout << "Incorrect File Path or empty file, FILE_PATH = "
+ << path << std::endl;
+ return sensorMessages;
+ }
+
+ try
+ {
+ std::ifstream jsonFile(path);
+ js = nlohmann::json::parse(jsonFile);
+ }
+ catch (const std::exception& e)
+ {
+ std::cout << "Failed to parse config file, ERROR = " << e.what()
+ << ", FILE_PATH = " << path << std::endl;
+ throw std::runtime_error("Failed to parse config file");
+ }
+
+ for (const auto& sensor : js.items())
+ {
+ SensorInfo info;
+ std::string sensorPath = sensor.key();
+ auto sensorParam = sensor.value();
+ info.sensorName = sensorParam["sensorName"];
+ info.readingType = sensorParam["sensorReadingType"];
+ info.sensorType = sensorParam["sensorType"];
+ sensorMessages.insert(std::make_pair(sensorPath, std::move(info)));
+ }
+ return sensorMessages;
+ }
+ catch (const std::exception& e)
+ {
+ throw std::runtime_error("Failed to parse sensor config file");
+ }
+}
+
+const SensorMessages& SensorManager::getSensorMessages()
+{
+ static const SensorMessages sensorMessages = loadSensorFromJson();
+ return sensorMessages;
+}
+
+std::optional<SensorInfo>
+ SensorManager::getSensorInfo(const std::string& sensorPath)
+{
+ const auto& sensorMessages = SensorManager::getSensorMessages();
+ auto ite = sensorMessages.find(sensorPath);
+ if (ite == sensorMessages.end())
+ {
+ return std::nullopt;
+ }
+ return std::make_optional(ite->second);
+}
+
+ScaleInfo SensorManager::getSensorScaleParam(const SensorPath& path)
+{
+ static std::optional<ipmiSensorsInfo> ipmiSensors = std::nullopt;
+ if (ipmiSensors == std::nullopt)
+ {
+ constexpr auto service = "xyz.openbmc_project.Ipmi.Host";
+ constexpr auto obj = "/xyz/openbmc_project/Ipmi/SensorInfo";
+ constexpr auto interface = "xyz.openbmc_project.IPMI.SensorInfo";
+ constexpr auto property = "SensorInfo";
+ using SensorInfoVariant = std::variant<ipmiSensorsInfo>;
+ SensorInfoVariant val;
+
+ auto bus = sdbusplus::bus::new_default();
+ auto method = bus.new_method_call(
+ service, obj, "org.freedesktop.DBus.Properties", "Get");
+ method.append(interface, property);
+ try
+ {
+ auto reply = bus.call(method);
+ reply.read(val);
+ }
+ catch (const sdbusplus::exception_t& e)
+ {
+ lg2::warning(
+ "Failed to get IPMI sensor info, error: {ERROR}, retry...",
+ "ERROR", e.what());
+ return ScaleInfo{};
+ }
+
+ ipmiSensors = std::get<ipmiSensorsInfo>(val);
+ }
+ auto it = ipmiSensors->find(path);
+ if (it == ipmiSensors->end())
+ {
+ return ScaleInfo{};
+ }
+ return it->second;
+}
+
+} // namespace sensors
diff --git a/sensors.hpp b/sensors.hpp
new file mode 100644
index 0000000..da9a9ff
--- /dev/null
+++ b/sensors.hpp
@@ -0,0 +1,44 @@
+#pragma once
+
+#include <cstdint>
+#include <optional>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+namespace sensors
+{
+using ScaleInfo = std::vector<int64_t>;
+using ipmiSensorsInfo = std::unordered_map<std::string, ScaleInfo>;
+using SensorPath = std::string;
+struct SensorInfo
+{
+ std::string sensorName;
+ uint8_t readingType;
+ uint8_t sensorType;
+};
+
+using SensorMessages = std::unordered_map<SensorPath, SensorInfo>;
+
+/**
+ * @class SensorManager
+ *
+ * Manage sensor message
+ */
+class SensorManager
+{
+ public:
+ SensorManager() = default;
+ ~SensorManager() = default;
+ SensorManager(const SensorManager&) = delete;
+ SensorManager& operator=(const SensorManager&) = delete;
+ SensorManager(SensorManager&&) = delete;
+ SensorManager& operator=(SensorManager&&) = delete;
+
+ static const SensorMessages& getSensorMessages();
+
+ static std::optional<SensorInfo> getSensorInfo(const SensorPath& path);
+
+ static ScaleInfo getSensorScaleParam(const SensorPath& path);
+};
+} // namespace sensors
--
2.25.1