platform-mc: Add sensor manager
Added sensor_manager class. The sensor_manager class manages the timing
of sensor polling.
tested: Verified on ast2600 EVB which is connected to a PLDM device
over I2C. bmcweb can display the state of numeric sensor.
Signed-off-by: Gilbert Chen <gilbert.chen@arm.com>
Signed-off-by: Thu Nguyen <thu@os.amperecomputing.com>
Change-Id: I4257f823ea26d7fdb322cc82d847e94db056258c
diff --git a/platform-mc/test/meson.build b/platform-mc/test/meson.build
index 6b95f90..64177cc 100644
--- a/platform-mc/test/meson.build
+++ b/platform-mc/test/meson.build
@@ -4,6 +4,7 @@
'../terminus.cpp',
'../platform_manager.cpp',
'../manager.cpp',
+ '../sensor_manager.cpp',
'../numeric_sensor.cpp',
'../../requester/mctp_endpoint_discovery.cpp'],
include_directories: ['../../requester', '../../pldmd'])
@@ -12,6 +13,8 @@
'terminus_manager_test',
'terminus_test',
'platform_manager_test',
+ 'sensor_manager_test',
+ 'numeric_sensor_test',
]
foreach t : tests
diff --git a/platform-mc/test/mock_sensor_manager.hpp b/platform-mc/test/mock_sensor_manager.hpp
new file mode 100644
index 0000000..a52e4ea
--- /dev/null
+++ b/platform-mc/test/mock_sensor_manager.hpp
@@ -0,0 +1,24 @@
+#pragma once
+
+#include "platform-mc/sensor_manager.hpp"
+
+#include <gmock/gmock.h>
+
+namespace pldm
+{
+namespace platform_mc
+{
+
+class MockSensorManager : public SensorManager
+{
+ public:
+ MockSensorManager(sdeventplus::Event& event,
+ TerminusManager& terminusManager,
+ TerminiMapper& termini) :
+ SensorManager(event, terminusManager, termini) {};
+
+ MOCK_METHOD(void, doSensorPolling, (pldm_tid_t tid), (override));
+};
+
+} // namespace platform_mc
+} // namespace pldm
diff --git a/platform-mc/test/numeric_sensor_test.cpp b/platform-mc/test/numeric_sensor_test.cpp
new file mode 100644
index 0000000..8b59401
--- /dev/null
+++ b/platform-mc/test/numeric_sensor_test.cpp
@@ -0,0 +1,272 @@
+
+#include "libpldm/entity.h"
+#include "libpldm/platform.h"
+
+#include "platform-mc/numeric_sensor.hpp"
+#include "platform-mc/terminus.hpp"
+
+#include <gtest/gtest.h>
+
+TEST(NumericSensor, conversionFormula)
+{
+ std::vector<uint8_t> pdr1{
+ 0x1,
+ 0x0,
+ 0x0,
+ 0x0, // record handle
+ 0x1, // PDRHeaderVersion
+ PLDM_NUMERIC_SENSOR_PDR, // PDRType
+ 0x0,
+ 0x0, // recordChangeNumber
+ PLDM_PDR_NUMERIC_SENSOR_PDR_FIXED_LENGTH +
+ PLDM_PDR_NUMERIC_SENSOR_PDR_VARIED_SENSOR_DATA_SIZE_MIN_LENGTH +
+ PLDM_PDR_NUMERIC_SENSOR_PDR_VARIED_RANGE_FIELD_MIN_LENGTH,
+ 0, // dataLength
+ 0,
+ 0, // PLDMTerminusHandle
+ 0x1,
+ 0x0, // sensorID=1
+ PLDM_ENTITY_POWER_SUPPLY,
+ 0, // entityType=Power Supply(120)
+ 1,
+ 0, // entityInstanceNumber
+ 0x1,
+ 0x0, // containerID=1
+ PLDM_NO_INIT, // sensorInit
+ false, // sensorAuxiliaryNamesPDR
+ PLDM_SENSOR_UNIT_DEGRESS_C, // baseUint(2)=degrees C
+ 1, // unitModifier = 1
+ 0, // rateUnit
+ 0, // baseOEMUnitHandle
+ 0, // auxUnit
+ 0, // auxUnitModifier
+ 0, // auxRateUnit
+ 0, // rel
+ 0, // auxOEMUnitHandle
+ true, // isLinear
+ PLDM_RANGE_FIELD_FORMAT_SINT8, // sensorDataSize
+ 0,
+ 0,
+ 0xc0,
+ 0x3f, // resolution=1.5
+ 0,
+ 0,
+ 0x80,
+ 0x3f, // offset=1.0
+ 0,
+ 0, // accuracy
+ 0, // plusTolerance
+ 0, // minusTolerance
+ 2, // hysteresis
+ 0, // supportedThresholds
+ 0, // thresholdAndHysteresisVolatility
+ 0,
+ 0,
+ 0x80,
+ 0x3f, // stateTransistionInterval=1.0
+ 0,
+ 0,
+ 0x80,
+ 0x3f, // updateInverval=1.0
+ 255, // maxReadable
+ 0, // minReadable
+ PLDM_RANGE_FIELD_FORMAT_UINT8, // rangeFieldFormat
+ 0, // rangeFieldsupport
+ 0, // nominalValue
+ 0, // normalMax
+ 0, // normalMin
+ 0, // warningHigh
+ 0, // warningLow
+ 0, // criticalHigh
+ 0, // criticalLow
+ 0, // fatalHigh
+ 0 // fatalLow
+ };
+
+ auto numericSensorPdr = std::make_shared<pldm_numeric_sensor_value_pdr>();
+ std::printf("pdr size=%ld\n", pdr1.size());
+ auto rc = decode_numeric_sensor_pdr_data(pdr1.data(), pdr1.size(),
+ numericSensorPdr.get());
+ EXPECT_EQ(rc, PLDM_SUCCESS);
+
+ std::string sensorName{"test1"};
+ std::string inventoryPath{
+ "/xyz/openbmc_project/inventroy/Item/Board/PLDM_device_1"};
+ pldm::platform_mc::NumericSensor sensor(0x01, true, numericSensorPdr,
+ sensorName, inventoryPath);
+ double reading = 40.0;
+ double convertedValue = 0;
+ convertedValue = sensor.conversionFormula(reading);
+ convertedValue = sensor.unitModifier(convertedValue);
+
+ // (40*1.5 + 1.0 ) * 10^1 = 610
+ EXPECT_EQ(610, convertedValue);
+}
+
+TEST(NumericSensor, checkThreshold)
+{
+ std::vector<uint8_t> pdr1{
+ 0x1,
+ 0x0,
+ 0x0,
+ 0x0, // record handle
+ 0x1, // PDRHeaderVersion
+ PLDM_NUMERIC_SENSOR_PDR, // PDRType
+ 0x0,
+ 0x0, // recordChangeNumber
+ PLDM_PDR_NUMERIC_SENSOR_PDR_FIXED_LENGTH +
+ PLDM_PDR_NUMERIC_SENSOR_PDR_VARIED_SENSOR_DATA_SIZE_MIN_LENGTH +
+ PLDM_PDR_NUMERIC_SENSOR_PDR_VARIED_RANGE_FIELD_MIN_LENGTH,
+ 0, // dataLength
+ 0,
+ 0, // PLDMTerminusHandle
+ 0x1,
+ 0x0, // sensorID=1
+ PLDM_ENTITY_POWER_SUPPLY,
+ 0, // entityType=Power Supply(120)
+ 1,
+ 0, // entityInstanceNumber
+ 0x1,
+ 0x0, // containerID=1
+ PLDM_NO_INIT, // sensorInit
+ false, // sensorAuxiliaryNamesPDR
+ PLDM_SENSOR_UNIT_DEGRESS_C, // baseUint(2)=degrees C
+ 1, // unitModifier = 1
+ 0, // rateUnit
+ 0, // baseOEMUnitHandle
+ 0, // auxUnit
+ 0, // auxUnitModifier
+ 0, // auxRateUnit
+ 0, // rel
+ 0, // auxOEMUnitHandle
+ true, // isLinear
+ PLDM_RANGE_FIELD_FORMAT_SINT8, // sensorDataSize
+ 0,
+ 0,
+ 0xc0,
+ 0x3f, // resolution=1.5
+ 0,
+ 0,
+ 0x80,
+ 0x3f, // offset=1.0
+ 0,
+ 0, // accuracy
+ 0, // plusTolerance
+ 0, // minusTolerance
+ 2, // hysteresis
+ 0, // supportedThresholds
+ 0, // thresholdAndHysteresisVolatility
+ 0,
+ 0,
+ 0x80,
+ 0x3f, // stateTransistionInterval=1.0
+ 0,
+ 0,
+ 0x80,
+ 0x3f, // updateInverval=1.0
+ 255, // maxReadable
+ 0, // minReadable
+ PLDM_RANGE_FIELD_FORMAT_UINT8, // rangeFieldFormat
+ 0, // rangeFieldsupport
+ 0, // nominalValue
+ 0, // normalMax
+ 0, // normalMin
+ 0, // warningHigh
+ 0, // warningLow
+ 0, // criticalHigh
+ 0, // criticalLow
+ 0, // fatalHigh
+ 0 // fatalLow
+ };
+
+ auto numericSensorPdr = std::make_shared<pldm_numeric_sensor_value_pdr>();
+ auto rc = decode_numeric_sensor_pdr_data(pdr1.data(), pdr1.size(),
+ numericSensorPdr.get());
+ EXPECT_EQ(rc, PLDM_SUCCESS);
+ std::string sensorName{"test1"};
+ std::string inventoryPath{
+ "/xyz/openbmc_project/inventroy/Item/Board/PLDM_device_1"};
+ pldm::platform_mc::NumericSensor sensor(0x01, true, numericSensorPdr,
+ sensorName, inventoryPath);
+
+ bool highAlarm = false;
+ bool lowAlarm = false;
+ double highThreshold = 40;
+ double lowThreshold = 30;
+ double hysteresis = 2;
+
+ // reading 35->40->45->38->35->30->25->32->35
+ // highAlarm F->T ->T ->T ->F ->F ->F -> F-> F
+ // lowAlarm F->F ->F ->F ->F ->T ->T -> T ->F
+ double reading = 35;
+ highAlarm = sensor.checkThreshold(highAlarm, true, reading, highThreshold,
+ hysteresis);
+ EXPECT_EQ(false, highAlarm);
+ lowAlarm = sensor.checkThreshold(lowAlarm, false, reading, lowThreshold,
+ hysteresis);
+ EXPECT_EQ(false, lowAlarm);
+
+ reading = 40;
+ highAlarm = sensor.checkThreshold(highAlarm, true, reading, highThreshold,
+ hysteresis);
+ EXPECT_EQ(true, highAlarm);
+ lowAlarm = sensor.checkThreshold(lowAlarm, false, reading, lowThreshold,
+ hysteresis);
+ EXPECT_EQ(false, lowAlarm);
+
+ reading = 45;
+ highAlarm = sensor.checkThreshold(highAlarm, true, reading, highThreshold,
+ hysteresis);
+ EXPECT_EQ(true, highAlarm);
+ lowAlarm = sensor.checkThreshold(lowAlarm, false, reading, lowThreshold,
+ hysteresis);
+ EXPECT_EQ(false, lowAlarm);
+
+ reading = 38;
+ highAlarm = sensor.checkThreshold(highAlarm, true, reading, highThreshold,
+ hysteresis);
+ EXPECT_EQ(true, highAlarm);
+ lowAlarm = sensor.checkThreshold(lowAlarm, false, reading, lowThreshold,
+ hysteresis);
+ EXPECT_EQ(false, lowAlarm);
+
+ reading = 35;
+ highAlarm = sensor.checkThreshold(highAlarm, true, reading, highThreshold,
+ hysteresis);
+ EXPECT_EQ(false, highAlarm);
+ lowAlarm = sensor.checkThreshold(lowAlarm, false, reading, lowThreshold,
+ hysteresis);
+ EXPECT_EQ(false, lowAlarm);
+
+ reading = 30;
+ highAlarm = sensor.checkThreshold(highAlarm, true, reading, highThreshold,
+ hysteresis);
+ EXPECT_EQ(false, highAlarm);
+ lowAlarm = sensor.checkThreshold(lowAlarm, false, reading, lowThreshold,
+ hysteresis);
+ EXPECT_EQ(true, lowAlarm);
+
+ reading = 25;
+ highAlarm = sensor.checkThreshold(highAlarm, true, reading, highThreshold,
+ hysteresis);
+ EXPECT_EQ(false, highAlarm);
+ lowAlarm = sensor.checkThreshold(lowAlarm, false, reading, lowThreshold,
+ hysteresis);
+ EXPECT_EQ(true, lowAlarm);
+
+ reading = 32;
+ highAlarm = sensor.checkThreshold(highAlarm, true, reading, highThreshold,
+ hysteresis);
+ EXPECT_EQ(false, highAlarm);
+ lowAlarm = sensor.checkThreshold(lowAlarm, false, reading, lowThreshold,
+ hysteresis);
+ EXPECT_EQ(true, lowAlarm);
+
+ reading = 35;
+ highAlarm = sensor.checkThreshold(highAlarm, true, reading, highThreshold,
+ hysteresis);
+ EXPECT_EQ(false, highAlarm);
+ lowAlarm = sensor.checkThreshold(lowAlarm, false, reading, lowThreshold,
+ hysteresis);
+ EXPECT_EQ(false, lowAlarm);
+}
diff --git a/platform-mc/test/platform_manager_test.cpp b/platform-mc/test/platform_manager_test.cpp
index 8afad35..73baa1a 100644
--- a/platform-mc/test/platform_manager_test.cpp
+++ b/platform-mc/test/platform_manager_test.cpp
@@ -63,7 +63,7 @@
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // updateTime
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // OEMUpdateTime
- 1, 0x0, 0x0, 0x0, // recordCount
+ 2, 0x0, 0x0, 0x0, // recordCount
0x0, 0x1, 0x0, 0x0, // repositorySize
59, 0x0, 0x0, 0x0, // largestRecordSize
0x0 // dataTransferHandleTimeout
@@ -76,12 +76,12 @@
// queue getPDR responses
const size_t getPdrRespLen = 81;
std::array<uint8_t, sizeof(pldm_msg_hdr) + getPdrRespLen> getPdrResp{
- 0x0, 0x02, 0x51, PLDM_SUCCESS, 0x0, 0x0, 0x0, 0x0, // nextRecordHandle
+ 0x0, 0x02, 0x51, PLDM_SUCCESS, 0x1, 0x0, 0x0, 0x0, // nextRecordHandle
0x0, 0x0, 0x0, 0x0, // nextDataTransferHandle
0x5, // transferFlag
69, 0x0, // responseCount
// numeric Sensor PDR
- 0x1, 0x0, 0x0,
+ 0x0, 0x0, 0x0,
0x0, // record handle
0x1, // PDRHeaderVersion
PLDM_NUMERIC_SENSOR_PDR, // PDRType
@@ -147,9 +147,47 @@
reinterpret_cast<pldm_msg*>(getPdrResp.data()), sizeof(getPdrResp));
EXPECT_EQ(rc, PLDM_SUCCESS);
+ const size_t getPdrAuxNameRespLen = 39;
+ std::array<uint8_t, sizeof(pldm_msg_hdr) + getPdrAuxNameRespLen>
+ getPdrAuxNameResp{
+ 0x0, 0x02, 0x51, PLDM_SUCCESS, 0x0, 0x0, 0x0,
+ 0x0, // nextRecordHandle
+ 0x0, 0x0, 0x0, 0x0, // nextDataTransferHandle
+ 0x5, // transferFlag
+ 0x1b, 0x0, // responseCount
+ // Common PDR Header
+ 0x1, 0x0, 0x0,
+ 0x0, // record handle
+ 0x1, // PDRHeaderVersion
+ PLDM_ENTITY_AUXILIARY_NAMES_PDR, // PDRType
+ 0x1,
+ 0x0, // recordChangeNumber
+ 0x11,
+ 0, // dataLength
+ /* Entity Auxiliary Names PDR Data*/
+ 3,
+ 0x80, // entityType system software
+ 0x1,
+ 0x0, // Entity instance number =1
+ 0,
+ 0, // Overal system
+ 0, // shared Name Count one name only
+ 01, // nameStringCount
+ 0x65, 0x6e, 0x00,
+ 0x00, // Language Tag "en"
+ 0x53, 0x00, 0x30, 0x00,
+ 0x00 // Entity Name "S0"
+ };
+ rc = mockTerminusManager.enqueueResponse(
+ reinterpret_cast<pldm_msg*>(getPdrAuxNameResp.data()),
+ sizeof(getPdrAuxNameResp));
+ EXPECT_EQ(rc, PLDM_SUCCESS);
+
stdexec::sync_wait(platformManager.initTerminus());
EXPECT_EQ(true, terminus->initialized);
- EXPECT_EQ(1, terminus->pdrs.size());
+ EXPECT_EQ(2, terminus->pdrs.size());
+ EXPECT_EQ(1, terminus->numericSensors.size());
+ EXPECT_EQ("S0", terminus->getTerminusName());
}
TEST_F(PlatformManagerTest, parseTerminusNameTest)
@@ -440,6 +478,7 @@
stdexec::sync_wait(platformManager.initTerminus());
EXPECT_EQ(true, terminus->initialized);
EXPECT_EQ(0, terminus->pdrs.size());
+ EXPECT_EQ(0, terminus->numericSensors.size());
}
TEST_F(PlatformManagerTest, negativeInitTerminusTest2)
@@ -471,4 +510,5 @@
stdexec::sync_wait(platformManager.initTerminus());
EXPECT_EQ(true, terminus->initialized);
EXPECT_EQ(0, terminus->pdrs.size());
+ EXPECT_EQ(0, terminus->numericSensors.size());
}
diff --git a/platform-mc/test/sensor_manager_test.cpp b/platform-mc/test/sensor_manager_test.cpp
new file mode 100644
index 0000000..03cb7fd
--- /dev/null
+++ b/platform-mc/test/sensor_manager_test.cpp
@@ -0,0 +1,172 @@
+#include "common/instance_id.hpp"
+#include "common/types.hpp"
+#include "mock_sensor_manager.hpp"
+#include "platform-mc/terminus_manager.hpp"
+#include "test/test_instance_id.hpp"
+
+#include <sdeventplus/event.hpp>
+
+#include <gtest/gtest.h>
+
+using ::testing::_;
+using ::testing::Between;
+using ::testing::Return;
+
+class SensorManagerTest : public testing::Test
+{
+ protected:
+ SensorManagerTest() :
+ bus(pldm::utils::DBusHandler::getBus()),
+ event(sdeventplus::Event::get_default()), instanceIdDb(),
+ reqHandler(pldmTransport, event, instanceIdDb, false),
+ terminusManager(event, reqHandler, instanceIdDb, termini, nullptr),
+ sensorManager(event, terminusManager, termini)
+ {}
+
+ void runEventLoopForSeconds(uint64_t sec)
+ {
+ uint64_t t0 = 0;
+ uint64_t t1 = 0;
+ uint64_t usec = sec * 1000000;
+ uint64_t elapsed = 0;
+ sd_event_now(event.get(), CLOCK_MONOTONIC, &t0);
+ do
+ {
+ if (!sd_event_run(event.get(), usec - elapsed))
+ {
+ break;
+ }
+ sd_event_now(event.get(), CLOCK_MONOTONIC, &t1);
+ elapsed = t1 - t0;
+ } while (elapsed < usec);
+ }
+
+ PldmTransport* pldmTransport = nullptr;
+ sdbusplus::bus::bus& bus;
+ sdeventplus::Event event;
+ TestInstanceIdDb instanceIdDb;
+ pldm::requester::Handler<pldm::requester::Request> reqHandler;
+ pldm::platform_mc::TerminusManager terminusManager;
+ pldm::platform_mc::MockSensorManager sensorManager;
+ std::map<pldm_tid_t, std::shared_ptr<pldm::platform_mc::Terminus>> termini;
+
+ std::vector<uint8_t> pdr1{
+ 0x1,
+ 0x0,
+ 0x0,
+ 0x0, // record handle
+ 0x1, // PDRHeaderVersion
+ PLDM_NUMERIC_SENSOR_PDR, // PDRType
+ 0x0,
+ 0x0, // recordChangeNumber
+ PLDM_PDR_NUMERIC_SENSOR_PDR_FIXED_LENGTH +
+ PLDM_PDR_NUMERIC_SENSOR_PDR_VARIED_SENSOR_DATA_SIZE_MIN_LENGTH +
+ PLDM_PDR_NUMERIC_SENSOR_PDR_VARIED_RANGE_FIELD_MIN_LENGTH,
+ 0, // dataLength
+ 0,
+ 0, // PLDMTerminusHandle
+ 0x1,
+ 0x0, // sensorID=1
+ PLDM_ENTITY_POWER_SUPPLY,
+ 0, // entityType=Power Supply(120)
+ 1,
+ 0, // entityInstanceNumber
+ 0x1,
+ 0x0, // containerID=1
+ PLDM_NO_INIT, // sensorInit
+ false, // sensorAuxiliaryNamesPDR
+ PLDM_SENSOR_UNIT_DEGRESS_C, // baseUint(2)=degrees C
+ 1, // unitModifier = 1
+ 0, // rateUnit
+ 0, // baseOEMUnitHandle
+ 0, // auxUnit
+ 0, // auxUnitModifier
+ 0, // auxRateUnit
+ 0, // rel
+ 0, // auxOEMUnitHandle
+ true, // isLinear
+ PLDM_RANGE_FIELD_FORMAT_SINT8, // sensorDataSize
+ 0,
+ 0,
+ 0xc0,
+ 0x3f, // resolution=1.5
+ 0,
+ 0,
+ 0x80,
+ 0x3f, // offset=1.0
+ 0,
+ 0, // accuracy
+ 0, // plusTolerance
+ 0, // minusTolerance
+ 2, // hysteresis
+ 0, // supportedThresholds
+ 0, // thresholdAndHysteresisVolatility
+ 0,
+ 0,
+ 0x80,
+ 0x3f, // stateTransistionInterval=1.0
+ 0,
+ 0,
+ 0x80,
+ 0x3f, // updateInverval=1.0
+ 255, // maxReadable
+ 0, // minReadable
+ PLDM_RANGE_FIELD_FORMAT_UINT8, // rangeFieldFormat
+ 0, // rangeFieldsupport
+ 0, // nominalValue
+ 0, // normalMax
+ 0, // normalMin
+ 0, // warningHigh
+ 0, // warningLow
+ 0, // criticalHigh
+ 0, // criticalLow
+ 0, // fatalHigh
+ 0 // fatalLow
+ };
+
+ std::vector<uint8_t> pdr2{
+ 0x1, 0x0, 0x0,
+ 0x0, // record handle
+ 0x1, // PDRHeaderVersion
+ PLDM_ENTITY_AUXILIARY_NAMES_PDR, // PDRType
+ 0x1,
+ 0x0, // recordChangeNumber
+ 0x11,
+ 0, // dataLength
+ /* Entity Auxiliary Names PDR Data*/
+ 3,
+ 0x80, // entityType system software
+ 0x1,
+ 0x0, // Entity instance number =1
+ 0,
+ 0, // Overal system
+ 0, // shared Name Count one name only
+ 01, // nameStringCount
+ 0x65, 0x6e, 0x00,
+ 0x00, // Language Tag "en"
+ 0x53, 0x00, 0x30, 0x00,
+ 0x00 // Entity Name "S0"
+ };
+};
+
+TEST_F(SensorManagerTest, sensorPollingTest)
+{
+ uint64_t seconds = 10;
+ uint64_t expectedTimes = (seconds * 1000) / SENSOR_POLLING_TIME;
+
+ pldm_tid_t tid = 1;
+ termini[tid] = std::make_shared<pldm::platform_mc::Terminus>(tid, 0);
+ termini[tid]->pdrs.push_back(pdr1);
+ termini[tid]->pdrs.push_back(pdr2);
+ termini[tid]->parseTerminusPDRs();
+
+ EXPECT_CALL(sensorManager, doSensorPolling(tid))
+ .Times(Between(expectedTimes - 3, expectedTimes + 3))
+ .WillRepeatedly(Return());
+
+ sensorManager.startPolling(tid);
+
+ runEventLoopForSeconds(seconds);
+
+ sensorManager.stopPolling(tid);
+}