1*939a6431SVijay Khemka /** 2*939a6431SVijay Khemka * Copyright © 2019 Facebook 3*939a6431SVijay Khemka * 4*939a6431SVijay Khemka * Licensed under the Apache License, Version 2.0 (the "License"); 5*939a6431SVijay Khemka * you may not use this file except in compliance with the License. 6*939a6431SVijay Khemka * You may obtain a copy of the License at 7*939a6431SVijay Khemka * 8*939a6431SVijay Khemka * http://www.apache.org/licenses/LICENSE-2.0 9*939a6431SVijay Khemka * 10*939a6431SVijay Khemka * Unless required by applicable law or agreed to in writing, software 11*939a6431SVijay Khemka * distributed under the License is distributed on an "AS IS" BASIS, 12*939a6431SVijay Khemka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*939a6431SVijay Khemka * See the License for the specific language governing permissions and 14*939a6431SVijay Khemka * limitations under the License. 15*939a6431SVijay Khemka */ 16*939a6431SVijay Khemka 17*939a6431SVijay Khemka #include "gpioMon.hpp" 18*939a6431SVijay Khemka 19*939a6431SVijay Khemka #include <CLI/CLI.hpp> 20*939a6431SVijay Khemka #include <boost/asio/io_service.hpp> 21*939a6431SVijay Khemka #include <fstream> 22*939a6431SVijay Khemka #include <nlohmann/json.hpp> 23*939a6431SVijay Khemka #include <phosphor-logging/log.hpp> 24*939a6431SVijay Khemka 25*939a6431SVijay Khemka using namespace phosphor::logging; 26*939a6431SVijay Khemka 27*939a6431SVijay Khemka namespace phosphor 28*939a6431SVijay Khemka { 29*939a6431SVijay Khemka namespace gpio 30*939a6431SVijay Khemka { 31*939a6431SVijay Khemka 32*939a6431SVijay Khemka std::map<std::string, int> polarityMap = { 33*939a6431SVijay Khemka /**< Only watch falling edge events. */ 34*939a6431SVijay Khemka {"FALLING", GPIOD_LINE_REQUEST_EVENT_FALLING_EDGE}, 35*939a6431SVijay Khemka /**< Only watch rising edge events. */ 36*939a6431SVijay Khemka {"RISING", GPIOD_LINE_REQUEST_EVENT_RISING_EDGE}, 37*939a6431SVijay Khemka /**< Monitor both types of events. */ 38*939a6431SVijay Khemka {"BOTH", GPIOD_LINE_REQUEST_EVENT_BOTH_EDGES}}; 39*939a6431SVijay Khemka 40*939a6431SVijay Khemka } 41*939a6431SVijay Khemka } // namespace phosphor 42*939a6431SVijay Khemka 43*939a6431SVijay Khemka int main(int argc, char** argv) 44*939a6431SVijay Khemka { 45*939a6431SVijay Khemka 46*939a6431SVijay Khemka boost::asio::io_service io; 47*939a6431SVijay Khemka 48*939a6431SVijay Khemka CLI::App app{"Monitor GPIO line for requested state change"}; 49*939a6431SVijay Khemka 50*939a6431SVijay Khemka std::string gpioFileName; 51*939a6431SVijay Khemka 52*939a6431SVijay Khemka /* Add an input option */ 53*939a6431SVijay Khemka app.add_option("-c,--config", gpioFileName, "Name of config json file") 54*939a6431SVijay Khemka ->required() 55*939a6431SVijay Khemka ->check(CLI::ExistingFile); 56*939a6431SVijay Khemka 57*939a6431SVijay Khemka /* Parse input parameter */ 58*939a6431SVijay Khemka try 59*939a6431SVijay Khemka { 60*939a6431SVijay Khemka app.parse(argc, argv); 61*939a6431SVijay Khemka } 62*939a6431SVijay Khemka catch (CLI::Error& e) 63*939a6431SVijay Khemka { 64*939a6431SVijay Khemka return app.exit(e); 65*939a6431SVijay Khemka } 66*939a6431SVijay Khemka 67*939a6431SVijay Khemka /* Get list of gpio config details from json file */ 68*939a6431SVijay Khemka std::ifstream file(gpioFileName); 69*939a6431SVijay Khemka if (!file) 70*939a6431SVijay Khemka { 71*939a6431SVijay Khemka log<level::ERR>("GPIO monitor config file not found", 72*939a6431SVijay Khemka entry("GPIO_MON_FILE=%s", gpioFileName.c_str())); 73*939a6431SVijay Khemka return -1; 74*939a6431SVijay Khemka } 75*939a6431SVijay Khemka 76*939a6431SVijay Khemka nlohmann::json gpioMonObj; 77*939a6431SVijay Khemka file >> gpioMonObj; 78*939a6431SVijay Khemka file.close(); 79*939a6431SVijay Khemka 80*939a6431SVijay Khemka std::vector<std::unique_ptr<phosphor::gpio::GpioMonitor>> gpios; 81*939a6431SVijay Khemka 82*939a6431SVijay Khemka for (auto& obj : gpioMonObj) 83*939a6431SVijay Khemka { 84*939a6431SVijay Khemka 85*939a6431SVijay Khemka /* GPIO Line message */ 86*939a6431SVijay Khemka std::string lineMsg = "GPIO Line "; 87*939a6431SVijay Khemka 88*939a6431SVijay Khemka /* GPIO line */ 89*939a6431SVijay Khemka gpiod_line* line = NULL; 90*939a6431SVijay Khemka 91*939a6431SVijay Khemka /* Log message string */ 92*939a6431SVijay Khemka std::string errMsg; 93*939a6431SVijay Khemka 94*939a6431SVijay Khemka /* GPIO line configuration, default to monitor both edge */ 95*939a6431SVijay Khemka struct gpiod_line_request_config config 96*939a6431SVijay Khemka { 97*939a6431SVijay Khemka "gpio_monitor", GPIOD_LINE_REQUEST_EVENT_BOTH_EDGES, 0 98*939a6431SVijay Khemka }; 99*939a6431SVijay Khemka 100*939a6431SVijay Khemka /* flag to monitor */ 101*939a6431SVijay Khemka bool flag = false; 102*939a6431SVijay Khemka 103*939a6431SVijay Khemka /* target to start */ 104*939a6431SVijay Khemka std::string target; 105*939a6431SVijay Khemka 106*939a6431SVijay Khemka if (obj.find("LineName") == obj.end()) 107*939a6431SVijay Khemka { 108*939a6431SVijay Khemka /* If there is no line Name defined then gpio num nd chip 109*939a6431SVijay Khemka * id must be defined. GpioNum is integer mapping to the 110*939a6431SVijay Khemka * GPIO key configured by the kernel 111*939a6431SVijay Khemka */ 112*939a6431SVijay Khemka if (obj.find("GpioNum") == obj.end() || 113*939a6431SVijay Khemka obj.find("ChipId") == obj.end()) 114*939a6431SVijay Khemka { 115*939a6431SVijay Khemka log<level::ERR>( 116*939a6431SVijay Khemka "Failed to find line name or gpio number", 117*939a6431SVijay Khemka entry("GPIO_JSON_FILE_NAME=%s", gpioFileName.c_str())); 118*939a6431SVijay Khemka return -1; 119*939a6431SVijay Khemka } 120*939a6431SVijay Khemka 121*939a6431SVijay Khemka std::string chipIdStr = obj["ChipId"]; 122*939a6431SVijay Khemka int gpioNum = obj["GpioNum"]; 123*939a6431SVijay Khemka 124*939a6431SVijay Khemka lineMsg += std::to_string(gpioNum); 125*939a6431SVijay Khemka 126*939a6431SVijay Khemka /* Get the GPIO line */ 127*939a6431SVijay Khemka line = gpiod_line_get(chipIdStr.c_str(), gpioNum); 128*939a6431SVijay Khemka } 129*939a6431SVijay Khemka else 130*939a6431SVijay Khemka { 131*939a6431SVijay Khemka /* Find the GPIO line */ 132*939a6431SVijay Khemka std::string lineName = obj["LineName"]; 133*939a6431SVijay Khemka lineMsg += lineName; 134*939a6431SVijay Khemka line = gpiod_line_find(lineName.c_str()); 135*939a6431SVijay Khemka } 136*939a6431SVijay Khemka 137*939a6431SVijay Khemka if (line == NULL) 138*939a6431SVijay Khemka { 139*939a6431SVijay Khemka errMsg = "Failed to find the " + lineMsg; 140*939a6431SVijay Khemka log<level::ERR>(errMsg.c_str()); 141*939a6431SVijay Khemka return -1; 142*939a6431SVijay Khemka } 143*939a6431SVijay Khemka 144*939a6431SVijay Khemka /* Get event to be monitored, if it is not defined then 145*939a6431SVijay Khemka * Both rising falling edge will be monitored. 146*939a6431SVijay Khemka */ 147*939a6431SVijay Khemka if (obj.find("EventMon") != obj.end()) 148*939a6431SVijay Khemka { 149*939a6431SVijay Khemka std::string eventStr = obj["EventMon"]; 150*939a6431SVijay Khemka auto findEvent = phosphor::gpio::polarityMap.find(eventStr); 151*939a6431SVijay Khemka if (findEvent == phosphor::gpio::polarityMap.end()) 152*939a6431SVijay Khemka { 153*939a6431SVijay Khemka errMsg = "Incorrect GPIO monitor event defined " + lineMsg; 154*939a6431SVijay Khemka log<level::ERR>(errMsg.c_str()); 155*939a6431SVijay Khemka return -1; 156*939a6431SVijay Khemka } 157*939a6431SVijay Khemka 158*939a6431SVijay Khemka config.request_type = findEvent->second; 159*939a6431SVijay Khemka } 160*939a6431SVijay Khemka 161*939a6431SVijay Khemka /* Get flag if monitoring needs to continue after first event */ 162*939a6431SVijay Khemka if (obj.find("Continue") != obj.end()) 163*939a6431SVijay Khemka { 164*939a6431SVijay Khemka flag = obj["Continue"]; 165*939a6431SVijay Khemka } 166*939a6431SVijay Khemka 167*939a6431SVijay Khemka /* Parse out target argument. It is fine if the user does not 168*939a6431SVijay Khemka * pass this if they are not interested in calling into any target 169*939a6431SVijay Khemka * on meeting a condition. 170*939a6431SVijay Khemka */ 171*939a6431SVijay Khemka if (obj.find("Target") != obj.end()) 172*939a6431SVijay Khemka { 173*939a6431SVijay Khemka target = obj["Target"]; 174*939a6431SVijay Khemka } 175*939a6431SVijay Khemka 176*939a6431SVijay Khemka /* Create a monitor object and let it do all the rest */ 177*939a6431SVijay Khemka gpios.push_back(std::make_unique<phosphor::gpio::GpioMonitor>( 178*939a6431SVijay Khemka line, config, io, target, lineMsg, flag)); 179*939a6431SVijay Khemka } 180*939a6431SVijay Khemka io.run(); 181*939a6431SVijay Khemka 182*939a6431SVijay Khemka return 0; 183*939a6431SVijay Khemka } 184