xref: /openbmc/phosphor-gpio-monitor/multi-presence/main.cpp (revision 1c88803f75c4d5b606345df7bdef318b677f9696)
1 /**
2  * Copyright © 2019 Facebook
3  * Copyright © 2023 9elements GmbH
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 #include "gpio_presence.hpp"
19 
20 #include <CLI/CLI.hpp>
21 #include <boost/asio/io_context.hpp>
22 #include <nlohmann/json.hpp>
23 #include <phosphor-logging/lg2.hpp>
24 
25 #include <fstream>
26 
27 namespace phosphor
28 {
29 namespace gpio
30 {
31 
32 const std::map<std::string, int> biasMap = {
33     /**< Set bias as is. */
34     {"AS_IS", 0},
35     /**< Disable bias. */
36     {"DISABLE", GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE},
37     /**< Enable pull-up. */
38     {"PULL_UP", GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP},
39     /**< Enable pull-down. */
40     {"PULL_DOWN", GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN}};
41 }
42 } // namespace phosphor
43 
main(int argc,char ** argv)44 int main(int argc, char** argv)
45 {
46     boost::asio::io_context io;
47 
48     CLI::App app{"Monitor gpio presence status"};
49 
50     std::string gpioFileName;
51 
52     /* Add an input option */
53     app.add_option("-c,--config", gpioFileName, "Name of config json file")
54         ->required()
55         ->check(CLI::ExistingFile);
56 
57     /* Parse input parameter */
58     try
59     {
60         app.parse(argc, argv);
61     }
62     catch (const CLI::Error& e)
63     {
64         return app.exit(e);
65     }
66 
67     /* Get list of gpio config details from json file */
68     std::ifstream file(gpioFileName);
69     if (!file)
70     {
71         lg2::error("Failed to open config file: {FILE}", "FILE", gpioFileName);
72         return -1;
73     }
74 
75     nlohmann::json gpioMonObj;
76     file >> gpioMonObj;
77     file.close();
78 
79     std::vector<phosphor::gpio::GpioPresence> gpios;
80 
81     for (auto& obj : gpioMonObj)
82     {
83         /* GPIO Line message */
84         std::string lineMsg = "GPIO Line ";
85 
86         /* GPIO line */
87         gpiod_line* line = nullptr;
88 
89         /* GPIO line configuration, default to monitor both edge */
90         struct gpiod_line_request_config config{
91             "gpio_monitor", GPIOD_LINE_REQUEST_EVENT_BOTH_EDGES, 0};
92 
93         /* Pretty name of the inventory object */
94         std::string name;
95 
96         /* Object path under inventory that will be created */
97         std::string inventory;
98 
99         /* List of interfaces to associate to inventory item */
100         std::vector<std::string> extraInterfaces;
101 
102         if (obj.find("LineName") == obj.end())
103         {
104             /* If there is no line Name defined then gpio num nd chip
105              * id must be defined. GpioNum is integer mapping to the
106              * GPIO key configured by the kernel
107              */
108             if (obj.find("GpioNum") == obj.end() ||
109                 obj.find("ChipId") == obj.end())
110             {
111                 lg2::error("Failed to find line name or gpio number: {FILE}",
112                            "FILE", gpioFileName);
113                 return -1;
114             }
115 
116             std::string chipIdStr = obj["ChipId"].get<std::string>();
117             int gpioNum = obj["GpioNum"].get<int>();
118 
119             lineMsg += chipIdStr + " " + std::to_string(gpioNum);
120 
121             /* Get the GPIO line */
122             line = gpiod_line_get(chipIdStr.c_str(), gpioNum);
123         }
124         else
125         {
126             /* Find the GPIO line */
127             std::string lineName = obj["LineName"].get<std::string>();
128             lineMsg += lineName;
129             line = gpiod_line_find(lineName.c_str());
130         }
131 
132         if (line == nullptr)
133         {
134             lg2::error("Failed to find the {GPIO}", "GPIO", lineMsg);
135             continue;
136         }
137 
138         /* Parse out inventory argument. */
139         if (obj.find("Inventory") == obj.end())
140         {
141             lg2::error("{GPIO}: Inventory path not specified", "GPIO", lineMsg);
142             return -1;
143         }
144         else
145         {
146             inventory = obj["Inventory"].get<std::string>();
147         }
148 
149         if (obj.find("Name") == obj.end())
150         {
151             lg2::error("{GPIO}: Name path not specified", "GPIO", lineMsg);
152             return -1;
153         }
154         else
155         {
156             name = obj["Name"].get<std::string>();
157         }
158 
159         /* Parse optional bias */
160         if (obj.find("Bias") != obj.end())
161         {
162             std::string biasName = obj["Bias"].get<std::string>();
163             auto findBias = phosphor::gpio::biasMap.find(biasName);
164             if (findBias == phosphor::gpio::biasMap.end())
165             {
166                 lg2::error("{GPIO}: Bias unknown: {BIAS}", "GPIO", lineMsg,
167                            "BIAS", biasName);
168                 return -1;
169             }
170 
171             config.flags = findBias->second;
172         }
173 
174         /* Parse optional active level */
175         if (obj.find("ActiveLow") != obj.end() && obj["ActiveLow"].get<bool>())
176         {
177             config.flags |= GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW;
178         }
179 
180         /* Parse optional extra interfaces */
181         if (obj.find("ExtraInterfaces") != obj.end())
182         {
183             obj.at("ExtraInterfaces").get_to(extraInterfaces);
184         }
185 
186         /* Create a monitor object and let it do all the rest */
187         gpios.push_back(phosphor::gpio::GpioPresence(
188             line, config, io, inventory, extraInterfaces, name, lineMsg));
189     }
190     io.run();
191 
192     return 0;
193 }
194