xref: /openbmc/phosphor-gpio-monitor/gpioMonMain.cpp (revision 939a6431661931b3d31c46ec0310c553e22308d1)
1*939a6431SVijay Khemka /**
2*939a6431SVijay Khemka  * Copyright © 2019 Facebook
3*939a6431SVijay Khemka  *
4*939a6431SVijay Khemka  * Licensed under the Apache License, Version 2.0 (the "License");
5*939a6431SVijay Khemka  * you may not use this file except in compliance with the License.
6*939a6431SVijay Khemka  * You may obtain a copy of the License at
7*939a6431SVijay Khemka  *
8*939a6431SVijay Khemka  *     http://www.apache.org/licenses/LICENSE-2.0
9*939a6431SVijay Khemka  *
10*939a6431SVijay Khemka  * Unless required by applicable law or agreed to in writing, software
11*939a6431SVijay Khemka  * distributed under the License is distributed on an "AS IS" BASIS,
12*939a6431SVijay Khemka  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*939a6431SVijay Khemka  * See the License for the specific language governing permissions and
14*939a6431SVijay Khemka  * limitations under the License.
15*939a6431SVijay Khemka  */
16*939a6431SVijay Khemka 
17*939a6431SVijay Khemka #include "gpioMon.hpp"
18*939a6431SVijay Khemka 
19*939a6431SVijay Khemka #include <CLI/CLI.hpp>
20*939a6431SVijay Khemka #include <boost/asio/io_service.hpp>
21*939a6431SVijay Khemka #include <fstream>
22*939a6431SVijay Khemka #include <nlohmann/json.hpp>
23*939a6431SVijay Khemka #include <phosphor-logging/log.hpp>
24*939a6431SVijay Khemka 
25*939a6431SVijay Khemka using namespace phosphor::logging;
26*939a6431SVijay Khemka 
27*939a6431SVijay Khemka namespace phosphor
28*939a6431SVijay Khemka {
29*939a6431SVijay Khemka namespace gpio
30*939a6431SVijay Khemka {
31*939a6431SVijay Khemka 
32*939a6431SVijay Khemka std::map<std::string, int> polarityMap = {
33*939a6431SVijay Khemka     /**< Only watch falling edge events. */
34*939a6431SVijay Khemka     {"FALLING", GPIOD_LINE_REQUEST_EVENT_FALLING_EDGE},
35*939a6431SVijay Khemka     /**< Only watch rising edge events. */
36*939a6431SVijay Khemka     {"RISING", GPIOD_LINE_REQUEST_EVENT_RISING_EDGE},
37*939a6431SVijay Khemka     /**< Monitor both types of events. */
38*939a6431SVijay Khemka     {"BOTH", GPIOD_LINE_REQUEST_EVENT_BOTH_EDGES}};
39*939a6431SVijay Khemka 
40*939a6431SVijay Khemka }
41*939a6431SVijay Khemka } // namespace phosphor
42*939a6431SVijay Khemka 
43*939a6431SVijay Khemka int main(int argc, char** argv)
44*939a6431SVijay Khemka {
45*939a6431SVijay Khemka 
46*939a6431SVijay Khemka     boost::asio::io_service io;
47*939a6431SVijay Khemka 
48*939a6431SVijay Khemka     CLI::App app{"Monitor GPIO line for requested state change"};
49*939a6431SVijay Khemka 
50*939a6431SVijay Khemka     std::string gpioFileName;
51*939a6431SVijay Khemka 
52*939a6431SVijay Khemka     /* Add an input option */
53*939a6431SVijay Khemka     app.add_option("-c,--config", gpioFileName, "Name of config json file")
54*939a6431SVijay Khemka         ->required()
55*939a6431SVijay Khemka         ->check(CLI::ExistingFile);
56*939a6431SVijay Khemka 
57*939a6431SVijay Khemka     /* Parse input parameter */
58*939a6431SVijay Khemka     try
59*939a6431SVijay Khemka     {
60*939a6431SVijay Khemka         app.parse(argc, argv);
61*939a6431SVijay Khemka     }
62*939a6431SVijay Khemka     catch (CLI::Error& e)
63*939a6431SVijay Khemka     {
64*939a6431SVijay Khemka         return app.exit(e);
65*939a6431SVijay Khemka     }
66*939a6431SVijay Khemka 
67*939a6431SVijay Khemka     /* Get list of gpio config details from json file */
68*939a6431SVijay Khemka     std::ifstream file(gpioFileName);
69*939a6431SVijay Khemka     if (!file)
70*939a6431SVijay Khemka     {
71*939a6431SVijay Khemka         log<level::ERR>("GPIO monitor config file not found",
72*939a6431SVijay Khemka                         entry("GPIO_MON_FILE=%s", gpioFileName.c_str()));
73*939a6431SVijay Khemka         return -1;
74*939a6431SVijay Khemka     }
75*939a6431SVijay Khemka 
76*939a6431SVijay Khemka     nlohmann::json gpioMonObj;
77*939a6431SVijay Khemka     file >> gpioMonObj;
78*939a6431SVijay Khemka     file.close();
79*939a6431SVijay Khemka 
80*939a6431SVijay Khemka     std::vector<std::unique_ptr<phosphor::gpio::GpioMonitor>> gpios;
81*939a6431SVijay Khemka 
82*939a6431SVijay Khemka     for (auto& obj : gpioMonObj)
83*939a6431SVijay Khemka     {
84*939a6431SVijay Khemka 
85*939a6431SVijay Khemka         /* GPIO Line message */
86*939a6431SVijay Khemka         std::string lineMsg = "GPIO Line ";
87*939a6431SVijay Khemka 
88*939a6431SVijay Khemka         /* GPIO line */
89*939a6431SVijay Khemka         gpiod_line* line = NULL;
90*939a6431SVijay Khemka 
91*939a6431SVijay Khemka         /* Log message string */
92*939a6431SVijay Khemka         std::string errMsg;
93*939a6431SVijay Khemka 
94*939a6431SVijay Khemka         /* GPIO line configuration, default to monitor both edge */
95*939a6431SVijay Khemka         struct gpiod_line_request_config config
96*939a6431SVijay Khemka         {
97*939a6431SVijay Khemka             "gpio_monitor", GPIOD_LINE_REQUEST_EVENT_BOTH_EDGES, 0
98*939a6431SVijay Khemka         };
99*939a6431SVijay Khemka 
100*939a6431SVijay Khemka         /* flag to monitor */
101*939a6431SVijay Khemka         bool flag = false;
102*939a6431SVijay Khemka 
103*939a6431SVijay Khemka         /* target to start */
104*939a6431SVijay Khemka         std::string target;
105*939a6431SVijay Khemka 
106*939a6431SVijay Khemka         if (obj.find("LineName") == obj.end())
107*939a6431SVijay Khemka         {
108*939a6431SVijay Khemka             /* If there is no line Name defined then gpio num nd chip
109*939a6431SVijay Khemka              * id must be defined. GpioNum is integer mapping to the
110*939a6431SVijay Khemka              * GPIO key configured by the kernel
111*939a6431SVijay Khemka              */
112*939a6431SVijay Khemka             if (obj.find("GpioNum") == obj.end() ||
113*939a6431SVijay Khemka                 obj.find("ChipId") == obj.end())
114*939a6431SVijay Khemka             {
115*939a6431SVijay Khemka                 log<level::ERR>(
116*939a6431SVijay Khemka                     "Failed to find line name or gpio number",
117*939a6431SVijay Khemka                     entry("GPIO_JSON_FILE_NAME=%s", gpioFileName.c_str()));
118*939a6431SVijay Khemka                 return -1;
119*939a6431SVijay Khemka             }
120*939a6431SVijay Khemka 
121*939a6431SVijay Khemka             std::string chipIdStr = obj["ChipId"];
122*939a6431SVijay Khemka             int gpioNum = obj["GpioNum"];
123*939a6431SVijay Khemka 
124*939a6431SVijay Khemka             lineMsg += std::to_string(gpioNum);
125*939a6431SVijay Khemka 
126*939a6431SVijay Khemka             /* Get the GPIO line */
127*939a6431SVijay Khemka             line = gpiod_line_get(chipIdStr.c_str(), gpioNum);
128*939a6431SVijay Khemka         }
129*939a6431SVijay Khemka         else
130*939a6431SVijay Khemka         {
131*939a6431SVijay Khemka             /* Find the GPIO line */
132*939a6431SVijay Khemka             std::string lineName = obj["LineName"];
133*939a6431SVijay Khemka             lineMsg += lineName;
134*939a6431SVijay Khemka             line = gpiod_line_find(lineName.c_str());
135*939a6431SVijay Khemka         }
136*939a6431SVijay Khemka 
137*939a6431SVijay Khemka         if (line == NULL)
138*939a6431SVijay Khemka         {
139*939a6431SVijay Khemka             errMsg = "Failed to find the " + lineMsg;
140*939a6431SVijay Khemka             log<level::ERR>(errMsg.c_str());
141*939a6431SVijay Khemka             return -1;
142*939a6431SVijay Khemka         }
143*939a6431SVijay Khemka 
144*939a6431SVijay Khemka         /* Get event to be monitored, if it is not defined then
145*939a6431SVijay Khemka          * Both rising falling edge will be monitored.
146*939a6431SVijay Khemka          */
147*939a6431SVijay Khemka         if (obj.find("EventMon") != obj.end())
148*939a6431SVijay Khemka         {
149*939a6431SVijay Khemka             std::string eventStr = obj["EventMon"];
150*939a6431SVijay Khemka             auto findEvent = phosphor::gpio::polarityMap.find(eventStr);
151*939a6431SVijay Khemka             if (findEvent == phosphor::gpio::polarityMap.end())
152*939a6431SVijay Khemka             {
153*939a6431SVijay Khemka                 errMsg = "Incorrect GPIO monitor event defined " + lineMsg;
154*939a6431SVijay Khemka                 log<level::ERR>(errMsg.c_str());
155*939a6431SVijay Khemka                 return -1;
156*939a6431SVijay Khemka             }
157*939a6431SVijay Khemka 
158*939a6431SVijay Khemka             config.request_type = findEvent->second;
159*939a6431SVijay Khemka         }
160*939a6431SVijay Khemka 
161*939a6431SVijay Khemka         /* Get flag if monitoring needs to continue after first event */
162*939a6431SVijay Khemka         if (obj.find("Continue") != obj.end())
163*939a6431SVijay Khemka         {
164*939a6431SVijay Khemka             flag = obj["Continue"];
165*939a6431SVijay Khemka         }
166*939a6431SVijay Khemka 
167*939a6431SVijay Khemka         /* Parse out target argument. It is fine if the user does not
168*939a6431SVijay Khemka          * pass this if they are not interested in calling into any target
169*939a6431SVijay Khemka          * on meeting a condition.
170*939a6431SVijay Khemka          */
171*939a6431SVijay Khemka         if (obj.find("Target") != obj.end())
172*939a6431SVijay Khemka         {
173*939a6431SVijay Khemka             target = obj["Target"];
174*939a6431SVijay Khemka         }
175*939a6431SVijay Khemka 
176*939a6431SVijay Khemka         /* Create a monitor object and let it do all the rest */
177*939a6431SVijay Khemka         gpios.push_back(std::make_unique<phosphor::gpio::GpioMonitor>(
178*939a6431SVijay Khemka             line, config, io, target, lineMsg, flag));
179*939a6431SVijay Khemka     }
180*939a6431SVijay Khemka     io.run();
181*939a6431SVijay Khemka 
182*939a6431SVijay Khemka     return 0;
183*939a6431SVijay Khemka }
184