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
89*b9d4fb71SAndrew 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  */
1586a957f6fSShawn McCarney std::vector<std::unique_ptr<Rail>>
1596a957f6fSShawn McCarney     parseRailArray(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