16a957f6fSShawn McCarney /**
26a957f6fSShawn McCarney * Copyright © 2024 IBM Corporation
36a957f6fSShawn McCarney *
46a957f6fSShawn McCarney * Licensed under the Apache License, Version 2.0 (the "License");
56a957f6fSShawn McCarney * you may not use this file except in compliance with the License.
66a957f6fSShawn McCarney * You may obtain a copy of the License at
76a957f6fSShawn McCarney *
86a957f6fSShawn McCarney * http://www.apache.org/licenses/LICENSE-2.0
96a957f6fSShawn McCarney *
106a957f6fSShawn McCarney * Unless required by applicable law or agreed to in writing, software
116a957f6fSShawn McCarney * distributed under the License is distributed on an "AS IS" BASIS,
126a957f6fSShawn McCarney * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136a957f6fSShawn McCarney * See the License for the specific language governing permissions and
146a957f6fSShawn McCarney * limitations under the License.
156a957f6fSShawn McCarney */
166a957f6fSShawn McCarney #pragma once
176a957f6fSShawn McCarney
186a957f6fSShawn McCarney #include "rail.hpp"
196a957f6fSShawn McCarney
206a957f6fSShawn McCarney #include <nlohmann/json.hpp>
216a957f6fSShawn McCarney
226a957f6fSShawn McCarney #include <cstdint>
236a957f6fSShawn McCarney #include <filesystem>
24906cc3f3SShawn McCarney #include <memory>
256a957f6fSShawn McCarney #include <stdexcept>
266a957f6fSShawn McCarney #include <string>
276a957f6fSShawn McCarney #include <vector>
286a957f6fSShawn McCarney
296a957f6fSShawn McCarney namespace phosphor::power::sequencer::config_file_parser
306a957f6fSShawn McCarney {
316a957f6fSShawn McCarney
326a957f6fSShawn McCarney /**
33e9144ab4SShawn McCarney * Standard JSON configuration file directory on the BMC.
34e9144ab4SShawn McCarney */
35e9144ab4SShawn McCarney extern const std::filesystem::path standardConfigFileDirectory;
36e9144ab4SShawn McCarney
37e9144ab4SShawn McCarney /**
38e9144ab4SShawn McCarney * Finds the JSON configuration file for the current system based on the
39e9144ab4SShawn McCarney * specified compatible system types.
40e9144ab4SShawn McCarney *
41e9144ab4SShawn McCarney * This is required when a single BMC firmware image supports multiple system
42e9144ab4SShawn McCarney * types and some system types require different configuration files.
43e9144ab4SShawn McCarney *
44e9144ab4SShawn McCarney * The compatible system types must be ordered from most to least specific.
45e9144ab4SShawn McCarney * Example:
46e9144ab4SShawn McCarney * - com.acme.Hardware.Chassis.Model.MegaServer4CPU
47e9144ab4SShawn McCarney * - com.acme.Hardware.Chassis.Model.MegaServer
48e9144ab4SShawn McCarney * - com.acme.Hardware.Chassis.Model.Server
49e9144ab4SShawn McCarney *
50e9144ab4SShawn McCarney * Throws an exception if an error occurs.
51e9144ab4SShawn McCarney *
52e9144ab4SShawn McCarney * @param compatibleSystemTypes compatible system types for the current system
53e9144ab4SShawn McCarney * ordered from most to least specific
54e9144ab4SShawn McCarney * @param configFileDir directory containing configuration files
55e9144ab4SShawn McCarney * @return path to the JSON configuration file, or an empty path if none was
56e9144ab4SShawn McCarney * found
57e9144ab4SShawn McCarney */
58e9144ab4SShawn McCarney std::filesystem::path find(
59e9144ab4SShawn McCarney const std::vector<std::string>& compatibleSystemTypes,
60e9144ab4SShawn McCarney const std::filesystem::path& configFileDir = standardConfigFileDirectory);
61e9144ab4SShawn McCarney
62e9144ab4SShawn McCarney /**
636a957f6fSShawn McCarney * Parses the specified JSON configuration file.
646a957f6fSShawn McCarney *
656a957f6fSShawn McCarney * Returns the corresponding C++ Rail objects.
666a957f6fSShawn McCarney *
676a957f6fSShawn McCarney * Throws a ConfigFileParserError if an error occurs.
686a957f6fSShawn McCarney *
696a957f6fSShawn McCarney * @param pathName configuration file path name
706a957f6fSShawn McCarney * @return vector of Rail objects
716a957f6fSShawn McCarney */
726a957f6fSShawn McCarney std::vector<std::unique_ptr<Rail>> parse(const std::filesystem::path& pathName);
736a957f6fSShawn McCarney
746a957f6fSShawn McCarney /*
756a957f6fSShawn McCarney * Internal implementation details for parse()
766a957f6fSShawn McCarney */
776a957f6fSShawn McCarney namespace internal
786a957f6fSShawn McCarney {
796a957f6fSShawn McCarney
806a957f6fSShawn McCarney /**
816a957f6fSShawn McCarney * Returns the specified property of the specified JSON element.
826a957f6fSShawn McCarney *
836a957f6fSShawn McCarney * Throws an invalid_argument exception if the property does not exist.
846a957f6fSShawn McCarney *
856a957f6fSShawn McCarney * @param element JSON element
866a957f6fSShawn McCarney * @param property property name
876a957f6fSShawn McCarney */
886a957f6fSShawn McCarney #pragma GCC diagnostic push
89b9d4fb71SAndrew Geissler #if __GNUC__ >= 13
906a957f6fSShawn McCarney #pragma GCC diagnostic ignored "-Wdangling-reference"
916a957f6fSShawn McCarney #endif
getRequiredProperty(const nlohmann::json & element,const std::string & property)926a957f6fSShawn McCarney inline const nlohmann::json& getRequiredProperty(const nlohmann::json& element,
936a957f6fSShawn McCarney const std::string& property)
946a957f6fSShawn McCarney {
956a957f6fSShawn McCarney auto it = element.find(property);
966a957f6fSShawn McCarney if (it == element.end())
976a957f6fSShawn McCarney {
986a957f6fSShawn McCarney throw std::invalid_argument{"Required property missing: " + property};
996a957f6fSShawn McCarney }
1006a957f6fSShawn McCarney return *it;
1016a957f6fSShawn McCarney }
1026a957f6fSShawn McCarney #pragma GCC diagnostic pop
1036a957f6fSShawn McCarney
1046a957f6fSShawn McCarney /**
1056a957f6fSShawn McCarney * Parses a JSON element containing a boolean.
1066a957f6fSShawn McCarney *
1076a957f6fSShawn McCarney * Returns the corresponding C++ boolean value.
1086a957f6fSShawn McCarney *
1096a957f6fSShawn McCarney * Throws an exception if parsing fails.
1106a957f6fSShawn McCarney *
1116a957f6fSShawn McCarney * @param element JSON element
1126a957f6fSShawn McCarney * @return boolean value
1136a957f6fSShawn McCarney */
parseBoolean(const nlohmann::json & element)1146a957f6fSShawn McCarney inline bool parseBoolean(const nlohmann::json& element)
1156a957f6fSShawn McCarney {
1166a957f6fSShawn McCarney // Verify element contains a boolean
1176a957f6fSShawn McCarney if (!element.is_boolean())
1186a957f6fSShawn McCarney {
1196a957f6fSShawn McCarney throw std::invalid_argument{"Element is not a boolean"};
1206a957f6fSShawn McCarney }
1216a957f6fSShawn McCarney return element.get<bool>();
1226a957f6fSShawn McCarney }
1236a957f6fSShawn McCarney
1246a957f6fSShawn McCarney /**
1256a957f6fSShawn McCarney * Parses a JSON element containing a GPIO.
1266a957f6fSShawn McCarney *
1276a957f6fSShawn McCarney * Returns the corresponding C++ GPIO object.
1286a957f6fSShawn McCarney *
1296a957f6fSShawn McCarney * Throws an exception if parsing fails.
1306a957f6fSShawn McCarney *
1316a957f6fSShawn McCarney * @param element JSON element
1326a957f6fSShawn McCarney * @return GPIO object
1336a957f6fSShawn McCarney */
1346a957f6fSShawn McCarney GPIO parseGPIO(const nlohmann::json& element);
1356a957f6fSShawn McCarney
1366a957f6fSShawn McCarney /**
1376a957f6fSShawn McCarney * Parses a JSON element containing a rail.
1386a957f6fSShawn McCarney *
1396a957f6fSShawn McCarney * Returns the corresponding C++ Rail object.
1406a957f6fSShawn McCarney *
1416a957f6fSShawn McCarney * Throws an exception if parsing fails.
1426a957f6fSShawn McCarney *
1436a957f6fSShawn McCarney * @param element JSON element
1446a957f6fSShawn McCarney * @return Rail object
1456a957f6fSShawn McCarney */
1466a957f6fSShawn McCarney std::unique_ptr<Rail> parseRail(const nlohmann::json& element);
1476a957f6fSShawn McCarney
1486a957f6fSShawn McCarney /**
1496a957f6fSShawn McCarney * Parses a JSON element containing an array of rails.
1506a957f6fSShawn McCarney *
1516a957f6fSShawn McCarney * Returns the corresponding C++ Rail objects.
1526a957f6fSShawn McCarney *
1536a957f6fSShawn McCarney * Throws an exception if parsing fails.
1546a957f6fSShawn McCarney *
1556a957f6fSShawn McCarney * @param element JSON element
1566a957f6fSShawn McCarney * @return vector of Rail objects
1576a957f6fSShawn McCarney */
158*92261f88SPatrick Williams std::vector<std::unique_ptr<Rail>> parseRailArray(
159*92261f88SPatrick Williams const nlohmann::json& element);
1606a957f6fSShawn McCarney
1616a957f6fSShawn McCarney /**
1626a957f6fSShawn McCarney * Parses the JSON root element of the entire configuration file.
1636a957f6fSShawn McCarney *
1646a957f6fSShawn McCarney * Returns the corresponding C++ Rail objects.
1656a957f6fSShawn McCarney *
1666a957f6fSShawn McCarney * Throws an exception if parsing fails.
1676a957f6fSShawn McCarney *
1686a957f6fSShawn McCarney * @param element JSON element
1696a957f6fSShawn McCarney * @return vector of Rail objects
1706a957f6fSShawn McCarney */
1716a957f6fSShawn McCarney std::vector<std::unique_ptr<Rail>> parseRoot(const nlohmann::json& element);
1726a957f6fSShawn McCarney
1736a957f6fSShawn McCarney /**
1746a957f6fSShawn McCarney * Parses a JSON element containing a string.
1756a957f6fSShawn McCarney *
1766a957f6fSShawn McCarney * Returns the corresponding C++ string.
1776a957f6fSShawn McCarney *
1786a957f6fSShawn McCarney * Throws an exception if parsing fails.
1796a957f6fSShawn McCarney *
1806a957f6fSShawn McCarney * @param element JSON element
1816a957f6fSShawn McCarney * @param isEmptyValid indicates whether an empty string value is valid
1826a957f6fSShawn McCarney * @return string value
1836a957f6fSShawn McCarney */
parseString(const nlohmann::json & element,bool isEmptyValid=false)1846a957f6fSShawn McCarney inline std::string parseString(const nlohmann::json& element,
1856a957f6fSShawn McCarney bool isEmptyValid = false)
1866a957f6fSShawn McCarney {
1876a957f6fSShawn McCarney if (!element.is_string())
1886a957f6fSShawn McCarney {
1896a957f6fSShawn McCarney throw std::invalid_argument{"Element is not a string"};
1906a957f6fSShawn McCarney }
1916a957f6fSShawn McCarney std::string value = element.get<std::string>();
1926a957f6fSShawn McCarney if (value.empty() && !isEmptyValid)
1936a957f6fSShawn McCarney {
1946a957f6fSShawn McCarney throw std::invalid_argument{"Element contains an empty string"};
1956a957f6fSShawn McCarney }
1966a957f6fSShawn McCarney return value;
1976a957f6fSShawn McCarney }
1986a957f6fSShawn McCarney
1996a957f6fSShawn McCarney /**
2006a957f6fSShawn McCarney * Parses a JSON element containing an 8-bit unsigned integer.
2016a957f6fSShawn McCarney *
2026a957f6fSShawn McCarney * Returns the corresponding C++ uint8_t value.
2036a957f6fSShawn McCarney *
2046a957f6fSShawn McCarney * Throws an exception if parsing fails.
2056a957f6fSShawn McCarney *
2066a957f6fSShawn McCarney * @param element JSON element
2076a957f6fSShawn McCarney * @return uint8_t value
2086a957f6fSShawn McCarney */
parseUint8(const nlohmann::json & element)2096a957f6fSShawn McCarney inline uint8_t parseUint8(const nlohmann::json& element)
2106a957f6fSShawn McCarney {
2116a957f6fSShawn McCarney // Verify element contains an integer
2126a957f6fSShawn McCarney if (!element.is_number_integer())
2136a957f6fSShawn McCarney {
2146a957f6fSShawn McCarney throw std::invalid_argument{"Element is not an integer"};
2156a957f6fSShawn McCarney }
2166a957f6fSShawn McCarney int value = element.get<int>();
2176a957f6fSShawn McCarney if ((value < 0) || (value > UINT8_MAX))
2186a957f6fSShawn McCarney {
2196a957f6fSShawn McCarney throw std::invalid_argument{"Element is not an 8-bit unsigned integer"};
2206a957f6fSShawn McCarney }
2216a957f6fSShawn McCarney return static_cast<uint8_t>(value);
2226a957f6fSShawn McCarney }
2236a957f6fSShawn McCarney
2246a957f6fSShawn McCarney /**
2256a957f6fSShawn McCarney * Parses a JSON element containing an unsigned integer.
2266a957f6fSShawn McCarney *
2276a957f6fSShawn McCarney * Returns the corresponding C++ unsigned int value.
2286a957f6fSShawn McCarney *
2296a957f6fSShawn McCarney * Throws an exception if parsing fails.
2306a957f6fSShawn McCarney *
2316a957f6fSShawn McCarney * @param element JSON element
2326a957f6fSShawn McCarney * @return unsigned int value
2336a957f6fSShawn McCarney */
parseUnsignedInteger(const nlohmann::json & element)2346a957f6fSShawn McCarney inline unsigned int parseUnsignedInteger(const nlohmann::json& element)
2356a957f6fSShawn McCarney {
2366a957f6fSShawn McCarney // Verify element contains an unsigned integer
2376a957f6fSShawn McCarney if (!element.is_number_unsigned())
2386a957f6fSShawn McCarney {
2396a957f6fSShawn McCarney throw std::invalid_argument{"Element is not an unsigned integer"};
2406a957f6fSShawn McCarney }
2416a957f6fSShawn McCarney return element.get<unsigned int>();
2426a957f6fSShawn McCarney }
2436a957f6fSShawn McCarney
2446a957f6fSShawn McCarney /**
2456a957f6fSShawn McCarney * Verifies that the specified JSON element is a JSON array.
2466a957f6fSShawn McCarney *
2476a957f6fSShawn McCarney * Throws an invalid_argument exception if the element is not an array.
2486a957f6fSShawn McCarney *
2496a957f6fSShawn McCarney * @param element JSON element
2506a957f6fSShawn McCarney */
verifyIsArray(const nlohmann::json & element)2516a957f6fSShawn McCarney inline void verifyIsArray(const nlohmann::json& element)
2526a957f6fSShawn McCarney {
2536a957f6fSShawn McCarney if (!element.is_array())
2546a957f6fSShawn McCarney {
2556a957f6fSShawn McCarney throw std::invalid_argument{"Element is not an array"};
2566a957f6fSShawn McCarney }
2576a957f6fSShawn McCarney }
2586a957f6fSShawn McCarney
2596a957f6fSShawn McCarney /**
2606a957f6fSShawn McCarney * Verifies that the specified JSON element is a JSON object.
2616a957f6fSShawn McCarney *
2626a957f6fSShawn McCarney * Throws an invalid_argument exception if the element is not an object.
2636a957f6fSShawn McCarney *
2646a957f6fSShawn McCarney * @param element JSON element
2656a957f6fSShawn McCarney */
verifyIsObject(const nlohmann::json & element)2666a957f6fSShawn McCarney inline void verifyIsObject(const nlohmann::json& element)
2676a957f6fSShawn McCarney {
2686a957f6fSShawn McCarney if (!element.is_object())
2696a957f6fSShawn McCarney {
2706a957f6fSShawn McCarney throw std::invalid_argument{"Element is not an object"};
2716a957f6fSShawn McCarney }
2726a957f6fSShawn McCarney }
2736a957f6fSShawn McCarney
2746a957f6fSShawn McCarney /**
2756a957f6fSShawn McCarney * Verifies that the specified JSON element contains the expected number of
2766a957f6fSShawn McCarney * properties.
2776a957f6fSShawn McCarney *
2786a957f6fSShawn McCarney * Throws an invalid_argument exception if the element contains a different
2796a957f6fSShawn McCarney * number of properties. This indicates the element contains an invalid
2806a957f6fSShawn McCarney * property.
2816a957f6fSShawn McCarney *
2826a957f6fSShawn McCarney * @param element JSON element
2836a957f6fSShawn McCarney * @param expectedCount expected number of properties in element
2846a957f6fSShawn McCarney */
verifyPropertyCount(const nlohmann::json & element,unsigned int expectedCount)2856a957f6fSShawn McCarney inline void verifyPropertyCount(const nlohmann::json& element,
2866a957f6fSShawn McCarney unsigned int expectedCount)
2876a957f6fSShawn McCarney {
2886a957f6fSShawn McCarney if (element.size() != expectedCount)
2896a957f6fSShawn McCarney {
2906a957f6fSShawn McCarney throw std::invalid_argument{"Element contains an invalid property"};
2916a957f6fSShawn McCarney }
2926a957f6fSShawn McCarney }
2936a957f6fSShawn McCarney
2946a957f6fSShawn McCarney } // namespace internal
2956a957f6fSShawn McCarney
2966a957f6fSShawn McCarney } // namespace phosphor::power::sequencer::config_file_parser
297