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