1 /** 2 * Copyright © 2019 Facebook 3 * Copyright © 2023 9elements GmbH 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 #include "gpio_presence.hpp" 19 20 #include <CLI/CLI.hpp> 21 #include <boost/asio/io_context.hpp> 22 #include <nlohmann/json.hpp> 23 #include <phosphor-logging/lg2.hpp> 24 25 #include <fstream> 26 27 namespace phosphor 28 { 29 namespace gpio 30 { 31 32 const std::map<std::string, int> biasMap = { 33 /**< Set bias as is. */ 34 {"AS_IS", 0}, 35 /**< Disable bias. */ 36 {"DISABLE", GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE}, 37 /**< Enable pull-up. */ 38 {"PULL_UP", GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP}, 39 /**< Enable pull-down. */ 40 {"PULL_DOWN", GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN}}; 41 } 42 } // namespace phosphor 43 main(int argc,char ** argv)44 int main(int argc, char** argv) 45 { 46 boost::asio::io_context io; 47 48 CLI::App app{"Monitor gpio presence status"}; 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 lg2::error("Failed to open config file: {FILE}", "FILE", gpioFileName); 72 return -1; 73 } 74 75 nlohmann::json gpioMonObj; 76 file >> gpioMonObj; 77 file.close(); 78 79 std::vector<phosphor::gpio::GpioPresence> gpios; 80 81 for (auto& obj : gpioMonObj) 82 { 83 /* GPIO Line message */ 84 std::string lineMsg = "GPIO Line "; 85 86 /* GPIO line */ 87 gpiod_line* line = nullptr; 88 89 /* GPIO line configuration, default to monitor both edge */ 90 struct gpiod_line_request_config config{ 91 "gpio_monitor", GPIOD_LINE_REQUEST_EVENT_BOTH_EDGES, 0}; 92 93 /* Pretty name of the inventory object */ 94 std::string name; 95 96 /* Object path under inventory that will be created */ 97 std::string inventory; 98 99 /* List of interfaces to associate to inventory item */ 100 std::vector<std::string> extraInterfaces; 101 102 if (obj.find("LineName") == obj.end()) 103 { 104 /* If there is no line Name defined then gpio num nd chip 105 * id must be defined. GpioNum is integer mapping to the 106 * GPIO key configured by the kernel 107 */ 108 if (obj.find("GpioNum") == obj.end() || 109 obj.find("ChipId") == obj.end()) 110 { 111 lg2::error("Failed to find line name or gpio number: {FILE}", 112 "FILE", gpioFileName); 113 return -1; 114 } 115 116 std::string chipIdStr = obj["ChipId"].get<std::string>(); 117 int gpioNum = obj["GpioNum"].get<int>(); 118 119 lineMsg += chipIdStr + " " + std::to_string(gpioNum); 120 121 /* Get the GPIO line */ 122 line = gpiod_line_get(chipIdStr.c_str(), gpioNum); 123 } 124 else 125 { 126 /* Find the GPIO line */ 127 std::string lineName = obj["LineName"].get<std::string>(); 128 lineMsg += lineName; 129 line = gpiod_line_find(lineName.c_str()); 130 } 131 132 if (line == nullptr) 133 { 134 lg2::error("Failed to find the {GPIO}", "GPIO", lineMsg); 135 continue; 136 } 137 138 /* Parse out inventory argument. */ 139 if (obj.find("Inventory") == obj.end()) 140 { 141 lg2::error("{GPIO}: Inventory path not specified", "GPIO", lineMsg); 142 return -1; 143 } 144 else 145 { 146 inventory = obj["Inventory"].get<std::string>(); 147 } 148 149 if (obj.find("Name") == obj.end()) 150 { 151 lg2::error("{GPIO}: Name path not specified", "GPIO", lineMsg); 152 return -1; 153 } 154 else 155 { 156 name = obj["Name"].get<std::string>(); 157 } 158 159 /* Parse optional bias */ 160 if (obj.find("Bias") != obj.end()) 161 { 162 std::string biasName = obj["Bias"].get<std::string>(); 163 auto findBias = phosphor::gpio::biasMap.find(biasName); 164 if (findBias == phosphor::gpio::biasMap.end()) 165 { 166 lg2::error("{GPIO}: Bias unknown: {BIAS}", "GPIO", lineMsg, 167 "BIAS", biasName); 168 return -1; 169 } 170 171 config.flags = findBias->second; 172 } 173 174 /* Parse optional active level */ 175 if (obj.find("ActiveLow") != obj.end() && obj["ActiveLow"].get<bool>()) 176 { 177 config.flags |= GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW; 178 } 179 180 /* Parse optional extra interfaces */ 181 if (obj.find("ExtraInterfaces") != obj.end()) 182 { 183 obj.at("ExtraInterfaces").get_to(extraInterfaces); 184 } 185 186 /* Create a monitor object and let it do all the rest */ 187 gpios.push_back(phosphor::gpio::GpioPresence( 188 line, config, io, inventory, extraInterfaces, name, lineMsg)); 189 } 190 io.run(); 191 192 return 0; 193 } 194