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