xref: /openbmc/phosphor-led-manager/manager/json-parser.hpp (revision 158b2c14f54c78d334a21ca3656dc9364f598321)
1953315d2SPatrick Williams #include "config.h"
2953315d2SPatrick Williams 
3953315d2SPatrick Williams #include "json-config.hpp"
4953315d2SPatrick Williams #include "ledlayout.hpp"
5953315d2SPatrick Williams 
6953315d2SPatrick Williams #include <nlohmann/json.hpp>
7953315d2SPatrick Williams #include <phosphor-logging/lg2.hpp>
8953315d2SPatrick Williams #include <sdbusplus/bus.hpp>
9953315d2SPatrick Williams #include <sdeventplus/event.hpp>
10953315d2SPatrick Williams 
11953315d2SPatrick Williams #include <filesystem>
12953315d2SPatrick Williams #include <fstream>
13953315d2SPatrick Williams #include <iostream>
14953315d2SPatrick Williams 
15953315d2SPatrick Williams namespace fs = std::filesystem;
16953315d2SPatrick Williams 
17953315d2SPatrick Williams using Json = nlohmann::json;
18953315d2SPatrick Williams 
19953315d2SPatrick Williams // Priority for a particular LED needs to stay SAME across all groups
20953315d2SPatrick Williams // phosphor::led::Layout::Action can only be one of `Blink` and `On`
21f2044037SPatrick Williams using PriorityMap =
22f2044037SPatrick Williams     std::unordered_map<std::string, phosphor::led::Layout::Action>;
23953315d2SPatrick Williams 
24953315d2SPatrick Williams /** @brief Parse LED JSON file and output Json object
25953315d2SPatrick Williams  *
26953315d2SPatrick Williams  *  @param[in] path - path of LED JSON file
27953315d2SPatrick Williams  *
28953315d2SPatrick Williams  *  @return const Json - Json object
29953315d2SPatrick Williams  */
3073ff9ad6SPatrick Williams Json readJson(const fs::path& path)
31953315d2SPatrick Williams {
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  *
58953315d2SPatrick Williams  *  @return Action - action enum (On/Blink)
59953315d2SPatrick Williams  */
60953315d2SPatrick Williams phosphor::led::Layout::Action getAction(const std::string& action)
61953315d2SPatrick Williams {
62953315d2SPatrick Williams     assert(action == "On" || action == "Blink");
63953315d2SPatrick Williams 
64ed80e885SPatrick Williams     return action == "Blink" ? phosphor::led::Layout::Action::Blink
65ed80e885SPatrick Williams                              : phosphor::led::Layout::Action::On;
66953315d2SPatrick Williams }
67953315d2SPatrick Williams 
68953315d2SPatrick Williams /** @brief Validate the Priority of an LED is same across ALL groups
69953315d2SPatrick Williams  *
70953315d2SPatrick Williams  *  @param[in] name - led name member of each group
71953315d2SPatrick Williams  *  @param[in] priority - member priority of each group
72f2044037SPatrick Williams  *  @param[out] priorityMap - std::unordered_map, key:name, value:priority
73953315d2SPatrick Williams  *
74953315d2SPatrick Williams  *  @return
75953315d2SPatrick Williams  */
76953315d2SPatrick Williams void validatePriority(const std::string& name,
77953315d2SPatrick Williams                       const phosphor::led::Layout::Action& priority,
78953315d2SPatrick Williams                       PriorityMap& priorityMap)
79953315d2SPatrick Williams {
80953315d2SPatrick Williams 
81953315d2SPatrick Williams     auto iter = priorityMap.find(name);
82953315d2SPatrick Williams     if (iter == priorityMap.end())
83953315d2SPatrick Williams     {
84953315d2SPatrick Williams         priorityMap.emplace(name, priority);
85953315d2SPatrick Williams         return;
86953315d2SPatrick Williams     }
87953315d2SPatrick Williams 
88953315d2SPatrick Williams     if (iter->second != priority)
89953315d2SPatrick Williams     {
90953315d2SPatrick Williams         lg2::error(
91953315d2SPatrick Williams             "Priority of LED is not same across all, Name = {NAME}, Old Priority = {OLD_PRIO}, New Priority = {NEW_PRIO}",
92953315d2SPatrick Williams             "NAME", name, "OLD_PRIO", int(iter->second), "NEW_PRIO",
93953315d2SPatrick Williams             int(priority));
94953315d2SPatrick Williams 
95953315d2SPatrick Williams         throw std::runtime_error(
96953315d2SPatrick Williams             "Priority of at least one LED is not same across groups");
97953315d2SPatrick Williams     }
98953315d2SPatrick Williams }
99953315d2SPatrick Williams 
10073ff9ad6SPatrick Williams /** @brief Load JSON config and return led map (JSON version 1)
101953315d2SPatrick Williams  *
102*158b2c14SPatrick Williams  *  @return phosphor::led::GroupMap
103953315d2SPatrick Williams  */
104*158b2c14SPatrick Williams const phosphor::led::GroupMap loadJsonConfigV1(const Json& json)
105953315d2SPatrick Williams {
106*158b2c14SPatrick Williams     phosphor::led::GroupMap ledMap{};
107953315d2SPatrick Williams     PriorityMap priorityMap{};
108953315d2SPatrick Williams 
109953315d2SPatrick Williams     // define the default JSON as empty
110953315d2SPatrick Williams     const Json empty{};
111953315d2SPatrick Williams     auto leds = json.value("leds", empty);
112953315d2SPatrick Williams 
113953315d2SPatrick Williams     for (const auto& entry : leds)
114953315d2SPatrick Williams     {
115953315d2SPatrick Williams         fs::path tmpPath(std::string{OBJPATH});
116953315d2SPatrick Williams         tmpPath /= entry.value("group", "");
117953315d2SPatrick Williams         auto objpath = tmpPath.string();
118953315d2SPatrick Williams         auto members = entry.value("members", empty);
119953315d2SPatrick Williams 
120*158b2c14SPatrick Williams         phosphor::led::ActionSet ledActions{};
121953315d2SPatrick Williams         for (const auto& member : members)
122953315d2SPatrick Williams         {
123953315d2SPatrick Williams             auto name = member.value("Name", "");
124953315d2SPatrick Williams             auto action = getAction(member.value("Action", ""));
125953315d2SPatrick Williams             uint8_t dutyOn = member.value("DutyOn", 50);
126953315d2SPatrick Williams             uint16_t period = member.value("Period", 0);
127953315d2SPatrick Williams 
128953315d2SPatrick Williams             // Since only have Blink/On and default priority is Blink
129953315d2SPatrick Williams             auto priority = getAction(member.value("Priority", "Blink"));
130953315d2SPatrick Williams 
131953315d2SPatrick Williams             // Same LEDs can be part of multiple groups. However, their
132953315d2SPatrick Williams             // priorities across groups need to match.
133953315d2SPatrick Williams             validatePriority(name, priority, priorityMap);
134953315d2SPatrick Williams 
135953315d2SPatrick Williams             phosphor::led::Layout::LedAction ledAction{name, action, dutyOn,
136953315d2SPatrick Williams                                                        period, priority};
137953315d2SPatrick Williams             ledActions.emplace(ledAction);
138953315d2SPatrick Williams         }
139953315d2SPatrick Williams 
140f2044037SPatrick Williams         // Generated an std::unordered_map of LedGroupNames to std::set of LEDs
141953315d2SPatrick Williams         // containing the name and properties.
142953315d2SPatrick Williams         ledMap.emplace(objpath, ledActions);
143953315d2SPatrick Williams     }
144953315d2SPatrick Williams 
145953315d2SPatrick Williams     return ledMap;
146953315d2SPatrick Williams }
147953315d2SPatrick Williams 
14873ff9ad6SPatrick Williams /** @brief Load JSON config and return led map
14973ff9ad6SPatrick Williams  *
150*158b2c14SPatrick Williams  *  @return phosphor::led::GroupMap
15173ff9ad6SPatrick Williams  */
152*158b2c14SPatrick Williams const phosphor::led::GroupMap loadJsonConfig(const fs::path& path)
15373ff9ad6SPatrick Williams {
15473ff9ad6SPatrick Williams     auto json = readJson(path);
15573ff9ad6SPatrick Williams 
15673ff9ad6SPatrick Williams     auto version = json.value("version", 1);
15773ff9ad6SPatrick Williams     switch (version)
15873ff9ad6SPatrick Williams     {
15973ff9ad6SPatrick Williams         case 1:
16073ff9ad6SPatrick Williams             return loadJsonConfigV1(json);
16173ff9ad6SPatrick Williams 
16273ff9ad6SPatrick Williams         default:
16373ff9ad6SPatrick Williams             lg2::error("Unsupported JSON Version: {VERSION}", "VERSION",
16473ff9ad6SPatrick Williams                        version);
16573ff9ad6SPatrick Williams             throw std::runtime_error("Unsupported version");
16673ff9ad6SPatrick Williams     }
16773ff9ad6SPatrick Williams 
168*158b2c14SPatrick Williams     return phosphor::led::GroupMap{};
16973ff9ad6SPatrick Williams }
17073ff9ad6SPatrick Williams 
171953315d2SPatrick Williams /** @brief Get led map from LED groups JSON config
172953315d2SPatrick Williams  *
1737217c035SPatrick Williams  *  @param[in] config - Path to the JSON config.
174*158b2c14SPatrick Williams  *  @return phosphor::led::GroupMap
1757217c035SPatrick Williams  *
1767217c035SPatrick Williams  *  @note if config is an empty string, daemon will interrogate dbus for
1777217c035SPatrick Williams  *        compatible strings.
178953315d2SPatrick Williams  */
179*158b2c14SPatrick Williams const phosphor::led::GroupMap getSystemLedMap(fs::path config)
180953315d2SPatrick Williams {
1817217c035SPatrick Williams     if (config.empty())
182953315d2SPatrick Williams     {
1837217c035SPatrick Williams         config = phosphor::led::getJsonConfig();
184953315d2SPatrick Williams     }
185953315d2SPatrick Williams 
1867217c035SPatrick Williams     return loadJsonConfig(config);
187953315d2SPatrick Williams }
188