regulators: Implements support for pmbus_read_sensor action
Enhance the configuration file parser to support the pmbus_read_sensor
action element.
Signed-off-by: Bob King <Bob_King@wistron.com>
Change-Id: I7f87a7551469bb494fe17b6d6d79ebb1ca517e86
diff --git a/phosphor-regulators/src/config_file_parser.cpp b/phosphor-regulators/src/config_file_parser.cpp
index 11527b8..6fa34e1 100644
--- a/phosphor-regulators/src/config_file_parser.cpp
+++ b/phosphor-regulators/src/config_file_parser.cpp
@@ -127,9 +127,8 @@
}
else if (element.contains("pmbus_read_sensor"))
{
- // TODO: Not implemented yet
- // action = parsePMBusReadSensor(element["pmbus_read_sensor"]);
- // ++propertyCount;
+ action = parsePMBusReadSensor(element["pmbus_read_sensor"]);
+ ++propertyCount;
}
else if (element.contains("pmbus_write_vout_command"))
{
@@ -672,6 +671,42 @@
return std::make_unique<OrAction>(std::move(actions));
}
+std::unique_ptr<PMBusReadSensorAction> parsePMBusReadSensor(const json& element)
+{
+ verifyIsObject(element);
+ unsigned int propertyCount{0};
+
+ // Required type property
+ const json& typeElement = getRequiredProperty(element, "type");
+ pmbus_utils::SensorValueType type = parseSensorValueType(typeElement);
+ ++propertyCount;
+
+ // Required command property
+ const json& commandElement = getRequiredProperty(element, "command");
+ uint8_t command = parseHexByte(commandElement);
+ ++propertyCount;
+
+ // Required format property
+ const json& formatElement = getRequiredProperty(element, "format");
+ pmbus_utils::SensorDataFormat format = parseSensorDataFormat(formatElement);
+ ++propertyCount;
+
+ // Optional exponent property
+ std::optional<int8_t> exponent{};
+ auto exponentIt = element.find("exponent");
+ if (exponentIt != element.end())
+ {
+ exponent = parseInt8(*exponentIt);
+ ++propertyCount;
+ }
+
+ // Verify no invalid properties exist
+ verifyPropertyCount(element, propertyCount);
+
+ return std::make_unique<PMBusReadSensorAction>(type, command, format,
+ exponent);
+}
+
std::unique_ptr<PMBusWriteVoutCommandAction>
parsePMBusWriteVoutCommand(const json& element)
{
@@ -903,6 +938,31 @@
return std::make_unique<RunRuleAction>(ruleID);
}
+pmbus_utils::SensorDataFormat parseSensorDataFormat(const json& element)
+{
+ if (!element.is_string())
+ {
+ throw std::invalid_argument{"Element is not a string"};
+ }
+ std::string value = element.get<std::string>();
+ pmbus_utils::SensorDataFormat format{};
+
+ if (value == "linear_11")
+ {
+ format = pmbus_utils::SensorDataFormat::linear_11;
+ }
+ else if (value == "linear_16")
+ {
+ format = pmbus_utils::SensorDataFormat::linear_16;
+ }
+ else
+ {
+ throw std::invalid_argument{"Element is not a sensor data format"};
+ }
+
+ return format;
+}
+
std::unique_ptr<SensorMonitoring> parseSensorMonitoring(const json& element)
{
verifyIsObject(element);
@@ -925,6 +985,59 @@
return std::make_unique<SensorMonitoring>(std::move(actions));
}
+pmbus_utils::SensorValueType parseSensorValueType(const json& element)
+{
+ if (!element.is_string())
+ {
+ throw std::invalid_argument{"Element is not a string"};
+ }
+ std::string value = element.get<std::string>();
+ pmbus_utils::SensorValueType type{};
+
+ if (value == "iout")
+ {
+ type = pmbus_utils::SensorValueType::iout;
+ }
+ else if (value == "iout_peak")
+ {
+ type = pmbus_utils::SensorValueType::iout_peak;
+ }
+ else if (value == "iout_valley")
+ {
+ type = pmbus_utils::SensorValueType::iout_valley;
+ }
+ else if (value == "pout")
+ {
+ type = pmbus_utils::SensorValueType::pout;
+ }
+ else if (value == "temperature")
+ {
+ type = pmbus_utils::SensorValueType::temperature;
+ }
+ else if (value == "temperature_peak")
+ {
+ type = pmbus_utils::SensorValueType::temperature_peak;
+ }
+ else if (value == "vout")
+ {
+ type = pmbus_utils::SensorValueType::vout;
+ }
+ else if (value == "vout_peak")
+ {
+ type = pmbus_utils::SensorValueType::vout_peak;
+ }
+ else if (value == "vout_valley")
+ {
+ type = pmbus_utils::SensorValueType::vout_valley;
+ }
+ else
+ {
+ throw std::invalid_argument{"Element is not a sensor value type"};
+ }
+
+ return type;
+}
+
std::unique_ptr<SetDeviceAction> parseSetDevice(const json& element)
{
// String deviceID
@@ -933,6 +1046,39 @@
return std::make_unique<SetDeviceAction>(deviceID);
}
+pmbus_utils::VoutDataFormat parseVoutDataFormat(const json& element)
+{
+ if (!element.is_string())
+ {
+ throw std::invalid_argument{"Element is not a string"};
+ }
+ std::string value = element.get<std::string>();
+ pmbus_utils::VoutDataFormat format{};
+
+ if (value == "linear")
+ {
+ format = pmbus_utils::VoutDataFormat::linear;
+ }
+ else if (value == "vid")
+ {
+ format = pmbus_utils::VoutDataFormat::vid;
+ }
+ else if (value == "direct")
+ {
+ format = pmbus_utils::VoutDataFormat::direct;
+ }
+ else if (value == "ieee")
+ {
+ format = pmbus_utils::VoutDataFormat::ieee;
+ }
+ else
+ {
+ throw std::invalid_argument{"Element is not a vout data format"};
+ }
+
+ return format;
+}
+
} // namespace internal
} // namespace phosphor::power::regulators::config_file_parser
diff --git a/phosphor-regulators/src/config_file_parser.hpp b/phosphor-regulators/src/config_file_parser.hpp
index 205f43a..848ed95 100644
--- a/phosphor-regulators/src/config_file_parser.hpp
+++ b/phosphor-regulators/src/config_file_parser.hpp
@@ -32,6 +32,7 @@
#include "if_action.hpp"
#include "not_action.hpp"
#include "or_action.hpp"
+#include "pmbus_read_sensor_action.hpp"
#include "pmbus_write_vout_command_action.hpp"
#include "presence_detection.hpp"
#include "rail.hpp"
@@ -508,6 +509,19 @@
std::unique_ptr<OrAction> parseOr(const nlohmann::json& element);
/**
+ * Parses a JSON element containing a pmbus_read_sensor action.
+ *
+ * Returns the corresponding C++ PMBusReadSensorAction object.
+ *
+ * Throws an exception if parsing fails.
+ *
+ * @param element JSON element
+ * @return PMBusReadSensorAction object
+ */
+std::unique_ptr<PMBusReadSensorAction>
+ parsePMBusReadSensor(const nlohmann::json& element);
+
+/**
* Parses a JSON element containing a pmbus_write_vout_command action.
*
* Returns the corresponding C++ PMBusWriteVoutCommandAction object.
@@ -629,6 +643,19 @@
std::unique_ptr<RunRuleAction> parseRunRule(const nlohmann::json& element);
/**
+ * Parses a JSON element containing a SensorDataFormat expressed as a string.
+ *
+ * Returns the corresponding SensorDataFormat enum value.
+ *
+ * Throws an exception if parsing fails.
+ *
+ * @param element JSON element
+ * @return SensorDataFormat enum value
+ */
+pmbus_utils::SensorDataFormat
+ parseSensorDataFormat(const nlohmann::json& element);
+
+/**
* Parses a JSON element containing a sensor monitoring operation.
*
* Returns the corresponding C++ SensorMonitoring object.
@@ -642,6 +669,19 @@
parseSensorMonitoring(const nlohmann::json& element);
/**
+ * Parses a JSON element containing a SensorValueType expressed as a string.
+ *
+ * Returns the corresponding SensorValueType enum value.
+ *
+ * Throws an exception if parsing fails.
+ *
+ * @param element JSON element
+ * @return SensorValueType enum value
+ */
+pmbus_utils::SensorValueType
+ parseSensorValueType(const nlohmann::json& element);
+
+/**
* Parses a JSON element containing a set_device action.
*
* Returns the corresponding C++ SetDeviceAction object.
@@ -725,6 +765,18 @@
}
/**
+ * Parses a JSON element containing a VoutDataFormat expressed as a string.
+ *
+ * Returns the corresponding VoutDataFormat enum value.
+ *
+ * Throws an exception if parsing fails.
+ *
+ * @param element JSON element
+ * @return VoutDataFormat enum value
+ */
+pmbus_utils::VoutDataFormat parseVoutDataFormat(const nlohmann::json& element);
+
+/**
* Verifies that the specified JSON element is a JSON array.
*
* Throws an invalid_argument exception if the element is not an array.
diff --git a/phosphor-regulators/test/config_file_parser_tests.cpp b/phosphor-regulators/test/config_file_parser_tests.cpp
index c6db12d..80e65ba 100644
--- a/phosphor-regulators/test/config_file_parser_tests.cpp
+++ b/phosphor-regulators/test/config_file_parser_tests.cpp
@@ -31,6 +31,7 @@
#include "i2c_write_bytes_action.hpp"
#include "not_action.hpp"
#include "or_action.hpp"
+#include "pmbus_read_sensor_action.hpp"
#include "pmbus_utils.hpp"
#include "pmbus_write_vout_command_action.hpp"
#include "presence_detection.hpp"
@@ -419,7 +420,19 @@
}
// Test where works: pmbus_read_sensor action type specified
- // TODO: Not implemented yet
+ {
+ const json element = R"(
+ {
+ "pmbus_read_sensor": {
+ "type": "iout",
+ "command": "0x8C",
+ "format": "linear_11"
+ }
+ }
+ )"_json;
+ std::unique_ptr<Action> action = parseAction(element);
+ EXPECT_NE(action.get(), nullptr);
+ }
// Test where works: pmbus_write_vout_command action type specified
{
@@ -3110,6 +3123,202 @@
}
}
+TEST(ConfigFileParserTests, ParsePMBusReadSensor)
+{
+ // Test where works: Only required properties specified
+ {
+ const json element = R"(
+ {
+ "type": "iout",
+ "command": "0x8C",
+ "format": "linear_11"
+ }
+ )"_json;
+ std::unique_ptr<PMBusReadSensorAction> action =
+ parsePMBusReadSensor(element);
+ EXPECT_EQ(action->getType(), pmbus_utils::SensorValueType::iout);
+ EXPECT_EQ(action->getCommand(), 0x8C);
+ EXPECT_EQ(action->getFormat(),
+ pmbus_utils::SensorDataFormat::linear_11);
+ EXPECT_EQ(action->getExponent().has_value(), false);
+ }
+
+ // Test where works: All properties specified
+ {
+ const json element = R"(
+ {
+ "type": "temperature",
+ "command": "0x7A",
+ "format": "linear_16",
+ "exponent": -8
+ }
+ )"_json;
+ std::unique_ptr<PMBusReadSensorAction> action =
+ parsePMBusReadSensor(element);
+ EXPECT_EQ(action->getType(), pmbus_utils::SensorValueType::temperature);
+ EXPECT_EQ(action->getCommand(), 0x7A);
+ EXPECT_EQ(action->getFormat(),
+ pmbus_utils::SensorDataFormat::linear_16);
+ EXPECT_EQ(action->getExponent().has_value(), true);
+ EXPECT_EQ(action->getExponent().value(), -8);
+ }
+
+ // Test where fails: Element is not an object
+ try
+ {
+ const json element = R"( [ "0xFF", "0x01" ] )"_json;
+ parsePMBusReadSensor(element);
+ ADD_FAILURE() << "Should not have reached this line.";
+ }
+ catch (const std::invalid_argument& e)
+ {
+ EXPECT_STREQ(e.what(), "Element is not an object");
+ }
+
+ // Test where fails: Invalid property specified
+ try
+ {
+ const json element = R"(
+ {
+ "type": "iout",
+ "command": "0x8C",
+ "format": "linear_11",
+ "foo": 1
+ }
+ )"_json;
+ parsePMBusReadSensor(element);
+ ADD_FAILURE() << "Should not have reached this line.";
+ }
+ catch (const std::invalid_argument& e)
+ {
+ EXPECT_STREQ(e.what(), "Element contains an invalid property");
+ }
+
+ // Test where fails: Required type property not specified
+ try
+ {
+ const json element = R"(
+ {
+ "command": "0x8C",
+ "format": "linear_11"
+ }
+ )"_json;
+ parsePMBusReadSensor(element);
+ ADD_FAILURE() << "Should not have reached this line.";
+ }
+ catch (const std::invalid_argument& e)
+ {
+ EXPECT_STREQ(e.what(), "Required property missing: type");
+ }
+
+ // Test where fails: Required command property not specified
+ try
+ {
+ const json element = R"(
+ {
+ "type": "iout",
+ "format": "linear_11"
+ }
+ )"_json;
+ parsePMBusReadSensor(element);
+ ADD_FAILURE() << "Should not have reached this line.";
+ }
+ catch (const std::invalid_argument& e)
+ {
+ EXPECT_STREQ(e.what(), "Required property missing: command");
+ }
+
+ // Test where fails: Required format property not specified
+ try
+ {
+ const json element = R"(
+ {
+ "type": "iout",
+ "command": "0x8C"
+ }
+ )"_json;
+ parsePMBusReadSensor(element);
+ ADD_FAILURE() << "Should not have reached this line.";
+ }
+ catch (const std::invalid_argument& e)
+ {
+ EXPECT_STREQ(e.what(), "Required property missing: format");
+ }
+
+ // Test where fails: type value is invalid
+ try
+ {
+ const json element = R"(
+ {
+ "type": 1,
+ "command": "0x7A",
+ "format": "linear_16"
+ }
+ )"_json;
+ parsePMBusReadSensor(element);
+ ADD_FAILURE() << "Should not have reached this line.";
+ }
+ catch (const std::invalid_argument& e)
+ {
+ EXPECT_STREQ(e.what(), "Element is not a string");
+ }
+
+ // Test where fails: command value is invalid
+ try
+ {
+ const json element = R"(
+ {
+ "type": "temperature",
+ "command": 0,
+ "format": "linear_16"
+ }
+ )"_json;
+ parsePMBusReadSensor(element);
+ ADD_FAILURE() << "Should not have reached this line.";
+ }
+ catch (const std::invalid_argument& e)
+ {
+ EXPECT_STREQ(e.what(), "Element is not a string");
+ }
+
+ // Test where fails: format value is invalid
+ try
+ {
+ const json element = R"(
+ {
+ "type": "temperature",
+ "command": "0x7A",
+ "format": 1
+ }
+ )"_json;
+ parsePMBusReadSensor(element);
+ ADD_FAILURE() << "Should not have reached this line.";
+ }
+ catch (const std::invalid_argument& e)
+ {
+ EXPECT_STREQ(e.what(), "Element is not a string");
+ }
+
+ // Test where fails: exponent value is invalid
+ try
+ {
+ const json element = R"(
+ {
+ "type": "temperature",
+ "command": "0x7A",
+ "format": "linear_16",
+ "exponent": 1.3
+ }
+ )"_json;
+ parsePMBusReadSensor(element);
+ ADD_FAILURE() << "Should not have reached this line.";
+ }
+ catch (const std::invalid_argument& e)
+ {
+ EXPECT_STREQ(e.what(), "Element is not an integer");
+ }
+}
+
TEST(ConfigFileParserTests, ParsePMBusWriteVoutCommand)
{
// Test where works: Only required properties specified
@@ -4021,6 +4230,51 @@
}
}
+TEST(ConfigFileParserTests, ParseSensorDataFormat)
+{
+ // Test where works: linear_11
+ {
+ const json element = "linear_11";
+ pmbus_utils::SensorDataFormat value = parseSensorDataFormat(element);
+ pmbus_utils::SensorDataFormat format =
+ pmbus_utils::SensorDataFormat::linear_11;
+ EXPECT_EQ(value, format);
+ }
+
+ // Test where works: linear_16
+ {
+ const json element = "linear_16";
+ pmbus_utils::SensorDataFormat value = parseSensorDataFormat(element);
+ pmbus_utils::SensorDataFormat format =
+ pmbus_utils::SensorDataFormat::linear_16;
+ EXPECT_EQ(value, format);
+ }
+
+ // Test where fails: Element is not a sensor data format
+ try
+ {
+ const json element = "foo";
+ parseSensorDataFormat(element);
+ ADD_FAILURE() << "Should not have reached this line.";
+ }
+ catch (const std::invalid_argument& e)
+ {
+ EXPECT_STREQ(e.what(), "Element is not a sensor data format");
+ }
+
+ // Test where fails: Element is not a string
+ try
+ {
+ const json element = R"( { "foo": "bar" } )"_json;
+ parseSensorDataFormat(element);
+ ADD_FAILURE() << "Should not have reached this line.";
+ }
+ catch (const std::invalid_argument& e)
+ {
+ EXPECT_STREQ(e.what(), "Element is not a string");
+ }
+}
+
TEST(ConfigFileParserTests, ParseSensorMonitoring)
{
// Test where works: actions property specified
@@ -4151,6 +4405,111 @@
}
}
+TEST(ConfigFileParserTests, ParseSensorValueType)
+{
+ // Test where works: iout
+ {
+ const json element = "iout";
+ pmbus_utils::SensorValueType value = parseSensorValueType(element);
+ pmbus_utils::SensorValueType type = pmbus_utils::SensorValueType::iout;
+ EXPECT_EQ(value, type);
+ }
+
+ // Test where works: iout_peak
+ {
+ const json element = "iout_peak";
+ pmbus_utils::SensorValueType value = parseSensorValueType(element);
+ pmbus_utils::SensorValueType type =
+ pmbus_utils::SensorValueType::iout_peak;
+ EXPECT_EQ(value, type);
+ }
+
+ // Test where works: iout_valley
+ {
+ const json element = "iout_valley";
+ pmbus_utils::SensorValueType value = parseSensorValueType(element);
+ pmbus_utils::SensorValueType type =
+ pmbus_utils::SensorValueType::iout_valley;
+ EXPECT_EQ(value, type);
+ }
+
+ // Test where works: pout
+ {
+ const json element = "pout";
+ pmbus_utils::SensorValueType value = parseSensorValueType(element);
+ pmbus_utils::SensorValueType type = pmbus_utils::SensorValueType::pout;
+ EXPECT_EQ(value, type);
+ }
+
+ // Test where works: temperature
+ {
+ const json element = "temperature";
+ pmbus_utils::SensorValueType value = parseSensorValueType(element);
+ pmbus_utils::SensorValueType type =
+ pmbus_utils::SensorValueType::temperature;
+ EXPECT_EQ(value, type);
+ }
+
+ // Test where works: temperature_peak
+ {
+ const json element = "temperature_peak";
+ pmbus_utils::SensorValueType value = parseSensorValueType(element);
+ pmbus_utils::SensorValueType type =
+ pmbus_utils::SensorValueType::temperature_peak;
+ EXPECT_EQ(value, type);
+ }
+
+ // Test where works: vout
+ {
+ const json element = "vout";
+ pmbus_utils::SensorValueType value = parseSensorValueType(element);
+ pmbus_utils::SensorValueType type = pmbus_utils::SensorValueType::vout;
+ EXPECT_EQ(value, type);
+ }
+
+ // Test where works: vout_peak
+ {
+ const json element = "vout_peak";
+ pmbus_utils::SensorValueType value = parseSensorValueType(element);
+ pmbus_utils::SensorValueType type =
+ pmbus_utils::SensorValueType::vout_peak;
+ EXPECT_EQ(value, type);
+ }
+
+ // Test where works: vout_valley
+ {
+ const json element = "vout_valley";
+ pmbus_utils::SensorValueType value = parseSensorValueType(element);
+ pmbus_utils::SensorValueType type =
+ pmbus_utils::SensorValueType::vout_valley;
+ EXPECT_EQ(value, type);
+ }
+
+ // Test where fails: Element is not a sensor value type
+ try
+ {
+ const json element = "foo";
+ parseSensorValueType(element);
+ ADD_FAILURE() << "Should not have reached this line.";
+ }
+ catch (const std::invalid_argument& e)
+ {
+ EXPECT_STREQ(e.what(), "Element is not a sensor value type");
+ }
+
+ // Test where fails: Element is not a string
+ try
+ {
+ const json element = R"( { "foo": "bar" } )"_json;
+ parseSensorValueType(element);
+ ADD_FAILURE() << "Should not have reached this line.";
+ }
+ catch (const std::invalid_argument& e)
+ {
+ EXPECT_STREQ(e.what(), "Element is not a string");
+ }
+}
+
TEST(ConfigFileParserTests, ParseSetDevice)
{
// Test where works
@@ -4313,6 +4672,67 @@
}
}
+TEST(ConfigFileParserTests, ParseVoutDataFormat)
+{
+ // Test where works: linear
+ {
+ const json element = "linear";
+ pmbus_utils::VoutDataFormat value = parseVoutDataFormat(element);
+ pmbus_utils::VoutDataFormat format =
+ pmbus_utils::VoutDataFormat::linear;
+ EXPECT_EQ(value, format);
+ }
+
+ // Test where works: vid
+ {
+ const json element = "vid";
+ pmbus_utils::VoutDataFormat value = parseVoutDataFormat(element);
+ pmbus_utils::VoutDataFormat format = pmbus_utils::VoutDataFormat::vid;
+ EXPECT_EQ(value, format);
+ }
+
+ // Test where works: direct
+ {
+ const json element = "direct";
+ pmbus_utils::VoutDataFormat value = parseVoutDataFormat(element);
+ pmbus_utils::VoutDataFormat format =
+ pmbus_utils::VoutDataFormat::direct;
+ EXPECT_EQ(value, format);
+ }
+
+ // Test where works: ieee
+ {
+ const json element = "ieee";
+ pmbus_utils::VoutDataFormat value = parseVoutDataFormat(element);
+ pmbus_utils::VoutDataFormat format = pmbus_utils::VoutDataFormat::ieee;
+ EXPECT_EQ(value, format);
+ }
+
+ // Test where fails: Element is not a vout data format
+ try
+ {
+ const json element = "foo";
+ parseVoutDataFormat(element);
+ ADD_FAILURE() << "Should not have reached this line.";
+ }
+ catch (const std::invalid_argument& e)
+ {
+ EXPECT_STREQ(e.what(), "Element is not a vout data format");
+ }
+
+ // Test where fails: Element is not a string
+ try
+ {
+ const json element = R"( { "foo": "bar" } )"_json;
+ parseVoutDataFormat(element);
+ ADD_FAILURE() << "Should not have reached this line.";
+ }
+ catch (const std::invalid_argument& e)
+ {
+ EXPECT_STREQ(e.what(), "Element is not a string");
+ }
+}
+
TEST(ConfigFileParserTests, VerifyIsArray)
{
// Test where element is an array