xref: /openbmc/phosphor-led-manager/manager/json-parser.hpp (revision 638d148769f64f86425d6b404e7438e348f5839f)
1953315d2SPatrick Williams #include "config.h"
2953315d2SPatrick Williams 
3*638d1487SAlexander Hansen #include "config-validator.hpp"
47ba70c82SAlexander Hansen #include "grouplayout.hpp"
5953315d2SPatrick Williams #include "json-config.hpp"
6953315d2SPatrick Williams #include "ledlayout.hpp"
7953315d2SPatrick Williams 
8953315d2SPatrick Williams #include <nlohmann/json.hpp>
9953315d2SPatrick Williams #include <phosphor-logging/lg2.hpp>
10953315d2SPatrick Williams #include <sdbusplus/bus.hpp>
11953315d2SPatrick Williams #include <sdeventplus/event.hpp>
12953315d2SPatrick Williams 
13953315d2SPatrick Williams #include <filesystem>
14953315d2SPatrick Williams #include <fstream>
15953315d2SPatrick Williams #include <iostream>
16953315d2SPatrick Williams 
17953315d2SPatrick Williams namespace fs = std::filesystem;
18953315d2SPatrick Williams 
19953315d2SPatrick Williams using Json = nlohmann::json;
20953315d2SPatrick Williams 
21953315d2SPatrick Williams // Priority for a particular LED needs to stay SAME across all groups
22f2044037SPatrick Williams using PriorityMap =
2355badf79SAlexander Hansen     std::unordered_map<std::string,
2455badf79SAlexander Hansen                        std::optional<phosphor::led::Layout::Action>>;
25953315d2SPatrick Williams 
26953315d2SPatrick Williams /** @brief Parse LED JSON file and output Json object
27953315d2SPatrick Williams  *
28953315d2SPatrick Williams  *  @param[in] path - path of LED JSON file
29953315d2SPatrick Williams  *
30953315d2SPatrick Williams  *  @return const Json - Json object
31953315d2SPatrick Williams  */
3273ff9ad6SPatrick Williams Json readJson(const fs::path& path)
33953315d2SPatrick Williams {
34953315d2SPatrick Williams     if (!fs::exists(path) || fs::is_empty(path))
35953315d2SPatrick Williams     {
36953315d2SPatrick Williams         lg2::error("Incorrect File Path or empty file, FILE_PATH = {PATH}",
37953315d2SPatrick Williams                    "PATH", path);
38953315d2SPatrick Williams         throw std::runtime_error("Incorrect File Path or empty file");
39953315d2SPatrick Williams     }
40953315d2SPatrick Williams 
41953315d2SPatrick Williams     try
42953315d2SPatrick Williams     {
43953315d2SPatrick Williams         std::ifstream jsonFile(path);
44953315d2SPatrick Williams         return Json::parse(jsonFile);
45953315d2SPatrick Williams     }
46953315d2SPatrick Williams     catch (const std::exception& e)
47953315d2SPatrick Williams     {
48953315d2SPatrick Williams         lg2::error(
49953315d2SPatrick Williams             "Failed to parse config file, ERROR = {ERROR}, FILE_PATH = {PATH}",
50953315d2SPatrick Williams             "ERROR", e, "PATH", path);
51953315d2SPatrick Williams         throw std::runtime_error("Failed to parse config file");
52953315d2SPatrick Williams     }
53953315d2SPatrick Williams }
54953315d2SPatrick Williams 
55953315d2SPatrick Williams /** @brief Returns action enum based on string
56953315d2SPatrick Williams  *
57953315d2SPatrick Williams  *  @param[in] action - action string
58953315d2SPatrick Williams  *
594d44a55eSAlexander Hansen  *  @return Action - action enum (On/Off/Blink)
60953315d2SPatrick Williams  */
61953315d2SPatrick Williams phosphor::led::Layout::Action getAction(const std::string& action)
62953315d2SPatrick Williams {
634d44a55eSAlexander Hansen     if (action == "On")
644d44a55eSAlexander Hansen     {
654d44a55eSAlexander Hansen         return phosphor::led::Layout::Action::On;
664d44a55eSAlexander Hansen     }
674d44a55eSAlexander Hansen     if (action == "Off")
684d44a55eSAlexander Hansen     {
694d44a55eSAlexander Hansen         return phosphor::led::Layout::Action::Off;
704d44a55eSAlexander Hansen     }
714d44a55eSAlexander Hansen     if (action == "Blink")
724d44a55eSAlexander Hansen     {
734d44a55eSAlexander Hansen         return phosphor::led::Layout::Action::Blink;
744d44a55eSAlexander Hansen     }
75953315d2SPatrick Williams 
764d44a55eSAlexander Hansen     assert(false);
774d44a55eSAlexander Hansen     return phosphor::led::Layout::Action::Blink;
78953315d2SPatrick Williams }
79953315d2SPatrick Williams 
80d0f80506SAlexander Hansen static void loadJsonConfigV1GroupMember(const Json& member,
81d0f80506SAlexander Hansen                                         phosphor::led::ActionSet& ledActions)
82d0f80506SAlexander Hansen {
83d0f80506SAlexander Hansen     auto name = member.value("Name", "");
84d0f80506SAlexander Hansen     auto action = getAction(member.value("Action", ""));
85d0f80506SAlexander Hansen     uint8_t dutyOn = member.value("DutyOn", 50);
86d0f80506SAlexander Hansen     uint16_t period = member.value("Period", 0);
87d0f80506SAlexander Hansen 
8855badf79SAlexander Hansen     const std::string priorityStr = member.value("Priority", "");
8955badf79SAlexander Hansen     std::optional<phosphor::led::Layout::Action> priority = std::nullopt;
9055badf79SAlexander Hansen 
9155badf79SAlexander Hansen     if (!priorityStr.empty())
9255badf79SAlexander Hansen     {
9355badf79SAlexander Hansen         priority = getAction(priorityStr);
9455badf79SAlexander Hansen     }
95d0f80506SAlexander Hansen 
96d0f80506SAlexander Hansen     phosphor::led::Layout::LedAction ledAction{name, action, dutyOn, period,
97d0f80506SAlexander Hansen                                                priority};
98d0f80506SAlexander Hansen     ledActions.emplace(ledAction);
99d0f80506SAlexander Hansen }
100d0f80506SAlexander Hansen 
101d0f80506SAlexander Hansen static void loadJsonConfigV1Group(const Json& entry,
102*638d1487SAlexander Hansen                                   phosphor::led::GroupMap& ledMap)
103d0f80506SAlexander Hansen {
104d0f80506SAlexander Hansen     const Json empty{};
105d0f80506SAlexander Hansen 
106d0f80506SAlexander Hansen     fs::path tmpPath("/xyz/openbmc_project/led/groups");
107d0f80506SAlexander Hansen 
108d0f80506SAlexander Hansen     const std::string groupName = entry.value("group", "");
109d0f80506SAlexander Hansen 
110d0f80506SAlexander Hansen     tmpPath /= groupName;
111d0f80506SAlexander Hansen     auto objpath = tmpPath.string();
112d0f80506SAlexander Hansen     auto members = entry.value("members", empty);
113d0f80506SAlexander Hansen 
114d0f80506SAlexander Hansen     lg2::debug("config for '{GROUP}'", "GROUP", groupName);
115d0f80506SAlexander Hansen 
116*638d1487SAlexander Hansen     int priority = entry.value("Priority", 0);
117*638d1487SAlexander Hansen 
118d0f80506SAlexander Hansen     phosphor::led::ActionSet ledActions{};
1197ba70c82SAlexander Hansen     phosphor::led::Layout::GroupLayout groupLayout{};
120d0f80506SAlexander Hansen     for (const auto& member : members)
121d0f80506SAlexander Hansen     {
122*638d1487SAlexander Hansen         loadJsonConfigV1GroupMember(member, ledActions);
123d0f80506SAlexander Hansen     }
124d0f80506SAlexander Hansen 
125d0f80506SAlexander Hansen     // Generated an std::unordered_map of LedGroupNames to std::set of LEDs
126d0f80506SAlexander Hansen     // containing the name and properties.
1277ba70c82SAlexander Hansen     groupLayout.actionSet = ledActions;
1287ba70c82SAlexander Hansen     groupLayout.priority = priority;
1297ba70c82SAlexander Hansen 
1307ba70c82SAlexander Hansen     ledMap.emplace(objpath, groupLayout);
131d0f80506SAlexander Hansen }
132d0f80506SAlexander Hansen 
13373ff9ad6SPatrick Williams /** @brief Load JSON config and return led map (JSON version 1)
134953315d2SPatrick Williams  *
135158b2c14SPatrick Williams  *  @return phosphor::led::GroupMap
136953315d2SPatrick Williams  */
137158b2c14SPatrick Williams const phosphor::led::GroupMap loadJsonConfigV1(const Json& json)
138953315d2SPatrick Williams {
139158b2c14SPatrick Williams     phosphor::led::GroupMap ledMap{};
140953315d2SPatrick Williams 
141953315d2SPatrick Williams     // define the default JSON as empty
142953315d2SPatrick Williams     const Json empty{};
143953315d2SPatrick Williams     auto leds = json.value("leds", empty);
144953315d2SPatrick Williams 
145953315d2SPatrick Williams     for (const auto& entry : leds)
146953315d2SPatrick Williams     {
147*638d1487SAlexander Hansen         loadJsonConfigV1Group(entry, ledMap);
148953315d2SPatrick Williams     }
149953315d2SPatrick Williams 
150953315d2SPatrick Williams     return ledMap;
151953315d2SPatrick Williams }
152953315d2SPatrick Williams 
15373ff9ad6SPatrick Williams /** @brief Load JSON config and return led map
15473ff9ad6SPatrick Williams  *
155158b2c14SPatrick Williams  *  @return phosphor::led::GroupMap
15673ff9ad6SPatrick Williams  */
157158b2c14SPatrick Williams const phosphor::led::GroupMap loadJsonConfig(const fs::path& path)
15873ff9ad6SPatrick Williams {
15973ff9ad6SPatrick Williams     auto json = readJson(path);
16073ff9ad6SPatrick Williams 
16173ff9ad6SPatrick Williams     auto version = json.value("version", 1);
16273ff9ad6SPatrick Williams     switch (version)
16373ff9ad6SPatrick Williams     {
16473ff9ad6SPatrick Williams         case 1:
16573ff9ad6SPatrick Williams             return loadJsonConfigV1(json);
16673ff9ad6SPatrick Williams 
16773ff9ad6SPatrick Williams         default:
16873ff9ad6SPatrick Williams             lg2::error("Unsupported JSON Version: {VERSION}", "VERSION",
16973ff9ad6SPatrick Williams                        version);
17073ff9ad6SPatrick Williams             throw std::runtime_error("Unsupported version");
17173ff9ad6SPatrick Williams     }
17273ff9ad6SPatrick Williams 
173158b2c14SPatrick Williams     return phosphor::led::GroupMap{};
17473ff9ad6SPatrick Williams }
17573ff9ad6SPatrick Williams 
176953315d2SPatrick Williams /** @brief Get led map from LED groups JSON config
177953315d2SPatrick Williams  *
1787217c035SPatrick Williams  *  @param[in] config - Path to the JSON config.
179158b2c14SPatrick Williams  *  @return phosphor::led::GroupMap
1807217c035SPatrick Williams  *
1817217c035SPatrick Williams  *  @note if config is an empty string, daemon will interrogate dbus for
1827217c035SPatrick Williams  *        compatible strings.
183953315d2SPatrick Williams  */
184158b2c14SPatrick Williams const phosphor::led::GroupMap getSystemLedMap(fs::path config)
185953315d2SPatrick Williams {
1867217c035SPatrick Williams     if (config.empty())
187953315d2SPatrick Williams     {
1887217c035SPatrick Williams         config = phosphor::led::getJsonConfig();
189953315d2SPatrick Williams     }
190953315d2SPatrick Williams 
1917217c035SPatrick Williams     return loadJsonConfig(config);
192953315d2SPatrick Williams }
193