1*953315d2SPatrick Williams #include "config.h" 2*953315d2SPatrick Williams 3*953315d2SPatrick Williams #include "json-config.hpp" 4*953315d2SPatrick Williams #include "ledlayout.hpp" 5*953315d2SPatrick Williams 6*953315d2SPatrick Williams #include <nlohmann/json.hpp> 7*953315d2SPatrick Williams #include <phosphor-logging/lg2.hpp> 8*953315d2SPatrick Williams #include <sdbusplus/bus.hpp> 9*953315d2SPatrick Williams #include <sdeventplus/event.hpp> 10*953315d2SPatrick Williams 11*953315d2SPatrick Williams #include <filesystem> 12*953315d2SPatrick Williams #include <fstream> 13*953315d2SPatrick Williams #include <iostream> 14*953315d2SPatrick Williams 15*953315d2SPatrick Williams namespace fs = std::filesystem; 16*953315d2SPatrick Williams 17*953315d2SPatrick Williams using Json = nlohmann::json; 18*953315d2SPatrick Williams using LedAction = std::set<phosphor::led::Layout::LedAction>; 19*953315d2SPatrick Williams using LedMap = std::map<std::string, LedAction>; 20*953315d2SPatrick Williams 21*953315d2SPatrick Williams // Priority for a particular LED needs to stay SAME across all groups 22*953315d2SPatrick Williams // phosphor::led::Layout::Action can only be one of `Blink` and `On` 23*953315d2SPatrick Williams using PriorityMap = std::map<std::string, phosphor::led::Layout::Action>; 24*953315d2SPatrick Williams 25*953315d2SPatrick Williams /** @brief Parse LED JSON file and output Json object 26*953315d2SPatrick Williams * 27*953315d2SPatrick Williams * @param[in] path - path of LED JSON file 28*953315d2SPatrick Williams * 29*953315d2SPatrick Williams * @return const Json - Json object 30*953315d2SPatrick Williams */ 31*953315d2SPatrick Williams const Json readJson(const fs::path& path) 32*953315d2SPatrick Williams { 33*953315d2SPatrick Williams 34*953315d2SPatrick Williams if (!fs::exists(path) || fs::is_empty(path)) 35*953315d2SPatrick Williams { 36*953315d2SPatrick Williams lg2::error("Incorrect File Path or empty file, FILE_PATH = {PATH}", 37*953315d2SPatrick Williams "PATH", path); 38*953315d2SPatrick Williams throw std::runtime_error("Incorrect File Path or empty file"); 39*953315d2SPatrick Williams } 40*953315d2SPatrick Williams 41*953315d2SPatrick Williams try 42*953315d2SPatrick Williams { 43*953315d2SPatrick Williams std::ifstream jsonFile(path); 44*953315d2SPatrick Williams return Json::parse(jsonFile); 45*953315d2SPatrick Williams } 46*953315d2SPatrick Williams catch (const std::exception& e) 47*953315d2SPatrick Williams { 48*953315d2SPatrick Williams lg2::error( 49*953315d2SPatrick Williams "Failed to parse config file, ERROR = {ERROR}, FILE_PATH = {PATH}", 50*953315d2SPatrick Williams "ERROR", e, "PATH", path); 51*953315d2SPatrick Williams throw std::runtime_error("Failed to parse config file"); 52*953315d2SPatrick Williams } 53*953315d2SPatrick Williams } 54*953315d2SPatrick Williams 55*953315d2SPatrick Williams /** @brief Returns action enum based on string 56*953315d2SPatrick Williams * 57*953315d2SPatrick Williams * @param[in] action - action string 58*953315d2SPatrick Williams * 59*953315d2SPatrick Williams * @return Action - action enum (On/Blink) 60*953315d2SPatrick Williams */ 61*953315d2SPatrick Williams phosphor::led::Layout::Action getAction(const std::string& action) 62*953315d2SPatrick Williams { 63*953315d2SPatrick Williams assert(action == "On" || action == "Blink"); 64*953315d2SPatrick Williams 65*953315d2SPatrick Williams return action == "Blink" ? phosphor::led::Layout::Blink 66*953315d2SPatrick Williams : phosphor::led::Layout::On; 67*953315d2SPatrick Williams } 68*953315d2SPatrick Williams 69*953315d2SPatrick Williams /** @brief Validate the Priority of an LED is same across ALL groups 70*953315d2SPatrick Williams * 71*953315d2SPatrick Williams * @param[in] name - led name member of each group 72*953315d2SPatrick Williams * @param[in] priority - member priority of each group 73*953315d2SPatrick Williams * @param[out] priorityMap - std::map, key:name, value:priority 74*953315d2SPatrick Williams * 75*953315d2SPatrick Williams * @return 76*953315d2SPatrick Williams */ 77*953315d2SPatrick Williams void validatePriority(const std::string& name, 78*953315d2SPatrick Williams const phosphor::led::Layout::Action& priority, 79*953315d2SPatrick Williams PriorityMap& priorityMap) 80*953315d2SPatrick Williams { 81*953315d2SPatrick Williams 82*953315d2SPatrick Williams auto iter = priorityMap.find(name); 83*953315d2SPatrick Williams if (iter == priorityMap.end()) 84*953315d2SPatrick Williams { 85*953315d2SPatrick Williams priorityMap.emplace(name, priority); 86*953315d2SPatrick Williams return; 87*953315d2SPatrick Williams } 88*953315d2SPatrick Williams 89*953315d2SPatrick Williams if (iter->second != priority) 90*953315d2SPatrick Williams { 91*953315d2SPatrick Williams lg2::error( 92*953315d2SPatrick Williams "Priority of LED is not same across all, Name = {NAME}, Old Priority = {OLD_PRIO}, New Priority = {NEW_PRIO}", 93*953315d2SPatrick Williams "NAME", name, "OLD_PRIO", int(iter->second), "NEW_PRIO", 94*953315d2SPatrick Williams int(priority)); 95*953315d2SPatrick Williams 96*953315d2SPatrick Williams throw std::runtime_error( 97*953315d2SPatrick Williams "Priority of at least one LED is not same across groups"); 98*953315d2SPatrick Williams } 99*953315d2SPatrick Williams } 100*953315d2SPatrick Williams 101*953315d2SPatrick Williams /** @brief Load JSON config and return led map 102*953315d2SPatrick Williams * 103*953315d2SPatrick Williams * @return LedMap - Generated an std::map of LedAction 104*953315d2SPatrick Williams */ 105*953315d2SPatrick Williams const LedMap loadJsonConfig(const fs::path& path) 106*953315d2SPatrick Williams { 107*953315d2SPatrick Williams LedMap ledMap{}; 108*953315d2SPatrick Williams PriorityMap priorityMap{}; 109*953315d2SPatrick Williams 110*953315d2SPatrick Williams // define the default JSON as empty 111*953315d2SPatrick Williams const Json empty{}; 112*953315d2SPatrick Williams auto json = readJson(path); 113*953315d2SPatrick Williams auto leds = json.value("leds", empty); 114*953315d2SPatrick Williams 115*953315d2SPatrick Williams for (const auto& entry : leds) 116*953315d2SPatrick Williams { 117*953315d2SPatrick Williams fs::path tmpPath(std::string{OBJPATH}); 118*953315d2SPatrick Williams tmpPath /= entry.value("group", ""); 119*953315d2SPatrick Williams auto objpath = tmpPath.string(); 120*953315d2SPatrick Williams auto members = entry.value("members", empty); 121*953315d2SPatrick Williams 122*953315d2SPatrick Williams LedAction ledActions{}; 123*953315d2SPatrick Williams for (const auto& member : members) 124*953315d2SPatrick Williams { 125*953315d2SPatrick Williams auto name = member.value("Name", ""); 126*953315d2SPatrick Williams auto action = getAction(member.value("Action", "")); 127*953315d2SPatrick Williams uint8_t dutyOn = member.value("DutyOn", 50); 128*953315d2SPatrick Williams uint16_t period = member.value("Period", 0); 129*953315d2SPatrick Williams 130*953315d2SPatrick Williams // Since only have Blink/On and default priority is Blink 131*953315d2SPatrick Williams auto priority = getAction(member.value("Priority", "Blink")); 132*953315d2SPatrick Williams 133*953315d2SPatrick Williams // Same LEDs can be part of multiple groups. However, their 134*953315d2SPatrick Williams // priorities across groups need to match. 135*953315d2SPatrick Williams validatePriority(name, priority, priorityMap); 136*953315d2SPatrick Williams 137*953315d2SPatrick Williams phosphor::led::Layout::LedAction ledAction{name, action, dutyOn, 138*953315d2SPatrick Williams period, priority}; 139*953315d2SPatrick Williams ledActions.emplace(ledAction); 140*953315d2SPatrick Williams } 141*953315d2SPatrick Williams 142*953315d2SPatrick Williams // Generated an std::map of LedGroupNames to std::set of LEDs 143*953315d2SPatrick Williams // containing the name and properties. 144*953315d2SPatrick Williams ledMap.emplace(objpath, ledActions); 145*953315d2SPatrick Williams } 146*953315d2SPatrick Williams 147*953315d2SPatrick Williams return ledMap; 148*953315d2SPatrick Williams } 149*953315d2SPatrick Williams 150*953315d2SPatrick Williams /** @brief Get led map from LED groups JSON config 151*953315d2SPatrick Williams * 152*953315d2SPatrick Williams * @return LedMap - Generated an std::map of LedAction 153*953315d2SPatrick Williams */ 154*953315d2SPatrick Williams const LedMap getSystemLedMap() 155*953315d2SPatrick Williams { 156*953315d2SPatrick Williams // Get a new Dbus 157*953315d2SPatrick Williams auto bus = sdbusplus::bus::new_bus(); 158*953315d2SPatrick Williams 159*953315d2SPatrick Williams // Get a new event loop 160*953315d2SPatrick Williams auto event = sdeventplus::Event::get_new(); 161*953315d2SPatrick Williams 162*953315d2SPatrick Williams // Attach the bus to sd_event to service user requests 163*953315d2SPatrick Williams bus.attach_event(event.get(), SD_EVENT_PRIORITY_IMPORTANT); 164*953315d2SPatrick Williams phosphor::led::JsonConfig jsonConfig(bus, event); 165*953315d2SPatrick Williams 166*953315d2SPatrick Williams // The event loop will be terminated from inside of a function in JsonConfig 167*953315d2SPatrick Williams // after finding the configuration file 168*953315d2SPatrick Williams if (jsonConfig.getConfFile().empty()) 169*953315d2SPatrick Williams { 170*953315d2SPatrick Williams event.loop(); 171*953315d2SPatrick Williams } 172*953315d2SPatrick Williams 173*953315d2SPatrick Williams // Detach the bus from its sd_event event loop object 174*953315d2SPatrick Williams bus.detach_event(); 175*953315d2SPatrick Williams 176*953315d2SPatrick Williams return loadJsonConfig(jsonConfig.getConfFile()); 177*953315d2SPatrick Williams } 178