xref: /openbmc/phosphor-gpio-monitor/gpioMonMain.cpp (revision 75ff16717de9a7b3beeda9f3cace9456cad98156)
1 // SPDX-License-Identifier: Apache-2.0
2 // SPDX-FileCopyrightText: Copyright OpenBMC Authors
3 
4 #include "gpioMon.hpp"
5 
6 #include <CLI/CLI.hpp>
7 #include <boost/asio/io_context.hpp>
8 #include <nlohmann/json.hpp>
9 #include <phosphor-logging/lg2.hpp>
10 
11 #include <fstream>
12 
13 namespace phosphor
14 {
15 namespace gpio
16 {
17 
18 std::map<std::string, int> polarityMap = {
19     /**< Only watch falling edge events. */
20     {"FALLING", GPIOD_LINE_REQUEST_EVENT_FALLING_EDGE},
21     /**< Only watch rising edge events. */
22     {"RISING", GPIOD_LINE_REQUEST_EVENT_RISING_EDGE},
23     /**< Monitor both types of events. */
24     {"BOTH", GPIOD_LINE_REQUEST_EVENT_BOTH_EDGES}};
25 
26 }
27 } // namespace phosphor
28 
main(int argc,char ** argv)29 int main(int argc, char** argv)
30 {
31     boost::asio::io_context io;
32 
33     CLI::App app{"Monitor GPIO line for requested state change"};
34 
35     std::string gpioFileName;
36 
37     /* Add an input option */
38     app.add_option("-c,--config", gpioFileName, "Name of config json file")
39         ->required()
40         ->check(CLI::ExistingFile);
41 
42     /* Parse input parameter */
43     try
44     {
45         app.parse(argc, argv);
46     }
47     catch (const CLI::Error& e)
48     {
49         return app.exit(e);
50     }
51 
52     /* Get list of gpio config details from json file */
53     std::ifstream file(gpioFileName);
54     if (!file)
55     {
56         lg2::error("GPIO monitor config file not found: {FILE}", "FILE",
57                    gpioFileName);
58         return -1;
59     }
60 
61     nlohmann::json gpioMonObj;
62     file >> gpioMonObj;
63     file.close();
64 
65     std::vector<std::unique_ptr<phosphor::gpio::GpioMonitor>> gpios;
66 
67     for (auto& obj : gpioMonObj)
68     {
69         /* GPIO Line message */
70         std::string lineMsg = "GPIO Line ";
71 
72         /* GPIO line */
73         gpiod_line* line = nullptr;
74 
75         /* GPIO line configuration, default to monitor both edge */
76         struct gpiod_line_request_config config{
77             "gpio_monitor", GPIOD_LINE_REQUEST_EVENT_BOTH_EDGES, 0};
78 
79         /* flag to monitor */
80         bool flag = false;
81 
82         /* target to start */
83         std::string target;
84 
85         /* multi targets to start */
86         std::map<std::string, std::vector<std::string>> targets;
87 
88         if (obj.find("LineName") == obj.end())
89         {
90             /* If there is no line Name defined then gpio num nd chip
91              * id must be defined. GpioNum is integer mapping to the
92              * GPIO key configured by the kernel
93              */
94             if (obj.find("GpioNum") == obj.end() ||
95                 obj.find("ChipId") == obj.end())
96             {
97                 lg2::error("Failed to find line name or gpio number: {FILE}",
98                            "FILE", gpioFileName);
99                 return -1;
100             }
101 
102             std::string chipIdStr = obj["ChipId"];
103             int gpioNum = obj["GpioNum"];
104 
105             lineMsg += std::to_string(gpioNum);
106 
107             /* Get the GPIO line */
108             line = gpiod_line_get(chipIdStr.c_str(), gpioNum);
109         }
110         else
111         {
112             /* Find the GPIO line */
113             std::string lineName = obj["LineName"];
114             lineMsg += lineName;
115             line = gpiod_line_find(lineName.c_str());
116         }
117 
118         if (line == nullptr)
119         {
120             lg2::error("Failed to find the {GPIO}", "GPIO", lineMsg);
121             continue;
122         }
123 
124         /* Get event to be monitored, if it is not defined then
125          * Both rising falling edge will be monitored.
126          */
127         if (obj.find("EventMon") != obj.end())
128         {
129             std::string eventStr = obj["EventMon"];
130             auto findEvent = phosphor::gpio::polarityMap.find(eventStr);
131             if (findEvent == phosphor::gpio::polarityMap.end())
132             {
133                 lg2::error("{GPIO}: event missing: {EVENT}", "GPIO", lineMsg,
134                            "EVENT", eventStr);
135                 return -1;
136             }
137 
138             config.request_type = findEvent->second;
139         }
140 
141         /* Get flag if monitoring needs to continue after first event */
142         if (obj.find("Continue") != obj.end())
143         {
144             flag = obj["Continue"];
145         }
146 
147         /* Parse out target argument. It is fine if the user does not
148          * pass this if they are not interested in calling into any target
149          * on meeting a condition.
150          */
151         if (obj.find("Target") != obj.end())
152         {
153             target = obj["Target"];
154         }
155 
156         /* Parse out the targets argument if multi-targets are needed.*/
157         if (obj.find("Targets") != obj.end())
158         {
159             obj.at("Targets").get_to(targets);
160         }
161 
162         /* Create a monitor object and let it do all the rest */
163         gpios.push_back(std::make_unique<phosphor::gpio::GpioMonitor>(
164             line, config, io, target, targets, lineMsg, flag));
165     }
166     io.run();
167 
168     return 0;
169 }
170