1 #include "config.h" 2 3 #include "config-validator.hpp" 4 #include "grouplayout.hpp" 5 #include "json-config.hpp" 6 #include "ledlayout.hpp" 7 8 #include <nlohmann/json.hpp> 9 #include <phosphor-logging/lg2.hpp> 10 #include <sdbusplus/bus.hpp> 11 #include <sdeventplus/event.hpp> 12 13 #include <filesystem> 14 #include <fstream> 15 #include <iostream> 16 17 namespace fs = std::filesystem; 18 19 using Json = nlohmann::json; 20 21 // Priority for a particular LED needs to stay SAME across all groups 22 using PriorityMap = 23 std::unordered_map<std::string, 24 std::optional<phosphor::led::Layout::Action>>; 25 26 /** @brief Parse LED JSON file and output Json object 27 * 28 * @param[in] path - path of LED JSON file 29 * 30 * @return const Json - Json object 31 */ 32 Json readJson(const fs::path& path) 33 { 34 if (!fs::exists(path) || fs::is_empty(path)) 35 { 36 lg2::error("Incorrect File Path or empty file, FILE_PATH = {PATH}", 37 "PATH", path); 38 throw std::runtime_error("Incorrect File Path or empty file"); 39 } 40 41 try 42 { 43 std::ifstream jsonFile(path); 44 return Json::parse(jsonFile); 45 } 46 catch (const std::exception& e) 47 { 48 lg2::error( 49 "Failed to parse config file, ERROR = {ERROR}, FILE_PATH = {PATH}", 50 "ERROR", e, "PATH", path); 51 throw std::runtime_error("Failed to parse config file"); 52 } 53 } 54 55 /** @brief Returns action enum based on string 56 * 57 * @param[in] action - action string 58 * 59 * @return Action - action enum (On/Off/Blink) 60 */ 61 phosphor::led::Layout::Action getAction(const std::string& action) 62 { 63 if (action == "On") 64 { 65 return phosphor::led::Layout::Action::On; 66 } 67 if (action == "Off") 68 { 69 return phosphor::led::Layout::Action::Off; 70 } 71 if (action == "Blink") 72 { 73 return phosphor::led::Layout::Action::Blink; 74 } 75 76 assert(false); 77 return phosphor::led::Layout::Action::Blink; 78 } 79 80 static void loadJsonConfigV1GroupMember(const Json& member, 81 phosphor::led::ActionSet& ledActions) 82 { 83 auto name = member.value("Name", ""); 84 auto action = getAction(member.value("Action", "")); 85 uint8_t dutyOn = member.value("DutyOn", 50); 86 uint16_t period = member.value("Period", 0); 87 88 const std::string priorityStr = member.value("Priority", ""); 89 std::optional<phosphor::led::Layout::Action> priority = std::nullopt; 90 91 if (!priorityStr.empty()) 92 { 93 priority = getAction(priorityStr); 94 } 95 96 phosphor::led::Layout::LedAction ledAction{name, action, dutyOn, period, 97 priority}; 98 ledActions.emplace(ledAction); 99 } 100 101 static void loadJsonConfigV1Group(const Json& entry, 102 phosphor::led::GroupMap& ledMap) 103 { 104 const Json empty{}; 105 106 fs::path tmpPath("/xyz/openbmc_project/led/groups"); 107 108 const std::string groupName = entry.value("group", ""); 109 110 tmpPath /= groupName; 111 auto objpath = tmpPath.string(); 112 auto members = entry.value("members", empty); 113 114 lg2::debug("config for '{GROUP}'", "GROUP", groupName); 115 116 int priority = entry.value("Priority", 0); 117 118 phosphor::led::ActionSet ledActions{}; 119 phosphor::led::Layout::GroupLayout groupLayout{}; 120 for (const auto& member : members) 121 { 122 loadJsonConfigV1GroupMember(member, ledActions); 123 } 124 125 // Generated an std::unordered_map of LedGroupNames to std::set of LEDs 126 // containing the name and properties. 127 groupLayout.actionSet = ledActions; 128 groupLayout.priority = priority; 129 130 ledMap.emplace(objpath, groupLayout); 131 } 132 133 /** @brief Load JSON config and return led map (JSON version 1) 134 * 135 * @return phosphor::led::GroupMap 136 */ 137 const phosphor::led::GroupMap loadJsonConfigV1(const Json& json) 138 { 139 phosphor::led::GroupMap ledMap{}; 140 141 // define the default JSON as empty 142 const Json empty{}; 143 auto leds = json.value("leds", empty); 144 145 for (const auto& entry : leds) 146 { 147 loadJsonConfigV1Group(entry, ledMap); 148 } 149 150 return ledMap; 151 } 152 153 /** @brief Load JSON config and return led map 154 * 155 * @return phosphor::led::GroupMap 156 */ 157 const phosphor::led::GroupMap loadJsonConfig(const fs::path& path) 158 { 159 auto json = readJson(path); 160 161 auto version = json.value("version", 1); 162 switch (version) 163 { 164 case 1: 165 return loadJsonConfigV1(json); 166 167 default: 168 lg2::error("Unsupported JSON Version: {VERSION}", "VERSION", 169 version); 170 throw std::runtime_error("Unsupported version"); 171 } 172 173 return phosphor::led::GroupMap{}; 174 } 175 176 /** @brief Get led map from LED groups JSON config 177 * 178 * @param[in] config - Path to the JSON config. 179 * @return phosphor::led::GroupMap 180 * 181 * @note if config is an empty string, daemon will interrogate dbus for 182 * compatible strings. 183 */ 184 const phosphor::led::GroupMap getSystemLedMap(fs::path config) 185 { 186 if (config.empty()) 187 { 188 config = phosphor::led::getJsonConfig(); 189 } 190 191 return loadJsonConfig(config); 192 } 193