xref: /openbmc/phosphor-gpio-monitor/presence/main.cpp (revision 75ff16717de9a7b3beeda9f3cace9456cad98156)
1 // SPDX-License-Identifier: Apache-2.0
2 // SPDX-FileCopyrightText: Copyright OpenBMC Authors
3 
4 #include "gpio_presence.hpp"
5 
6 #include <systemd/sd-event.h>
7 
8 #include <CLI/CLI.hpp>
9 #include <phosphor-logging/lg2.hpp>
10 
11 #include <iostream>
12 
13 using namespace phosphor::gpio;
14 using namespace phosphor::gpio::presence;
15 
16 /**
17  * Pulls out the path,device pairs from the string
18  * passed in
19  *
20  * @param[in] driverString - space separated path,device pairs
21  * @param[out] drivers - vector of device,path tuples filled in
22  *                       from driverString
23  *
24  * @return int - 0 if successful, < 0 else
25  */
getDrivers(const std::string & driverString,std::vector<Driver> & drivers)26 static int getDrivers(const std::string& driverString,
27                       std::vector<Driver>& drivers)
28 {
29     std::istringstream stream{driverString};
30 
31     while (true)
32     {
33         std::string entry;
34 
35         // Extract each path,device pair
36         stream >> entry;
37 
38         if (entry.empty())
39         {
40             break;
41         }
42 
43         // Extract the path and device and save them
44         auto pos = entry.rfind(',');
45         if (pos != std::string::npos)
46         {
47             auto path = entry.substr(0, pos);
48             auto device = entry.substr(pos + 1);
49 
50             drivers.emplace_back(std::move(device), std::move(path));
51         }
52         else
53         {
54             lg2::error("Invalid path,device combination: {ENTRY}", "ENTRY",
55                        entry);
56             return -1;
57         }
58     }
59 
60     return 0;
61 }
62 
main(int argc,char ** argv)63 int main(int argc, char** argv)
64 {
65     CLI::App app{"Monitor gpio presence status"};
66 
67     std::string path{};
68     std::string key{};
69     std::string name{};
70     std::string inventory{};
71     std::string drivers{};
72     std::string ifaces{};
73 
74     /* Add an input option */
75     app.add_option(
76            "-p,--path", path,
77            " Path of device to read for GPIO pin state to determine presence of inventory item")
78         ->required();
79     app.add_option("-k,--key", key, "Input GPIO key number")->required();
80     app.add_option("-n,--name", name, "Pretty name of the inventory item")
81         ->required();
82     app.add_option("-i,--inventory", inventory,
83                    "Object path under inventory that will be created")
84         ->required();
85     app.add_option(
86            "-d,--drivers", drivers,
87            "List of drivers to bind when card is added and unbind when card is removed\n"
88            "Format is a space separated list of path,device pairs.\n"
89            "For example: /sys/bus/i2c/drivers/some-driver,3-0068")
90         ->expected(0, 1);
91     app.add_option(
92            "-e,--extra-ifaces", ifaces,
93            "List of interfaces to associate to inventory item\n"
94            "Format is a comma separated list of interfaces.\n"
95            "For example: /xyz/openbmc_project/.../1,/xyz/openbmc_project/.../2")
96         ->expected(0, 1);
97 
98     /* Parse input parameter */
99     try
100     {
101         app.parse(argc, argv);
102     }
103     catch (const CLI::Error& e)
104     {
105         return app.exit(e);
106     }
107 
108     std::vector<Driver> driverList;
109 
110     // Driver list is optional
111     if (!drivers.empty())
112     {
113         if (getDrivers(drivers, driverList) < 0)
114         {
115             lg2::error("Failed to parser drivers: {DRIVERS}", "DRIVERS",
116                        drivers);
117             return -1;
118         }
119     }
120 
121     std::vector<Interface> ifaceList;
122 
123     // Extra interfaces list is optional
124     if (!ifaces.empty())
125     {
126         std::stringstream ss(ifaces);
127         Interface iface;
128         while (std::getline(ss, iface, ','))
129         {
130             ifaceList.push_back(iface);
131         }
132     }
133 
134     auto bus = sdbusplus::bus::new_default();
135     auto rc = 0;
136     sd_event* event = nullptr;
137     rc = sd_event_default(&event);
138     if (rc < 0)
139     {
140         lg2::error("Error creating a default sd_event handler");
141         return rc;
142     }
143     EventPtr eventP{event};
144     event = nullptr;
145 
146     Presence presence(bus, inventory, path, std::stoul(key), name, eventP,
147                       driverList, ifaceList);
148 
149     while (true)
150     {
151         // -1 denotes wait forever
152         rc = sd_event_run(eventP.get(), (uint64_t)-1);
153         if (rc < 0)
154         {
155             lg2::error("Failure in processing request: {RC}", "RC", rc);
156             break;
157         }
158     }
159     return rc;
160 }
161