pseq: Parsing support for i2c_interface element
Add JSON parsing support for the new i2c_interface element in the
phosphor-power-sequencer configuration file.
Tested:
* Ran automated tests.
Change-Id: I2841078b0dd69635dbb6f71461d33d885b380f08
Signed-off-by: Shawn McCarney <shawnmm@us.ibm.com>
diff --git a/phosphor-power-sequencer/src/config_file_parser.cpp b/phosphor-power-sequencer/src/config_file_parser.cpp
index 07566ae..3163aff 100644
--- a/phosphor-power-sequencer/src/config_file_parser.cpp
+++ b/phosphor-power-sequencer/src/config_file_parser.cpp
@@ -118,6 +118,29 @@
return GPIO(line, activeLow);
}
+std::tuple<uint8_t, uint16_t> parseI2CInterface(
+ const nlohmann::json& element,
+ const std::map<std::string, std::string>& variables)
+{
+ verifyIsObject(element);
+ unsigned int propertyCount{0};
+
+ // Required bus property
+ const json& busElement = getRequiredProperty(element, "bus");
+ uint8_t bus = parseUint8(busElement, variables);
+ ++propertyCount;
+
+ // Required address property
+ const json& addressElement = getRequiredProperty(element, "address");
+ uint16_t address = parseHexByte(addressElement, variables);
+ ++propertyCount;
+
+ // Verify no invalid properties exist
+ verifyPropertyCount(element, propertyCount);
+
+ return {bus, address};
+}
+
std::unique_ptr<Rail> parseRail(const json& element)
{
verifyIsObject(element);
diff --git a/phosphor-power-sequencer/src/config_file_parser.hpp b/phosphor-power-sequencer/src/config_file_parser.hpp
index ee12690..a57083e 100644
--- a/phosphor-power-sequencer/src/config_file_parser.hpp
+++ b/phosphor-power-sequencer/src/config_file_parser.hpp
@@ -19,9 +19,12 @@
#include <nlohmann/json.hpp>
+#include <cstdint>
#include <filesystem>
+#include <map>
#include <memory>
#include <string>
+#include <tuple>
#include <vector>
namespace phosphor::power::sequencer::config_file_parser
@@ -88,6 +91,21 @@
GPIO parseGPIO(const nlohmann::json& element);
/**
+ * Parses a JSON element containing an i2c_interface object.
+ *
+ * Returns the corresponding I2C bus and address.
+ *
+ * Throws an exception if parsing fails.
+ *
+ * @param element JSON element
+ * @param variables variables map used to expand variables in element value
+ * @return tuple containing bus and address
+ */
+std::tuple<uint8_t, uint16_t> parseI2CInterface(
+ const nlohmann::json& element,
+ const std::map<std::string, std::string>& variables);
+
+/**
* Parses a JSON element containing a rail.
*
* Returns the corresponding C++ Rail object.
diff --git a/phosphor-power-sequencer/test/config_file_parser_tests.cpp b/phosphor-power-sequencer/test/config_file_parser_tests.cpp
index 9ad21c8..0fbf5fe 100644
--- a/phosphor-power-sequencer/test/config_file_parser_tests.cpp
+++ b/phosphor-power-sequencer/test/config_file_parser_tests.cpp
@@ -23,13 +23,16 @@
#include <nlohmann/json.hpp>
+#include <cstdint>
#include <exception>
#include <filesystem>
#include <fstream>
+#include <map>
#include <memory>
#include <optional>
#include <stdexcept>
#include <string>
+#include <tuple>
#include <vector>
#include <gtest/gtest.h>
@@ -428,6 +431,159 @@
}
}
+TEST(ConfigFileParserTests, ParseI2CInterface)
+{
+ // Test where works: No variables
+ {
+ const json element = R"(
+ {
+ "bus": 2,
+ "address": "0x70"
+ }
+ )"_json;
+ std::map<std::string, std::string> variables{};
+ auto [bus, address] = parseI2CInterface(element, variables);
+ EXPECT_EQ(bus, 2);
+ EXPECT_EQ(address, 0x70);
+ }
+
+ // Test where works: Variables specified
+ {
+ const json element = R"(
+ {
+ "bus": "${bus}",
+ "address": "${address}"
+ }
+ )"_json;
+ std::map<std::string, std::string> variables{{"bus", "3"},
+ {"address", "0x23"}};
+ auto [bus, address] = parseI2CInterface(element, variables);
+ EXPECT_EQ(bus, 3);
+ EXPECT_EQ(address, 0x23);
+ }
+
+ // Test where fails: Element is not an object
+ try
+ {
+ const json element = R"( [ 1, "0x70" ] )"_json;
+ std::map<std::string, std::string> variables{};
+ parseI2CInterface(element, variables);
+ 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: Required bus property not specified
+ try
+ {
+ const json element = R"(
+ {
+ "address": "0x70"
+ }
+ )"_json;
+ std::map<std::string, std::string> variables{};
+ parseI2CInterface(element, variables);
+ ADD_FAILURE() << "Should not have reached this line.";
+ }
+ catch (const std::invalid_argument& e)
+ {
+ EXPECT_STREQ(e.what(), "Required property missing: bus");
+ }
+
+ // Test where fails: Required address property not specified
+ try
+ {
+ const json element = R"(
+ {
+ "bus": 2
+ }
+ )"_json;
+ std::map<std::string, std::string> variables{};
+ parseI2CInterface(element, variables);
+ ADD_FAILURE() << "Should not have reached this line.";
+ }
+ catch (const std::invalid_argument& e)
+ {
+ EXPECT_STREQ(e.what(), "Required property missing: address");
+ }
+
+ // Test where fails: bus value is invalid
+ try
+ {
+ const json element = R"(
+ {
+ "bus": 1.1,
+ "address": "0x70"
+ }
+ )"_json;
+ std::map<std::string, std::string> variables{};
+ parseI2CInterface(element, variables);
+ ADD_FAILURE() << "Should not have reached this line.";
+ }
+ catch (const std::invalid_argument& e)
+ {
+ EXPECT_STREQ(e.what(), "Element is not an integer");
+ }
+
+ // Test where fails: address value is invalid
+ try
+ {
+ const json element = R"(
+ {
+ "bus": 2,
+ "address": 70
+ }
+ )"_json;
+ std::map<std::string, std::string> variables{};
+ parseI2CInterface(element, variables);
+ 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: Invalid property specified
+ try
+ {
+ const json element = R"(
+ {
+ "bus": 2,
+ "address": "0x70",
+ "foo": "bar"
+ }
+ )"_json;
+ std::map<std::string, std::string> variables{};
+ parseI2CInterface(element, variables);
+ 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: Invalid variable value specified
+ try
+ {
+ const json element = R"(
+ {
+ "bus": "${bus}",
+ "address": "${address}"
+ }
+ )"_json;
+ std::map<std::string, std::string> variables{{"bus", "foo"},
+ {"address", "0x23"}};
+ parseI2CInterface(element, variables);
+ 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, ParseRail)
{
// Test where works: Only required properties specified