| #include "gpio_presence.hpp" |
| |
| #include <systemd/sd-event.h> |
| |
| #include <CLI/CLI.hpp> |
| #include <phosphor-logging/lg2.hpp> |
| |
| #include <iostream> |
| |
| using namespace phosphor::gpio; |
| using namespace phosphor::gpio::presence; |
| |
| /** |
| * Pulls out the path,device pairs from the string |
| * passed in |
| * |
| * @param[in] driverString - space separated path,device pairs |
| * @param[out] drivers - vector of device,path tuples filled in |
| * from driverString |
| * |
| * @return int - 0 if successful, < 0 else |
| */ |
| static int getDrivers(const std::string& driverString, |
| std::vector<Driver>& drivers) |
| { |
| std::istringstream stream{driverString}; |
| |
| while (true) |
| { |
| std::string entry; |
| |
| // Extract each path,device pair |
| stream >> entry; |
| |
| if (entry.empty()) |
| { |
| break; |
| } |
| |
| // Extract the path and device and save them |
| auto pos = entry.rfind(','); |
| if (pos != std::string::npos) |
| { |
| auto path = entry.substr(0, pos); |
| auto device = entry.substr(pos + 1); |
| |
| drivers.emplace_back(std::move(device), std::move(path)); |
| } |
| else |
| { |
| lg2::error("Invalid path,device combination: {ENTRY}", "ENTRY", |
| entry); |
| return -1; |
| } |
| } |
| |
| return 0; |
| } |
| |
| int main(int argc, char** argv) |
| { |
| CLI::App app{"Monitor gpio presence status"}; |
| |
| std::string path{}; |
| std::string key{}; |
| std::string name{}; |
| std::string inventory{}; |
| std::string drivers{}; |
| std::string ifaces{}; |
| |
| /* Add an input option */ |
| app.add_option( |
| "-p,--path", path, |
| " Path of device to read for GPIO pin state to determine presence of inventory item") |
| ->required(); |
| app.add_option("-k,--key", key, "Input GPIO key number")->required(); |
| app.add_option("-n,--name", name, "Pretty name of the inventory item") |
| ->required(); |
| app.add_option("-i,--inventory", inventory, |
| "Object path under inventory that will be created") |
| ->required(); |
| app.add_option( |
| "-d,--drivers", drivers, |
| "List of drivers to bind when card is added and unbind when card is removed\n" |
| "Format is a space separated list of path,device pairs.\n" |
| "For example: /sys/bus/i2c/drivers/some-driver,3-0068") |
| ->expected(0, 1); |
| app.add_option( |
| "-e,--extra-ifaces", ifaces, |
| "List of interfaces to associate to inventory item\n" |
| "Format is a comma separated list of interfaces.\n" |
| "For example: /xyz/openbmc_project/.../1,/xyz/openbmc_project/.../2") |
| ->expected(0, 1); |
| |
| /* Parse input parameter */ |
| try |
| { |
| app.parse(argc, argv); |
| } |
| catch (const CLI::Error& e) |
| { |
| return app.exit(e); |
| } |
| |
| std::vector<Driver> driverList; |
| |
| // Driver list is optional |
| if (!drivers.empty()) |
| { |
| if (getDrivers(drivers, driverList) < 0) |
| { |
| lg2::error("Failed to parser drivers: {DRIVERS}", "DRIVERS", |
| drivers); |
| return -1; |
| } |
| } |
| |
| std::vector<Interface> ifaceList; |
| |
| // Extra interfaces list is optional |
| if (!ifaces.empty()) |
| { |
| std::stringstream ss(ifaces); |
| Interface iface; |
| while (std::getline(ss, iface, ',')) |
| { |
| ifaceList.push_back(iface); |
| } |
| } |
| |
| auto bus = sdbusplus::bus::new_default(); |
| auto rc = 0; |
| sd_event* event = nullptr; |
| rc = sd_event_default(&event); |
| if (rc < 0) |
| { |
| lg2::error("Error creating a default sd_event handler"); |
| return rc; |
| } |
| EventPtr eventP{event}; |
| event = nullptr; |
| |
| Presence presence(bus, inventory, path, std::stoul(key), name, eventP, |
| driverList, ifaceList); |
| |
| while (true) |
| { |
| // -1 denotes wait forever |
| rc = sd_event_run(eventP.get(), (uint64_t)-1); |
| if (rc < 0) |
| { |
| lg2::error("Failure in processing request: {RC}", "RC", rc); |
| break; |
| } |
| } |
| return rc; |
| } |