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_context.hpp> 21 #include <nlohmann/json.hpp> 22 #include <phosphor-logging/log.hpp> 23 24 #include <fstream> 25 26 using namespace phosphor::logging; 27 28 namespace phosphor 29 { 30 namespace gpio 31 { 32 33 std::map<std::string, int> polarityMap = { 34 /**< Only watch falling edge events. */ 35 {"FALLING", GPIOD_LINE_REQUEST_EVENT_FALLING_EDGE}, 36 /**< Only watch rising edge events. */ 37 {"RISING", GPIOD_LINE_REQUEST_EVENT_RISING_EDGE}, 38 /**< Monitor both types of events. */ 39 {"BOTH", GPIOD_LINE_REQUEST_EVENT_BOTH_EDGES}}; 40 41 } 42 } // namespace phosphor 43 44 int main(int argc, char** argv) 45 { 46 boost::asio::io_context 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 (const 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 /* GPIO Line message */ 85 std::string lineMsg = "GPIO Line "; 86 87 /* GPIO line */ 88 gpiod_line* line = NULL; 89 90 /* Log message string */ 91 std::string errMsg; 92 93 /* GPIO line configuration, default to monitor both edge */ 94 struct gpiod_line_request_config config 95 { 96 "gpio_monitor", GPIOD_LINE_REQUEST_EVENT_BOTH_EDGES, 0 97 }; 98 99 /* flag to monitor */ 100 bool flag = false; 101 102 /* target to start */ 103 std::string target; 104 105 /* multi targets to start */ 106 std::map<std::string, std::vector<std::string>> targets; 107 108 if (obj.find("LineName") == obj.end()) 109 { 110 /* If there is no line Name defined then gpio num nd chip 111 * id must be defined. GpioNum is integer mapping to the 112 * GPIO key configured by the kernel 113 */ 114 if (obj.find("GpioNum") == obj.end() || 115 obj.find("ChipId") == obj.end()) 116 { 117 log<level::ERR>( 118 "Failed to find line name or gpio number", 119 entry("GPIO_JSON_FILE_NAME=%s", gpioFileName.c_str())); 120 return -1; 121 } 122 123 std::string chipIdStr = obj["ChipId"]; 124 int gpioNum = obj["GpioNum"]; 125 126 lineMsg += std::to_string(gpioNum); 127 128 /* Get the GPIO line */ 129 line = gpiod_line_get(chipIdStr.c_str(), gpioNum); 130 } 131 else 132 { 133 /* Find the GPIO line */ 134 std::string lineName = obj["LineName"]; 135 lineMsg += lineName; 136 line = gpiod_line_find(lineName.c_str()); 137 } 138 139 if (line == NULL) 140 { 141 errMsg = "Failed to find the " + lineMsg; 142 log<level::ERR>(errMsg.c_str()); 143 return -1; 144 } 145 146 /* Get event to be monitored, if it is not defined then 147 * Both rising falling edge will be monitored. 148 */ 149 if (obj.find("EventMon") != obj.end()) 150 { 151 std::string eventStr = obj["EventMon"]; 152 auto findEvent = phosphor::gpio::polarityMap.find(eventStr); 153 if (findEvent == phosphor::gpio::polarityMap.end()) 154 { 155 errMsg = "Incorrect GPIO monitor event defined " + lineMsg; 156 log<level::ERR>(errMsg.c_str()); 157 return -1; 158 } 159 160 config.request_type = findEvent->second; 161 } 162 163 /* Get flag if monitoring needs to continue after first event */ 164 if (obj.find("Continue") != obj.end()) 165 { 166 flag = obj["Continue"]; 167 } 168 169 /* Parse out target argument. It is fine if the user does not 170 * pass this if they are not interested in calling into any target 171 * on meeting a condition. 172 */ 173 if (obj.find("Target") != obj.end()) 174 { 175 target = obj["Target"]; 176 } 177 178 /* Parse out the targets argument if multi-targets are needed.*/ 179 if (obj.find("Targets") != obj.end()) 180 { 181 obj.at("Targets").get_to(targets); 182 } 183 184 /* Create a monitor object and let it do all the rest */ 185 gpios.push_back(std::make_unique<phosphor::gpio::GpioMonitor>( 186 line, config, io, target, targets, lineMsg, flag)); 187 } 188 io.run(); 189 190 return 0; 191 } 192