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 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 = NULL; 88 89 /* GPIO line configuration, default to monitor both edge */ 90 struct gpiod_line_request_config config 91 { 92 "gpio_monitor", GPIOD_LINE_REQUEST_EVENT_BOTH_EDGES, 0 93 }; 94 95 /* Pretty name of the inventory object */ 96 std::string name; 97 98 /* Object path under inventory that will be created */ 99 std::string inventory; 100 101 /* List of interfaces to associate to inventory item */ 102 std::vector<std::string> extraInterfaces; 103 104 if (obj.find("LineName") == obj.end()) 105 { 106 /* If there is no line Name defined then gpio num nd chip 107 * id must be defined. GpioNum is integer mapping to the 108 * GPIO key configured by the kernel 109 */ 110 if (obj.find("GpioNum") == obj.end() || 111 obj.find("ChipId") == obj.end()) 112 { 113 lg2::error("Failed to find line name or gpio number: {FILE}", 114 "FILE", gpioFileName); 115 return -1; 116 } 117 118 std::string chipIdStr = obj["ChipId"].get<std::string>(); 119 int gpioNum = obj["GpioNum"].get<int>(); 120 121 lineMsg += chipIdStr + " " + std::to_string(gpioNum); 122 123 /* Get the GPIO line */ 124 line = gpiod_line_get(chipIdStr.c_str(), gpioNum); 125 } 126 else 127 { 128 /* Find the GPIO line */ 129 std::string lineName = obj["LineName"].get<std::string>(); 130 lineMsg += lineName; 131 line = gpiod_line_find(lineName.c_str()); 132 } 133 134 if (line == NULL) 135 { 136 lg2::error("Failed to find the {GPIO}", "GPIO", lineMsg); 137 return -1; 138 } 139 140 /* Parse out inventory argument. */ 141 if (obj.find("Inventory") == obj.end()) 142 { 143 lg2::error("{GPIO}: Inventory path not specified", "GPIO", lineMsg); 144 return -1; 145 } 146 else 147 { 148 inventory = obj["Inventory"].get<std::string>(); 149 } 150 151 if (obj.find("Name") == obj.end()) 152 { 153 lg2::error("{GPIO}: Name path not specified", "GPIO", lineMsg); 154 return -1; 155 } 156 else 157 { 158 name = obj["Name"].get<std::string>(); 159 } 160 161 /* Parse optional bias */ 162 if (obj.find("Bias") != obj.end()) 163 { 164 std::string biasName = obj["Bias"].get<std::string>(); 165 auto findBias = phosphor::gpio::biasMap.find(biasName); 166 if (findBias == phosphor::gpio::biasMap.end()) 167 { 168 lg2::error("{GPIO}: Bias unknown: {BIAS}", "GPIO", lineMsg, 169 "BIAS", biasName); 170 return -1; 171 } 172 173 config.flags = findBias->second; 174 } 175 176 /* Parse optional active level */ 177 if (obj.find("ActiveLow") != obj.end() && obj["ActiveLow"].get<bool>()) 178 { 179 config.flags |= GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW; 180 } 181 182 /* Parse optional extra interfaces */ 183 if (obj.find("ExtraInterfaces") != obj.end()) 184 { 185 obj.at("ExtraInterfaces").get_to(extraInterfaces); 186 } 187 188 /* Create a monitor object and let it do all the rest */ 189 gpios.push_back(phosphor::gpio::GpioPresence( 190 line, config, io, inventory, extraInterfaces, name, lineMsg)); 191 } 192 io.run(); 193 194 return 0; 195 } 196