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