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