sensor-cache: Implement reading data
Implement reading data in property changed callback.
With sensor-cache, the sensor's property is returned by the
callback of propertiesChanged match, parse the property from the message
and generate the sensor's response.
Tested: Verify the sensors using `readingData` have valid values in
QEMU, e.g.
Inlet_Temp | 20.000 | degrees C | ok | na | 0.000 | 5.000 | 38.000 | 43.000 | na
Signed-off-by: Lei YU <yulei.sh@bytedance.com>
Change-Id: I2c6328cb6001d0daf2045d17e73773dccf55d521
diff --git a/include/ipmid/types.hpp b/include/ipmid/types.hpp
index 3332f81..97d11a7 100644
--- a/include/ipmid/types.hpp
+++ b/include/ipmid/types.hpp
@@ -232,6 +232,23 @@
using EntityInfoMap = std::map<Id, EntityInfo>;
+#ifdef FEATURE_SENSORS_CACHE
+/**
+ * @struct SensorData
+ *
+ * The data to cache for sensors
+ */
+struct SensorData
+{
+ double value;
+ bool available;
+ bool functional;
+ GetSensorResponse response;
+};
+
+using SensorCacheMap = std::map<uint8_t, std::optional<SensorData>>;
+#endif
+
} // namespace sensor
namespace network
diff --git a/sensordatahandler.hpp b/sensordatahandler.hpp
index 91654af..2704146 100644
--- a/sensordatahandler.hpp
+++ b/sensordatahandler.hpp
@@ -12,6 +12,10 @@
#include <phosphor-logging/log.hpp>
#include <sdbusplus/message/types.hpp>
+#ifdef FEATURE_SENSORS_CACHE
+extern ipmi::sensor::SensorCacheMap sensorCacheMap;
+#endif
+
namespace ipmi
{
namespace sensor
@@ -334,10 +338,6 @@
#else
-using SensorCacheMap =
- std::map<uint8_t, std::optional<ipmi::sensor::GetSensorResponse>>;
-extern SensorCacheMap sensorCacheMap;
-
/**
* @brief Map the Dbus info to sensor's assertion status in the Get sensor
* reading command response.
@@ -397,8 +397,102 @@
std::optional<GetSensorResponse> readingData(uint8_t id, const Info& sensorInfo,
sdbusplus::message::message& msg)
{
- // TODO
- return {};
+ std::string interfaceName;
+ std::map<std::string, ipmi::Value> properties;
+ msg.read(interfaceName);
+
+ if (interfaceName ==
+ "xyz.openbmc_project.State.Decorator.OperationalStatus")
+ {
+ msg.read(properties);
+ auto val = properties.find("Functional");
+ if (val != properties.end())
+ {
+ sensorCacheMap[id]->functional = std::get<bool>(val->second);
+ }
+ return {};
+ }
+ if (interfaceName == "xyz.openbmc_project.State.Decorator.Availability")
+ {
+ msg.read(properties);
+ auto val = properties.find("Available");
+ if (val != properties.end())
+ {
+ sensorCacheMap[id]->available = std::get<bool>(val->second);
+ }
+ return {};
+ }
+
+ if (interfaceName != sensorInfo.sensorInterface)
+ {
+ // Not the interface we need
+ return {};
+ }
+
+#ifdef UPDATE_FUNCTIONAL_ON_FAIL
+ if (sensorCacheMap[id])
+ {
+ if (!sensorCacheMap[id]->functional)
+ {
+ throw SensorFunctionalError();
+ }
+ }
+#endif
+
+ GetSensorResponse response{};
+
+ enableScanning(&response);
+
+ msg.read(properties);
+
+ auto iter = properties.find(
+ sensorInfo.propertyInterfaces.begin()->second.begin()->first);
+ if (iter == properties.end())
+ {
+ return {};
+ }
+
+ double value = std::get<T>(iter->second) *
+ std::pow(10, sensorInfo.scale - sensorInfo.exponentR);
+ int32_t rawData =
+ (value - sensorInfo.scaledOffset) / sensorInfo.coefficientM;
+
+ constexpr uint8_t sensorUnitsSignedBits = 2 << 6;
+ constexpr uint8_t signedDataFormat = 0x80;
+ // if sensorUnits1 [7:6] = 10b, sensor is signed
+ if ((sensorInfo.sensorUnits1 & sensorUnitsSignedBits) == signedDataFormat)
+ {
+ if (rawData > std::numeric_limits<int8_t>::max() ||
+ rawData < std::numeric_limits<int8_t>::lowest())
+ {
+ log<level::ERR>("Value out of range");
+ throw std::out_of_range("Value out of range");
+ }
+ setReading(static_cast<int8_t>(rawData), &response);
+ }
+ else
+ {
+ if (rawData > std::numeric_limits<uint8_t>::max() ||
+ rawData < std::numeric_limits<uint8_t>::lowest())
+ {
+ log<level::ERR>("Value out of range");
+ throw std::out_of_range("Value out of range");
+ }
+ setReading(static_cast<uint8_t>(rawData), &response);
+ }
+
+ if (!std::isfinite(value))
+ {
+ response.readingOrStateUnavailable = 1;
+ }
+
+ if (!sensorCacheMap[id].has_value())
+ {
+ sensorCacheMap[id] = SensorData{};
+ }
+ sensorCacheMap[id]->response = response;
+
+ return response;
}
#endif // FEATURE_SENSORS_CACHE
diff --git a/sensorhandler.cpp b/sensorhandler.cpp
index 34565a1..7e0c7dc 100644
--- a/sensorhandler.cpp
+++ b/sensorhandler.cpp
@@ -92,9 +92,7 @@
std::map<uint8_t, std::unique_ptr<sdbusplus::bus::match::match>>
sensorUpdatedMatches __attribute__((init_priority(101)));
-using SensorCacheMap =
- std::map<uint8_t, std::optional<ipmi::sensor::GetSensorResponse>>;
-SensorCacheMap sensorCacheMap __attribute__((init_priority(101)));
+ipmi::sensor::SensorCacheMap sensorCacheMap __attribute__((init_priority(101)));
void initSensorMatches()
{
@@ -110,15 +108,21 @@
// TODO
}));
sensorUpdatedMatches.emplace(
- s.first,
- std::make_unique<sdbusplus::bus::match::match>(
- bus,
- type::signal() + path(s.second.sensorPath) +
- member("PropertiesChanged"s) +
- interface("org.freedesktop.DBus.Properties"s),
- [id = s.first, obj = s.second.sensorPath](auto& /*msg*/) {
- // TODO
- }));
+ s.first, std::make_unique<sdbusplus::bus::match::match>(
+ bus,
+ type::signal() + path(s.second.sensorPath) +
+ member("PropertiesChanged"s) +
+ interface("org.freedesktop.DBus.Properties"s),
+ [&s](auto& msg) {
+ try
+ {
+ s.second.getFunc(s.first, s.second, msg);
+ }
+ catch (const std::exception& e)
+ {
+ sensorCacheMap[s.first].reset();
+ }
+ }));
}
}
#endif
@@ -489,7 +493,30 @@
{
#ifdef FEATURE_SENSORS_CACHE
// TODO
- return ipmi::responseSuccess();
+ const auto& sensorData = sensorCacheMap[sensorNum];
+ if (!sensorData.has_value())
+ {
+ // Intitilizing with default values
+ constexpr uint8_t senReading = 0;
+ constexpr uint5_t reserved{0};
+ constexpr bool readState = true;
+ constexpr bool senScanState = false;
+ constexpr bool allEventMessageState = false;
+ constexpr uint8_t assertionStatesLsb = 0;
+ constexpr uint8_t assertionStatesMsb = 0;
+
+ return ipmi::responseSuccess(
+ senReading, reserved, readState, senScanState,
+ allEventMessageState, assertionStatesLsb, assertionStatesMsb);
+ }
+ return ipmi::responseSuccess(
+ sensorData->response.reading, uint5_t(0),
+ sensorData->response.readingOrStateUnavailable,
+ sensorData->response.scanningEnabled,
+ sensorData->response.allEventMessagesEnabled,
+ sensorData->response.thresholdLevelsStates,
+ sensorData->response.discreteReadingSensorStates);
+
#else
ipmi::sensor::GetSensorResponse getResponse =
iter->second.getFunc(iter->second);