xref: /openbmc/phosphor-led-manager/manager/json-parser.hpp (revision 405ea28684703dfc609ad8a42c853a5a609fa61c)
1953315d2SPatrick Williams #include "config.h"
2953315d2SPatrick Williams 
37ba70c82SAlexander Hansen #include "grouplayout.hpp"
4953315d2SPatrick Williams #include "json-config.hpp"
5953315d2SPatrick Williams #include "ledlayout.hpp"
6953315d2SPatrick Williams 
7953315d2SPatrick Williams #include <nlohmann/json.hpp>
8953315d2SPatrick Williams #include <phosphor-logging/lg2.hpp>
9953315d2SPatrick Williams #include <sdbusplus/bus.hpp>
10953315d2SPatrick Williams #include <sdeventplus/event.hpp>
11953315d2SPatrick Williams 
12953315d2SPatrick Williams #include <filesystem>
13953315d2SPatrick Williams #include <fstream>
14953315d2SPatrick Williams #include <iostream>
15953315d2SPatrick Williams 
16953315d2SPatrick Williams namespace fs = std::filesystem;
17953315d2SPatrick Williams 
18953315d2SPatrick Williams using Json = nlohmann::json;
19953315d2SPatrick Williams 
20953315d2SPatrick Williams // Priority for a particular LED needs to stay SAME across all groups
21f2044037SPatrick Williams using PriorityMap =
2255badf79SAlexander Hansen     std::unordered_map<std::string,
2355badf79SAlexander Hansen                        std::optional<phosphor::led::Layout::Action>>;
24953315d2SPatrick Williams 
25953315d2SPatrick Williams /** @brief Parse LED JSON file and output Json object
26953315d2SPatrick Williams  *
27953315d2SPatrick Williams  *  @param[in] path - path of LED JSON file
28953315d2SPatrick Williams  *
29953315d2SPatrick Williams  *  @return const Json - Json object
30953315d2SPatrick Williams  */
readJson(const fs::path & path)3173ff9ad6SPatrick Williams Json readJson(const fs::path& path)
32953315d2SPatrick Williams {
33953315d2SPatrick Williams     if (!fs::exists(path) || fs::is_empty(path))
34953315d2SPatrick Williams     {
35953315d2SPatrick Williams         lg2::error("Incorrect File Path or empty file, FILE_PATH = {PATH}",
36953315d2SPatrick Williams                    "PATH", path);
37953315d2SPatrick Williams         throw std::runtime_error("Incorrect File Path or empty file");
38953315d2SPatrick Williams     }
39953315d2SPatrick Williams 
40953315d2SPatrick Williams     try
41953315d2SPatrick Williams     {
42953315d2SPatrick Williams         std::ifstream jsonFile(path);
43953315d2SPatrick Williams         return Json::parse(jsonFile);
44953315d2SPatrick Williams     }
45953315d2SPatrick Williams     catch (const std::exception& e)
46953315d2SPatrick Williams     {
47953315d2SPatrick Williams         lg2::error(
48953315d2SPatrick Williams             "Failed to parse config file, ERROR = {ERROR}, FILE_PATH = {PATH}",
49953315d2SPatrick Williams             "ERROR", e, "PATH", path);
50953315d2SPatrick Williams         throw std::runtime_error("Failed to parse config file");
51953315d2SPatrick Williams     }
52953315d2SPatrick Williams }
53953315d2SPatrick Williams 
54953315d2SPatrick Williams /** @brief Returns action enum based on string
55953315d2SPatrick Williams  *
56953315d2SPatrick Williams  *  @param[in] action - action string
57953315d2SPatrick Williams  *
584d44a55eSAlexander Hansen  *  @return Action - action enum (On/Off/Blink)
59953315d2SPatrick Williams  */
getAction(const std::string & action)60953315d2SPatrick Williams phosphor::led::Layout::Action getAction(const std::string& action)
61953315d2SPatrick Williams {
624d44a55eSAlexander Hansen     if (action == "On")
634d44a55eSAlexander Hansen     {
644d44a55eSAlexander Hansen         return phosphor::led::Layout::Action::On;
654d44a55eSAlexander Hansen     }
664d44a55eSAlexander Hansen     if (action == "Off")
674d44a55eSAlexander Hansen     {
684d44a55eSAlexander Hansen         return phosphor::led::Layout::Action::Off;
694d44a55eSAlexander Hansen     }
704d44a55eSAlexander Hansen     if (action == "Blink")
714d44a55eSAlexander Hansen     {
724d44a55eSAlexander Hansen         return phosphor::led::Layout::Action::Blink;
734d44a55eSAlexander Hansen     }
74953315d2SPatrick Williams 
754d44a55eSAlexander Hansen     assert(false);
764d44a55eSAlexander Hansen     return phosphor::led::Layout::Action::Blink;
77953315d2SPatrick Williams }
78953315d2SPatrick Williams 
loadJsonConfigV1GroupMember(const Json & member,phosphor::led::ActionSet & ledActions)79d0f80506SAlexander Hansen static void loadJsonConfigV1GroupMember(const Json& member,
80d0f80506SAlexander Hansen                                         phosphor::led::ActionSet& ledActions)
81d0f80506SAlexander Hansen {
82d0f80506SAlexander Hansen     auto name = member.value("Name", "");
83d0f80506SAlexander Hansen     auto action = getAction(member.value("Action", ""));
84d0f80506SAlexander Hansen     uint8_t dutyOn = member.value("DutyOn", 50);
85d0f80506SAlexander Hansen     uint16_t period = member.value("Period", 0);
86d0f80506SAlexander Hansen 
8755badf79SAlexander Hansen     const std::string priorityStr = member.value("Priority", "");
8855badf79SAlexander Hansen     std::optional<phosphor::led::Layout::Action> priority = std::nullopt;
8955badf79SAlexander Hansen 
9055badf79SAlexander Hansen     if (!priorityStr.empty())
9155badf79SAlexander Hansen     {
9255badf79SAlexander Hansen         priority = getAction(priorityStr);
9355badf79SAlexander Hansen     }
94d0f80506SAlexander Hansen 
95d0f80506SAlexander Hansen     phosphor::led::Layout::LedAction ledAction{name, action, dutyOn, period,
96d0f80506SAlexander Hansen                                                priority};
97d0f80506SAlexander Hansen     ledActions.emplace(ledAction);
98d0f80506SAlexander Hansen }
99d0f80506SAlexander Hansen 
loadJsonConfigV1Group(const Json & entry,phosphor::led::GroupMap & ledMap)100d0f80506SAlexander Hansen static void loadJsonConfigV1Group(const Json& entry,
101638d1487SAlexander Hansen                                   phosphor::led::GroupMap& ledMap)
102d0f80506SAlexander Hansen {
103d0f80506SAlexander Hansen     const Json empty{};
104d0f80506SAlexander Hansen 
105d0f80506SAlexander Hansen     fs::path tmpPath("/xyz/openbmc_project/led/groups");
106d0f80506SAlexander Hansen 
107d0f80506SAlexander Hansen     const std::string groupName = entry.value("group", "");
108d0f80506SAlexander Hansen 
109d0f80506SAlexander Hansen     tmpPath /= groupName;
110d0f80506SAlexander Hansen     auto objpath = tmpPath.string();
111d0f80506SAlexander Hansen     auto members = entry.value("members", empty);
112d0f80506SAlexander Hansen 
113d0f80506SAlexander Hansen     lg2::debug("config for '{GROUP}'", "GROUP", groupName);
114d0f80506SAlexander Hansen 
115638d1487SAlexander Hansen     int priority = entry.value("Priority", 0);
116638d1487SAlexander Hansen 
117d0f80506SAlexander Hansen     phosphor::led::ActionSet ledActions{};
1187ba70c82SAlexander Hansen     phosphor::led::Layout::GroupLayout groupLayout{};
119d0f80506SAlexander Hansen     for (const auto& member : members)
120d0f80506SAlexander Hansen     {
121638d1487SAlexander Hansen         loadJsonConfigV1GroupMember(member, ledActions);
122d0f80506SAlexander Hansen     }
123d0f80506SAlexander Hansen 
124d0f80506SAlexander Hansen     // Generated an std::unordered_map of LedGroupNames to std::set of LEDs
125d0f80506SAlexander Hansen     // containing the name and properties.
1267ba70c82SAlexander Hansen     groupLayout.actionSet = ledActions;
1277ba70c82SAlexander Hansen     groupLayout.priority = priority;
1287ba70c82SAlexander Hansen 
1297ba70c82SAlexander Hansen     ledMap.emplace(objpath, groupLayout);
130d0f80506SAlexander Hansen }
131d0f80506SAlexander Hansen 
13273ff9ad6SPatrick Williams /** @brief Load JSON config and return led map (JSON version 1)
133953315d2SPatrick Williams  *
134158b2c14SPatrick Williams  *  @return phosphor::led::GroupMap
135953315d2SPatrick Williams  */
loadJsonConfigV1(const Json & json)136*405ea286SGeorge Liu phosphor::led::GroupMap loadJsonConfigV1(const Json& json)
137953315d2SPatrick Williams {
138158b2c14SPatrick Williams     phosphor::led::GroupMap ledMap{};
139953315d2SPatrick Williams 
140953315d2SPatrick Williams     // define the default JSON as empty
141953315d2SPatrick Williams     const Json empty{};
142953315d2SPatrick Williams     auto leds = json.value("leds", empty);
143953315d2SPatrick Williams 
144953315d2SPatrick Williams     for (const auto& entry : leds)
145953315d2SPatrick Williams     {
146638d1487SAlexander Hansen         loadJsonConfigV1Group(entry, ledMap);
147953315d2SPatrick Williams     }
148953315d2SPatrick Williams 
149953315d2SPatrick Williams     return ledMap;
150953315d2SPatrick Williams }
151953315d2SPatrick Williams 
15273ff9ad6SPatrick Williams /** @brief Load JSON config and return led map
15373ff9ad6SPatrick Williams  *
154158b2c14SPatrick Williams  *  @return phosphor::led::GroupMap
15573ff9ad6SPatrick Williams  */
loadJsonConfig(const fs::path & path)156*405ea286SGeorge Liu phosphor::led::GroupMap loadJsonConfig(const fs::path& path)
15773ff9ad6SPatrick Williams {
15873ff9ad6SPatrick Williams     auto json = readJson(path);
15973ff9ad6SPatrick Williams 
16073ff9ad6SPatrick Williams     auto version = json.value("version", 1);
16173ff9ad6SPatrick Williams     switch (version)
16273ff9ad6SPatrick Williams     {
16373ff9ad6SPatrick Williams         case 1:
16473ff9ad6SPatrick Williams             return loadJsonConfigV1(json);
16573ff9ad6SPatrick Williams 
16673ff9ad6SPatrick Williams         default:
16773ff9ad6SPatrick Williams             lg2::error("Unsupported JSON Version: {VERSION}", "VERSION",
16873ff9ad6SPatrick Williams                        version);
16973ff9ad6SPatrick Williams             throw std::runtime_error("Unsupported version");
17073ff9ad6SPatrick Williams     }
17173ff9ad6SPatrick Williams 
172158b2c14SPatrick Williams     return phosphor::led::GroupMap{};
17373ff9ad6SPatrick Williams }
17473ff9ad6SPatrick Williams 
175953315d2SPatrick Williams /** @brief Get led map from LED groups JSON config
176953315d2SPatrick Williams  *
1777217c035SPatrick Williams  *  @param[in] config - Path to the JSON config.
178158b2c14SPatrick Williams  *  @return phosphor::led::GroupMap
1797217c035SPatrick Williams  *
1807217c035SPatrick Williams  *  @note if config is an empty string, daemon will interrogate dbus for
1817217c035SPatrick Williams  *        compatible strings.
182953315d2SPatrick Williams  */
getSystemLedMap(fs::path config)183*405ea286SGeorge Liu phosphor::led::GroupMap getSystemLedMap(fs::path config)
184953315d2SPatrick Williams {
1857217c035SPatrick Williams     if (config.empty())
186953315d2SPatrick Williams     {
1877217c035SPatrick Williams         config = phosphor::led::getJsonConfig();
188953315d2SPatrick Williams     }
189953315d2SPatrick Williams 
1907217c035SPatrick Williams     return loadJsonConfig(config);
191953315d2SPatrick Williams }
192