| #pragma once | 
 | #include "additional_data.hpp" | 
 |  | 
 | #include <nlohmann/json.hpp> | 
 |  | 
 | #include <filesystem> | 
 | #include <optional> | 
 | #include <string> | 
 | #include <vector> | 
 |  | 
 | namespace openpower | 
 | { | 
 | namespace pels | 
 | { | 
 | namespace message | 
 | { | 
 |  | 
 | constexpr auto registryFileName = "message_registry.json"; | 
 | enum class LookupType | 
 | { | 
 |     name = 0, | 
 |     reasonCode = 1 | 
 | }; | 
 |  | 
 | /** | 
 |  * @brief A possible severity/system type combination | 
 |  * | 
 |  * If there is no system type defined for this entry, | 
 |  * then the system field will be empty. | 
 |  */ | 
 | struct RegistrySeverity | 
 | { | 
 |     std::string system; | 
 |     uint8_t severity; | 
 | }; | 
 |  | 
 | /** | 
 |  * @brief Represents the Documentation related fields in the message registry. | 
 |  *        It is part of the 'Entry' structure that will be filled in when | 
 |  *        an error is looked up in the registry. | 
 |  * | 
 |  * If a field is wrapped by std::optional, it means the field is | 
 |  * optional in the JSON and higher level code knows how to handle it. | 
 |  */ | 
 | struct DOC | 
 | { | 
 |     /** | 
 |      * @brief Description of error | 
 |      */ | 
 |     std::string description; | 
 |  | 
 |     /** | 
 |      * @brief Error message field | 
 |      */ | 
 |     std::string message; | 
 |  | 
 |     /** | 
 |      * @brief An optional vector of SRC word 6-9 to use as the source of the | 
 |      *        numeric arguments that will be substituted into any placeholder | 
 |      *        in the Message field. | 
 |      */ | 
 |     std::optional<std::vector<std::string>> messageArgSources; | 
 | }; | 
 |  | 
 | /** | 
 |  * @brief Represents the SRC related fields in the message registry. | 
 |  *        It is part of the 'Entry' structure that will be filled in when | 
 |  *        an error is looked up in the registry. | 
 |  * | 
 |  * If a field is wrapped by std::optional, it means the field is | 
 |  * optional in the JSON and higher level code knows how to handle it. | 
 |  */ | 
 | struct SRC | 
 | { | 
 |     /** | 
 |      * @brief SRC type - The first byte of the ASCII string | 
 |      */ | 
 |     uint8_t type; | 
 |  | 
 |     /** | 
 |      * @brief The SRC reason code (2nd half of 4B 'ASCII string' word) | 
 |      */ | 
 |     uint16_t reasonCode; | 
 |  | 
 |     /** | 
 |      * @brief An optional vector of SRC hexword numbers that should be used | 
 |      *        along with the SRC ASCII string to build the Symptom ID, which | 
 |      *        is a field in the Extended Header section. | 
 |      */ | 
 |     using WordNum = size_t; | 
 |     std::optional<std::vector<WordNum>> symptomID; | 
 |  | 
 |     /** | 
 |      * @brief Which AdditionalData fields to use to fill in the user defined | 
 |      *        SRC hexwords. | 
 |      * | 
 |      * For example, if the AdditionalData event log property contained | 
 |      * "CHIPNUM=42" and this map contained {6, {"CHIPNUM", "DESC"}}, then the | 
 |      * code would put 42 into SRC hexword 6. | 
 |      * | 
 |      * AdditionalDataField specifies two fields from the SRC entry in the | 
 |      * message registry: "AdditionalDataPropSource" and "Description" | 
 |      */ | 
 |     using AdditionalDataField = std::tuple<std::string, std::string>; | 
 |     std::optional<std::map<WordNum, AdditionalDataField>> hexwordADFields; | 
 |  | 
 |     SRC() : type(0), reasonCode(0) {} | 
 | }; | 
 |  | 
 | /** | 
 |  * @brief Represents a message registry entry, which is used for creating a | 
 |  *        PEL from an OpenBMC event log. | 
 |  */ | 
 | struct Entry | 
 | { | 
 |     /** | 
 |      * @brief The error name, like "xyz.openbmc_project.Error.Foo". | 
 |      */ | 
 |     std::string name; | 
 |  | 
 |     /** | 
 |      * @brief The component ID of the PEL creator. | 
 |      */ | 
 |     uint16_t componentID; | 
 |  | 
 |     /** | 
 |      * @brief The PEL subsystem field. | 
 |      */ | 
 |     std::optional<uint8_t> subsystem; | 
 |  | 
 |     /** | 
 |      * @brief The optional PEL severity field.  If not specified, the PEL | 
 |      *        will use the severity of the OpenBMC event log. | 
 |      * | 
 |      * If the system type is specified in any of the entries in the vector, | 
 |      * then the system type will be needed to find the actual severity. | 
 |      */ | 
 |     std::optional<std::vector<RegistrySeverity>> severity; | 
 |  | 
 |     /** | 
 |      * @brief The optional severity field to use when in manufacturing tolerance | 
 |      *        mode.  It behaves like the severity field above. | 
 |      */ | 
 |     std::optional<std::vector<RegistrySeverity>> mfgSeverity; | 
 |  | 
 |     /** | 
 |      * @brief The PEL action flags field. | 
 |      */ | 
 |     std::optional<uint16_t> actionFlags; | 
 |  | 
 |     /** | 
 |      * @brief  The optional action flags to use instead when in manufacturing | 
 |      * tolerance mode. | 
 |      */ | 
 |     std::optional<uint16_t> mfgActionFlags; | 
 |  | 
 |     /** | 
 |      * @brief The PEL event type field.  If not specified, higher level code | 
 |      *        will decide the value. | 
 |      */ | 
 |     std::optional<uint8_t> eventType; | 
 |  | 
 |     /** | 
 |      * @brief The PEL event scope field.  If not specified, higher level code | 
 |      *        will decide the value. | 
 |      */ | 
 |     std::optional<uint8_t> eventScope; | 
 |  | 
 |     /** | 
 |      * The SRC related fields. | 
 |      */ | 
 |     SRC src; | 
 |  | 
 |     /** | 
 |      * The Documentation related fields. | 
 |      */ | 
 |     DOC doc; | 
 |  | 
 |     /** | 
 |      * @brief The callout JSON, if the entry has callouts. | 
 |      */ | 
 |     std::optional<nlohmann::json> callouts; | 
 | }; | 
 |  | 
 | /** | 
 |  * @brief Holds callout information pulled out of the JSON. | 
 |  */ | 
 | struct RegistryCallout | 
 | { | 
 |     std::string priority; | 
 |     std::string locCode; | 
 |     std::string procedure; | 
 |     std::string symbolicFRU; | 
 |     std::string symbolicFRUTrusted; | 
 |     bool useInventoryLocCode; | 
 | }; | 
 |  | 
 | /** | 
 |  * @class Registry | 
 |  * | 
 |  * This class wraps the message registry JSON data and allows one to find | 
 |  * the message registry entry pertaining to the error name. | 
 |  * | 
 |  * So that new registry files can easily be tested, the code will look for | 
 |  * /etc/phosphor-logging/message_registry.json before looking for the real | 
 |  * path. | 
 |  */ | 
 | class Registry | 
 | { | 
 |   public: | 
 |     Registry() = delete; | 
 |     ~Registry() = default; | 
 |     Registry(const Registry&) = default; | 
 |     Registry& operator=(const Registry&) = default; | 
 |     Registry(Registry&&) = default; | 
 |     Registry& operator=(Registry&&) = default; | 
 |  | 
 |     /** | 
 |      * @brief Constructor | 
 |      * | 
 |      * Will load the callout JSON. | 
 |      * | 
 |      * @param[in] registryFile - The path to the file. | 
 |      */ | 
 |     explicit Registry(const std::filesystem::path& registryFile) : | 
 |         Registry(registryFile, true) | 
 |     {} | 
 |  | 
 |     /** | 
 |      * @brief Constructor | 
 |      * | 
 |      * This version contains a parameter that allows the callout JSON | 
 |      * to be saved in the Entry struct or not, as it isn't needed at | 
 |      * all in some cases. | 
 |      * | 
 |      * @param[in] registryFile - The path to the file. | 
 |      * @param[in] loadCallouts - If the callout JSON should be saved. | 
 |      */ | 
 |     explicit Registry(const std::filesystem::path& registryFile, | 
 |                       bool loadCallouts) : | 
 |         _registryFile(registryFile), | 
 |         _loadCallouts(loadCallouts) | 
 |     {} | 
 |  | 
 |     /** | 
 |      * @brief Find a registry entry based on its error name or reason code. | 
 |      * | 
 |      * This function does do some basic sanity checking on the JSON contents, | 
 |      * but there is also an external program that enforces a schema on the | 
 |      * registry JSON that should catch all of these problems ahead of time. | 
 |      * | 
 |      * @param[in] name - The error name, like xyz.openbmc_project.Error.Foo | 
 |      *                 - OR | 
 |      *                 - The reason code, like 0x1001 | 
 |      * @param[in] type - LookupType enum value | 
 |      * @param[in] toCache - boolean to cache registry in memory | 
 |      * @return optional<Entry> A filled in message registry structure if | 
 |      *                         found, otherwise an empty optional object. | 
 |      */ | 
 |     std::optional<Entry> lookup(const std::string& name, LookupType type, | 
 |                                 bool toCache = false); | 
 |  | 
 |     /** | 
 |      * @brief Find the callouts to put into the PEL based on the calloutJSON | 
 |      *        data. | 
 |      * | 
 |      * The system type and AdditionalData are used to index into the correct | 
 |      * callout table. | 
 |      * | 
 |      * Throws exceptions on failures. | 
 |      * | 
 |      * @param[in] calloutJSON - Where to look up the  callouts | 
 |      * @param[in] systemNames - List of compatible system type names | 
 |      * @param[in] additionalData - The AdditionalData property | 
 |      * | 
 |      * @return std::vector<RegistryCallout> - The callouts to use | 
 |      */ | 
 |     static std::vector<RegistryCallout> | 
 |         getCallouts(const nlohmann::json& calloutJSON, | 
 |                     const std::vector<std::string>& systemNames, | 
 |                     const AdditionalData& additionalData); | 
 |  | 
 |   private: | 
 |     /** | 
 |      * @brief Parse message registry file using nlohmann::json | 
 |      * @param[in] registryFile - The message registry JSON file | 
 |      * @return optional<nlohmann::json> The full message registry object or an | 
 |      *                                  empty optional object upon failure. | 
 |      */ | 
 |     std::optional<nlohmann::json> | 
 |         readRegistry(const std::filesystem::path& registryFile); | 
 |  | 
 |     /** | 
 |      * @brief The path to the registry JSON file. | 
 |      */ | 
 |     std::filesystem::path _registryFile; | 
 |  | 
 |     /** | 
 |      * @brief The full message registry object. | 
 |      */ | 
 |     std::optional<nlohmann::json> _registry; | 
 |  | 
 |     /** | 
 |      * @brief If the callout JSON should be saved in the Entry on lookup. | 
 |      */ | 
 |     bool _loadCallouts; | 
 | }; | 
 |  | 
 | namespace helper | 
 | { | 
 |  | 
 | /** | 
 |  * @brief A helper function to get the PEL subsystem value based on | 
 |  *        the registry subsystem name. | 
 |  * | 
 |  * @param[in] subsystemName - The registry name for the subsystem | 
 |  * | 
 |  * @return uint8_t The PEL subsystem value | 
 |  */ | 
 | uint8_t getSubsystem(const std::string& subsystemName); | 
 |  | 
 | /** | 
 |  * @brief A helper function to get the PEL severity value based on | 
 |  *        the registry severity name. | 
 |  * | 
 |  * @param[in] severityName - The registry name for the severity | 
 |  * | 
 |  * @return uint8_t The PEL severity value | 
 |  */ | 
 | uint8_t getSeverity(const std::string& severityName); | 
 |  | 
 | /** | 
 |  * @brief Returns all of the system type/severity values found | 
 |  * in the severity JSON passed in. | 
 |  * | 
 |  * The JSON is either a simple string, like: | 
 |  *     "unrecoverable" | 
 |  * or an array of system type/severity pairs, like: | 
 |  *     [ | 
 |  *        { | 
 |  *            "System": "1", | 
 |  *            "SevValue": "predictive" | 
 |  *        }, | 
 |  *        { | 
 |  *            "System": "2", | 
 |  *            "SevValue": "recovered" | 
 |  *        } | 
 |  *     ] | 
 |  * | 
 |  * @param[in] severity - The severity JSON | 
 |  * @return The list of severity/system combinations.  If the System key | 
 |  *         wasn't used, then that field will be empty in the structure. | 
 |  */ | 
 | std::vector<RegistrySeverity> getSeverities(const nlohmann::json& severity); | 
 |  | 
 | /** | 
 |  * @brief A helper function to get the action flags value based on | 
 |  *        the action flag names used in the registry. | 
 |  * | 
 |  * @param[in] flags - The list of flag names from the registry. | 
 |  * | 
 |  * @return uint16_t - The bitfield of flags used in the PEL. | 
 |  */ | 
 | uint16_t getActionFlags(const std::vector<std::string>& flags); | 
 |  | 
 | /** | 
 |  * @brief A helper function to get the PEL event type value based on | 
 |  *        the registry event type name. | 
 |  * | 
 |  * @param[in] eventTypeName - The registry name for the event type | 
 |  * | 
 |  * @return uint8_t The PEL event type value | 
 |  */ | 
 | uint8_t getEventType(const std::string& eventTypeName); | 
 |  | 
 | /** | 
 |  * @brief A helper function to get the PEL event scope value based on | 
 |  *        the registry event scope name. | 
 |  * | 
 |  * @param[in] eventScopeName - The registry name for the event scope | 
 |  * | 
 |  * @return uint8_t The PEL event scope value | 
 |  */ | 
 | uint8_t getEventScope(const std::string& eventScopeName); | 
 |  | 
 | /** | 
 |  * @brief Reads the "ReasonCode" field out of JSON and converts the string value | 
 |  *        such as "0x5555" to a uint16 like 0x5555. | 
 |  * | 
 |  * @param[in] src - The message registry SRC dictionary to read from | 
 |  * @param[in] name - The error name, to use in a trace if things go awry. | 
 |  * | 
 |  * @return uint16_t - The reason code | 
 |  */ | 
 | uint16_t getSRCReasonCode(const nlohmann::json& src, const std::string& name); | 
 |  | 
 | /** | 
 |  * @brief Reads the "Type" field out of JSON and converts it to the SRC::Type | 
 |  *        value. | 
 |  * | 
 |  * @param[in] src - The message registry SRC dictionary to read from | 
 |  * @param[in] name - The error name, to use in a trace if things go awry. | 
 |  * | 
 |  * @return uint8_t - The SRC type value, like 0x11 | 
 |  */ | 
 | uint8_t getSRCType(const nlohmann::json& src, const std::string& name); | 
 |  | 
 | /** | 
 |  * @brief Reads the "Words6To9" field out of JSON and converts it to a map | 
 |  *        of the SRC word number to the AdditionalData property field used | 
 |  *        to fill it in with. | 
 |  * | 
 |  * @param[in] src - The message registry SRC dictionary to read from | 
 |  * @param[in] name - The error name, to use in a trace if things go awry. | 
 |  * | 
 |  * @return std::optional<std::map<SRC::WordNum, SRC::AdditionalDataField>> | 
 |  */ | 
 | std::optional<std::map<SRC::WordNum, SRC::AdditionalDataField>> | 
 |     getSRCHexwordFields(const nlohmann::json& src, const std::string& name); | 
 |  | 
 | /** | 
 |  * @brief Reads the "SymptomIDFields" field out of JSON and converts it to | 
 |  *        a vector of SRC word numbers. | 
 |  * | 
 |  * @param[in] src - The message registry SRC dictionary to read from | 
 |  * @param[in] name - The error name, to use in a trace if things go awry. | 
 |  * | 
 |  * @return std::optional<std::vector<SRC::WordNum>> | 
 |  */ | 
 | std::optional<std::vector<SRC::WordNum>> | 
 |     getSRCSymptomIDFields(const nlohmann::json& src, const std::string& name); | 
 |  | 
 | /** | 
 |  * @brief Reads the "ComponentID" field out of JSON and converts it to a | 
 |  *        uint16_t like 0xFF00. | 
 |  * | 
 |  * The ComponentID JSON field is only required if the SRC type isn't a BD | 
 |  * BMC SRC, because for those SRCs it can be inferred from the upper byte | 
 |  * of the SRC reasoncode. | 
 |  * | 
 |  * @param[in] srcType - The SRC type | 
 |  * @param[in] reasonCode - The SRC reason code | 
 |  * @param[in] pelEntry - The PEL entry JSON | 
 |  * @param[in] name - The error name, to use in a trace if things go awry. | 
 |  * | 
 |  * @return uin16_t - The component ID, like 0xFF00 | 
 |  */ | 
 | uint16_t getComponentID(uint8_t srcType, uint16_t reasonCode, | 
 |                         const nlohmann::json& pelEntry, | 
 |                         const std::string& name); | 
 |  | 
 | } // namespace helper | 
 |  | 
 | } // namespace message | 
 |  | 
 | } // namespace pels | 
 | } // namespace openpower |