blob: 77d96504313bb515ae1fa14ac9ead592b304c9b5 [file] [log] [blame]
/**
* Copyright © 2024 IBM Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include "rail.hpp"
#include <nlohmann/json.hpp>
#include <cstdint>
#include <filesystem>
#include <memory>
#include <stdexcept>
#include <string>
#include <vector>
namespace phosphor::power::sequencer::config_file_parser
{
/**
* Standard JSON configuration file directory on the BMC.
*/
extern const std::filesystem::path standardConfigFileDirectory;
/**
* Finds the JSON configuration file for the current system based on the
* specified compatible system types.
*
* This is required when a single BMC firmware image supports multiple system
* types and some system types require different configuration files.
*
* The compatible system types must be ordered from most to least specific.
* Example:
* - com.acme.Hardware.Chassis.Model.MegaServer4CPU
* - com.acme.Hardware.Chassis.Model.MegaServer
* - com.acme.Hardware.Chassis.Model.Server
*
* Throws an exception if an error occurs.
*
* @param compatibleSystemTypes compatible system types for the current system
* ordered from most to least specific
* @param configFileDir directory containing configuration files
* @return path to the JSON configuration file, or an empty path if none was
* found
*/
std::filesystem::path find(
const std::vector<std::string>& compatibleSystemTypes,
const std::filesystem::path& configFileDir = standardConfigFileDirectory);
/**
* Parses the specified JSON configuration file.
*
* Returns the corresponding C++ Rail objects.
*
* Throws a ConfigFileParserError if an error occurs.
*
* @param pathName configuration file path name
* @return vector of Rail objects
*/
std::vector<std::unique_ptr<Rail>> parse(const std::filesystem::path& pathName);
/*
* Internal implementation details for parse()
*/
namespace internal
{
/**
* Returns the specified property of the specified JSON element.
*
* Throws an invalid_argument exception if the property does not exist.
*
* @param element JSON element
* @param property property name
*/
#pragma GCC diagnostic push
#if __GNUC__ == 13
#pragma GCC diagnostic ignored "-Wdangling-reference"
#endif
inline const nlohmann::json& getRequiredProperty(const nlohmann::json& element,
const std::string& property)
{
auto it = element.find(property);
if (it == element.end())
{
throw std::invalid_argument{"Required property missing: " + property};
}
return *it;
}
#pragma GCC diagnostic pop
/**
* Parses a JSON element containing a boolean.
*
* Returns the corresponding C++ boolean value.
*
* Throws an exception if parsing fails.
*
* @param element JSON element
* @return boolean value
*/
inline bool parseBoolean(const nlohmann::json& element)
{
// Verify element contains a boolean
if (!element.is_boolean())
{
throw std::invalid_argument{"Element is not a boolean"};
}
return element.get<bool>();
}
/**
* Parses a JSON element containing a GPIO.
*
* Returns the corresponding C++ GPIO object.
*
* Throws an exception if parsing fails.
*
* @param element JSON element
* @return GPIO object
*/
GPIO parseGPIO(const nlohmann::json& element);
/**
* Parses a JSON element containing a rail.
*
* Returns the corresponding C++ Rail object.
*
* Throws an exception if parsing fails.
*
* @param element JSON element
* @return Rail object
*/
std::unique_ptr<Rail> parseRail(const nlohmann::json& element);
/**
* Parses a JSON element containing an array of rails.
*
* Returns the corresponding C++ Rail objects.
*
* Throws an exception if parsing fails.
*
* @param element JSON element
* @return vector of Rail objects
*/
std::vector<std::unique_ptr<Rail>>
parseRailArray(const nlohmann::json& element);
/**
* Parses the JSON root element of the entire configuration file.
*
* Returns the corresponding C++ Rail objects.
*
* Throws an exception if parsing fails.
*
* @param element JSON element
* @return vector of Rail objects
*/
std::vector<std::unique_ptr<Rail>> parseRoot(const nlohmann::json& element);
/**
* Parses a JSON element containing a string.
*
* Returns the corresponding C++ string.
*
* Throws an exception if parsing fails.
*
* @param element JSON element
* @param isEmptyValid indicates whether an empty string value is valid
* @return string value
*/
inline std::string parseString(const nlohmann::json& element,
bool isEmptyValid = false)
{
if (!element.is_string())
{
throw std::invalid_argument{"Element is not a string"};
}
std::string value = element.get<std::string>();
if (value.empty() && !isEmptyValid)
{
throw std::invalid_argument{"Element contains an empty string"};
}
return value;
}
/**
* Parses a JSON element containing an 8-bit unsigned integer.
*
* Returns the corresponding C++ uint8_t value.
*
* Throws an exception if parsing fails.
*
* @param element JSON element
* @return uint8_t value
*/
inline uint8_t parseUint8(const nlohmann::json& element)
{
// Verify element contains an integer
if (!element.is_number_integer())
{
throw std::invalid_argument{"Element is not an integer"};
}
int value = element.get<int>();
if ((value < 0) || (value > UINT8_MAX))
{
throw std::invalid_argument{"Element is not an 8-bit unsigned integer"};
}
return static_cast<uint8_t>(value);
}
/**
* Parses a JSON element containing an unsigned integer.
*
* Returns the corresponding C++ unsigned int value.
*
* Throws an exception if parsing fails.
*
* @param element JSON element
* @return unsigned int value
*/
inline unsigned int parseUnsignedInteger(const nlohmann::json& element)
{
// Verify element contains an unsigned integer
if (!element.is_number_unsigned())
{
throw std::invalid_argument{"Element is not an unsigned integer"};
}
return element.get<unsigned int>();
}
/**
* Verifies that the specified JSON element is a JSON array.
*
* Throws an invalid_argument exception if the element is not an array.
*
* @param element JSON element
*/
inline void verifyIsArray(const nlohmann::json& element)
{
if (!element.is_array())
{
throw std::invalid_argument{"Element is not an array"};
}
}
/**
* Verifies that the specified JSON element is a JSON object.
*
* Throws an invalid_argument exception if the element is not an object.
*
* @param element JSON element
*/
inline void verifyIsObject(const nlohmann::json& element)
{
if (!element.is_object())
{
throw std::invalid_argument{"Element is not an object"};
}
}
/**
* Verifies that the specified JSON element contains the expected number of
* properties.
*
* Throws an invalid_argument exception if the element contains a different
* number of properties. This indicates the element contains an invalid
* property.
*
* @param element JSON element
* @param expectedCount expected number of properties in element
*/
inline void verifyPropertyCount(const nlohmann::json& element,
unsigned int expectedCount)
{
if (element.size() != expectedCount)
{
throw std::invalid_argument{"Element contains an invalid property"};
}
}
} // namespace internal
} // namespace phosphor::power::sequencer::config_file_parser