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
176a957f6fSShawn McCarney #include "config_file_parser.hpp"
186a957f6fSShawn McCarney
196a957f6fSShawn McCarney #include "config_file_parser_error.hpp"
206a957f6fSShawn McCarney
216a957f6fSShawn McCarney #include <exception>
226a957f6fSShawn McCarney #include <fstream>
236a957f6fSShawn McCarney #include <optional>
246a957f6fSShawn McCarney
256a957f6fSShawn McCarney using json = nlohmann::json;
26e9144ab4SShawn McCarney namespace fs = std::filesystem;
276a957f6fSShawn McCarney
286a957f6fSShawn McCarney namespace phosphor::power::sequencer::config_file_parser
296a957f6fSShawn McCarney {
306a957f6fSShawn McCarney
31e9144ab4SShawn McCarney const std::filesystem::path standardConfigFileDirectory{
32e9144ab4SShawn McCarney "/usr/share/phosphor-power-sequencer"};
33e9144ab4SShawn McCarney
find(const std::vector<std::string> & compatibleSystemTypes,const std::filesystem::path & configFileDir)34*92261f88SPatrick Williams std::filesystem::path find(
35*92261f88SPatrick Williams const std::vector<std::string>& compatibleSystemTypes,
36e9144ab4SShawn McCarney const std::filesystem::path& configFileDir)
37e9144ab4SShawn McCarney {
38e9144ab4SShawn McCarney fs::path pathName, possiblePath;
39e9144ab4SShawn McCarney std::string fileName;
40e9144ab4SShawn McCarney
41e9144ab4SShawn McCarney for (const std::string& systemType : compatibleSystemTypes)
42e9144ab4SShawn McCarney {
43e9144ab4SShawn McCarney // Look for file name that is entire system type + ".json"
44e9144ab4SShawn McCarney // Example: com.acme.Hardware.Chassis.Model.MegaServer.json
45e9144ab4SShawn McCarney fileName = systemType + ".json";
46e9144ab4SShawn McCarney possiblePath = configFileDir / fileName;
47e9144ab4SShawn McCarney if (fs::is_regular_file(possiblePath))
48e9144ab4SShawn McCarney {
49e9144ab4SShawn McCarney pathName = possiblePath;
50e9144ab4SShawn McCarney break;
51e9144ab4SShawn McCarney }
52e9144ab4SShawn McCarney
53e9144ab4SShawn McCarney // Look for file name that is last node of system type + ".json"
54e9144ab4SShawn McCarney // Example: MegaServer.json
55e9144ab4SShawn McCarney std::string::size_type pos = systemType.rfind('.');
56e9144ab4SShawn McCarney if ((pos != std::string::npos) && ((systemType.size() - pos) > 1))
57e9144ab4SShawn McCarney {
58e9144ab4SShawn McCarney fileName = systemType.substr(pos + 1) + ".json";
59e9144ab4SShawn McCarney possiblePath = configFileDir / fileName;
60e9144ab4SShawn McCarney if (fs::is_regular_file(possiblePath))
61e9144ab4SShawn McCarney {
62e9144ab4SShawn McCarney pathName = possiblePath;
63e9144ab4SShawn McCarney break;
64e9144ab4SShawn McCarney }
65e9144ab4SShawn McCarney }
66e9144ab4SShawn McCarney }
67e9144ab4SShawn McCarney
68e9144ab4SShawn McCarney return pathName;
69e9144ab4SShawn McCarney }
70e9144ab4SShawn McCarney
parse(const std::filesystem::path & pathName)716a957f6fSShawn McCarney std::vector<std::unique_ptr<Rail>> parse(const std::filesystem::path& pathName)
726a957f6fSShawn McCarney {
736a957f6fSShawn McCarney try
746a957f6fSShawn McCarney {
756a957f6fSShawn McCarney // Use standard JSON parser to create tree of JSON elements
766a957f6fSShawn McCarney std::ifstream file{pathName};
776a957f6fSShawn McCarney json rootElement = json::parse(file);
786a957f6fSShawn McCarney
796a957f6fSShawn McCarney // Parse tree of JSON elements and return corresponding C++ objects
806a957f6fSShawn McCarney return internal::parseRoot(rootElement);
816a957f6fSShawn McCarney }
826a957f6fSShawn McCarney catch (const std::exception& e)
836a957f6fSShawn McCarney {
846a957f6fSShawn McCarney throw ConfigFileParserError{pathName, e.what()};
856a957f6fSShawn McCarney }
866a957f6fSShawn McCarney }
876a957f6fSShawn McCarney
886a957f6fSShawn McCarney namespace internal
896a957f6fSShawn McCarney {
906a957f6fSShawn McCarney
parseGPIO(const json & element)916a957f6fSShawn McCarney GPIO parseGPIO(const json& element)
926a957f6fSShawn McCarney {
936a957f6fSShawn McCarney verifyIsObject(element);
946a957f6fSShawn McCarney unsigned int propertyCount{0};
956a957f6fSShawn McCarney
966a957f6fSShawn McCarney // Required line property
976a957f6fSShawn McCarney const json& lineElement = getRequiredProperty(element, "line");
986a957f6fSShawn McCarney unsigned int line = parseUnsignedInteger(lineElement);
996a957f6fSShawn McCarney ++propertyCount;
1006a957f6fSShawn McCarney
1016a957f6fSShawn McCarney // Optional active_low property
1026a957f6fSShawn McCarney bool activeLow{false};
1036a957f6fSShawn McCarney auto activeLowIt = element.find("active_low");
1046a957f6fSShawn McCarney if (activeLowIt != element.end())
1056a957f6fSShawn McCarney {
1066a957f6fSShawn McCarney activeLow = parseBoolean(*activeLowIt);
1076a957f6fSShawn McCarney ++propertyCount;
1086a957f6fSShawn McCarney }
1096a957f6fSShawn McCarney
1106a957f6fSShawn McCarney // Verify no invalid properties exist
1116a957f6fSShawn McCarney verifyPropertyCount(element, propertyCount);
1126a957f6fSShawn McCarney
1136a957f6fSShawn McCarney return GPIO(line, activeLow);
1146a957f6fSShawn McCarney }
1156a957f6fSShawn McCarney
parseRail(const json & element)1166a957f6fSShawn McCarney std::unique_ptr<Rail> parseRail(const json& element)
1176a957f6fSShawn McCarney {
1186a957f6fSShawn McCarney verifyIsObject(element);
1196a957f6fSShawn McCarney unsigned int propertyCount{0};
1206a957f6fSShawn McCarney
1216a957f6fSShawn McCarney // Required name property
1226a957f6fSShawn McCarney const json& nameElement = getRequiredProperty(element, "name");
1236a957f6fSShawn McCarney std::string name = parseString(nameElement);
1246a957f6fSShawn McCarney ++propertyCount;
1256a957f6fSShawn McCarney
1266a957f6fSShawn McCarney // Optional presence property
1276a957f6fSShawn McCarney std::optional<std::string> presence{};
1286a957f6fSShawn McCarney auto presenceIt = element.find("presence");
1296a957f6fSShawn McCarney if (presenceIt != element.end())
1306a957f6fSShawn McCarney {
1316a957f6fSShawn McCarney presence = parseString(*presenceIt);
1326a957f6fSShawn McCarney ++propertyCount;
1336a957f6fSShawn McCarney }
1346a957f6fSShawn McCarney
1356a957f6fSShawn McCarney // Optional page property
1366a957f6fSShawn McCarney std::optional<uint8_t> page{};
1376a957f6fSShawn McCarney auto pageIt = element.find("page");
1386a957f6fSShawn McCarney if (pageIt != element.end())
1396a957f6fSShawn McCarney {
1406a957f6fSShawn McCarney page = parseUint8(*pageIt);
1416a957f6fSShawn McCarney ++propertyCount;
1426a957f6fSShawn McCarney }
1436a957f6fSShawn McCarney
14416e493afSShawn McCarney // Optional is_power_supply_rail property
14516e493afSShawn McCarney bool isPowerSupplyRail{false};
14616e493afSShawn McCarney auto isPowerSupplyRailIt = element.find("is_power_supply_rail");
14716e493afSShawn McCarney if (isPowerSupplyRailIt != element.end())
14816e493afSShawn McCarney {
14916e493afSShawn McCarney isPowerSupplyRail = parseBoolean(*isPowerSupplyRailIt);
15016e493afSShawn McCarney ++propertyCount;
15116e493afSShawn McCarney }
15216e493afSShawn McCarney
1536a957f6fSShawn McCarney // Optional check_status_vout property
1546a957f6fSShawn McCarney bool checkStatusVout{false};
1556a957f6fSShawn McCarney auto checkStatusVoutIt = element.find("check_status_vout");
1566a957f6fSShawn McCarney if (checkStatusVoutIt != element.end())
1576a957f6fSShawn McCarney {
1586a957f6fSShawn McCarney checkStatusVout = parseBoolean(*checkStatusVoutIt);
1596a957f6fSShawn McCarney ++propertyCount;
1606a957f6fSShawn McCarney }
1616a957f6fSShawn McCarney
1629ec0d43dSShawn McCarney // Optional compare_voltage_to_limit property
1639ec0d43dSShawn McCarney bool compareVoltageToLimit{false};
1649ec0d43dSShawn McCarney auto compareVoltageToLimitIt = element.find("compare_voltage_to_limit");
1659ec0d43dSShawn McCarney if (compareVoltageToLimitIt != element.end())
1666a957f6fSShawn McCarney {
1679ec0d43dSShawn McCarney compareVoltageToLimit = parseBoolean(*compareVoltageToLimitIt);
1686a957f6fSShawn McCarney ++propertyCount;
1696a957f6fSShawn McCarney }
1706a957f6fSShawn McCarney
1716a957f6fSShawn McCarney // Optional gpio property
1726a957f6fSShawn McCarney std::optional<GPIO> gpio{};
1736a957f6fSShawn McCarney auto gpioIt = element.find("gpio");
1746a957f6fSShawn McCarney if (gpioIt != element.end())
1756a957f6fSShawn McCarney {
1766a957f6fSShawn McCarney gpio = parseGPIO(*gpioIt);
1776a957f6fSShawn McCarney ++propertyCount;
1786a957f6fSShawn McCarney }
1796a957f6fSShawn McCarney
1809ec0d43dSShawn McCarney // If check_status_vout or compare_voltage_to_limit property is true, the
1819ec0d43dSShawn McCarney // page property is required; verify page was specified
1829ec0d43dSShawn McCarney if ((checkStatusVout || compareVoltageToLimit) && !page.has_value())
1836a957f6fSShawn McCarney {
1846a957f6fSShawn McCarney throw std::invalid_argument{"Required property missing: page"};
1856a957f6fSShawn McCarney }
1866a957f6fSShawn McCarney
1876a957f6fSShawn McCarney // Verify no invalid properties exist
1886a957f6fSShawn McCarney verifyPropertyCount(element, propertyCount);
1896a957f6fSShawn McCarney
19016e493afSShawn McCarney return std::make_unique<Rail>(name, presence, page, isPowerSupplyRail,
1919ec0d43dSShawn McCarney checkStatusVout, compareVoltageToLimit, gpio);
1926a957f6fSShawn McCarney }
1936a957f6fSShawn McCarney
parseRailArray(const json & element)1946a957f6fSShawn McCarney std::vector<std::unique_ptr<Rail>> parseRailArray(const json& element)
1956a957f6fSShawn McCarney {
1966a957f6fSShawn McCarney verifyIsArray(element);
1976a957f6fSShawn McCarney std::vector<std::unique_ptr<Rail>> rails;
1986a957f6fSShawn McCarney for (auto& railElement : element)
1996a957f6fSShawn McCarney {
2006a957f6fSShawn McCarney rails.emplace_back(parseRail(railElement));
2016a957f6fSShawn McCarney }
2026a957f6fSShawn McCarney return rails;
2036a957f6fSShawn McCarney }
2046a957f6fSShawn McCarney
parseRoot(const json & element)2056a957f6fSShawn McCarney std::vector<std::unique_ptr<Rail>> parseRoot(const json& element)
2066a957f6fSShawn McCarney {
2076a957f6fSShawn McCarney verifyIsObject(element);
2086a957f6fSShawn McCarney unsigned int propertyCount{0};
2096a957f6fSShawn McCarney
2106a957f6fSShawn McCarney // Required rails property
2116a957f6fSShawn McCarney const json& railsElement = getRequiredProperty(element, "rails");
2126a957f6fSShawn McCarney std::vector<std::unique_ptr<Rail>> rails = parseRailArray(railsElement);
2136a957f6fSShawn McCarney ++propertyCount;
2146a957f6fSShawn McCarney
2156a957f6fSShawn McCarney // Verify no invalid properties exist
2166a957f6fSShawn McCarney verifyPropertyCount(element, propertyCount);
2176a957f6fSShawn McCarney
2186a957f6fSShawn McCarney return rails;
2196a957f6fSShawn McCarney }
2206a957f6fSShawn McCarney
2216a957f6fSShawn McCarney } // namespace internal
2226a957f6fSShawn McCarney
2236a957f6fSShawn McCarney } // namespace phosphor::power::sequencer::config_file_parser
224