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