xref: /openbmc/phosphor-gpio-monitor/multi-presence/main.cpp (revision 75ff16717de9a7b3beeda9f3cace9456cad98156)
1 // SPDX-License-Identifier: Apache-2.0
2 // SPDX-FileCopyrightText: Copyright OpenBMC Authors
3 
4 #include "gpio_presence.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 const std::map<std::string, int> biasMap = {
19     /**< Set bias as is. */
20     {"AS_IS", 0},
21     /**< Disable bias. */
22     {"DISABLE", GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE},
23     /**< Enable pull-up. */
24     {"PULL_UP", GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP},
25     /**< Enable pull-down. */
26     {"PULL_DOWN", GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN}};
27 }
28 } // namespace phosphor
29 
main(int argc,char ** argv)30 int main(int argc, char** argv)
31 {
32     boost::asio::io_context io;
33 
34     CLI::App app{"Monitor gpio presence status"};
35 
36     std::string gpioFileName;
37 
38     /* Add an input option */
39     app.add_option("-c,--config", gpioFileName, "Name of config json file")
40         ->required()
41         ->check(CLI::ExistingFile);
42 
43     /* Parse input parameter */
44     try
45     {
46         app.parse(argc, argv);
47     }
48     catch (const CLI::Error& e)
49     {
50         return app.exit(e);
51     }
52 
53     /* Get list of gpio config details from json file */
54     std::ifstream file(gpioFileName);
55     if (!file)
56     {
57         lg2::error("Failed to open config file: {FILE}", "FILE", gpioFileName);
58         return -1;
59     }
60 
61     nlohmann::json gpioMonObj;
62     file >> gpioMonObj;
63     file.close();
64 
65     std::vector<phosphor::gpio::GpioPresence> 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         /* Pretty name of the inventory object */
80         std::string name;
81 
82         /* Object path under inventory that will be created */
83         std::string inventory;
84 
85         /* List of interfaces to associate to inventory item */
86         std::vector<std::string> extraInterfaces;
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"].get<std::string>();
103             int gpioNum = obj["GpioNum"].get<int>();
104 
105             lineMsg += chipIdStr + " " + 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"].get<std::string>();
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         /* Parse out inventory argument. */
125         if (obj.find("Inventory") == obj.end())
126         {
127             lg2::error("{GPIO}: Inventory path not specified", "GPIO", lineMsg);
128             return -1;
129         }
130         else
131         {
132             inventory = obj["Inventory"].get<std::string>();
133         }
134 
135         if (obj.find("Name") == obj.end())
136         {
137             lg2::error("{GPIO}: Name path not specified", "GPIO", lineMsg);
138             return -1;
139         }
140         else
141         {
142             name = obj["Name"].get<std::string>();
143         }
144 
145         /* Parse optional bias */
146         if (obj.find("Bias") != obj.end())
147         {
148             std::string biasName = obj["Bias"].get<std::string>();
149             auto findBias = phosphor::gpio::biasMap.find(biasName);
150             if (findBias == phosphor::gpio::biasMap.end())
151             {
152                 lg2::error("{GPIO}: Bias unknown: {BIAS}", "GPIO", lineMsg,
153                            "BIAS", biasName);
154                 return -1;
155             }
156 
157             config.flags = findBias->second;
158         }
159 
160         /* Parse optional active level */
161         if (obj.find("ActiveLow") != obj.end() && obj["ActiveLow"].get<bool>())
162         {
163             config.flags |= GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW;
164         }
165 
166         /* Parse optional extra interfaces */
167         if (obj.find("ExtraInterfaces") != obj.end())
168         {
169             obj.at("ExtraInterfaces").get_to(extraInterfaces);
170         }
171 
172         /* Create a monitor object and let it do all the rest */
173         gpios.push_back(phosphor::gpio::GpioPresence(
174             line, config, io, inventory, extraInterfaces, name, lineMsg));
175     }
176     io.run();
177 
178     return 0;
179 }
180