1 #include "gpioMonitor.hpp"
2 
3 #include "common_utility.hpp"
4 #include "ibm_vpd_utils.hpp"
5 
6 #include <boost/asio.hpp>
7 #include <boost/bind/bind.hpp>
8 #include <gpiod.hpp>
9 
10 using namespace std;
11 using namespace openpower::vpd::constants;
12 
13 namespace openpower
14 {
15 namespace vpd
16 {
17 namespace manager
18 {
19 
getPresencePinValue()20 bool GpioEventHandler::getPresencePinValue()
21 {
22     Byte gpioData = 1;
23     gpiod::line presenceLine = gpiod::find_line(presencePin);
24     if (!presenceLine)
25     {
26         cerr << "Error getPresencePinValue: couldn't find presence line:"
27              << presencePin << " on GPIO \n";
28         // return previous state as we couldn't read current state
29         return prevPresPinValue;
30     }
31 
32     presenceLine.request(
33         {"Op-panel presence line", gpiod::line_request::DIRECTION_INPUT, 0});
34 
35     gpioData = presenceLine.get_value();
36 
37     return gpioData;
38 }
39 
initGpioInfos(std::shared_ptr<boost::asio::io_context> & ioContext)40 void GpioMonitor::initGpioInfos(
41     std::shared_ptr<boost::asio::io_context>& ioContext)
42 {
43     Byte outputValue = 0;
44     Byte presenceValue = 0;
45     string presencePinName{}, outputPinName{};
46     string devNameAddr{}, driverType{}, busType{}, objectPath{};
47 
48     for (const auto& eachFRU : jsonFile["frus"].items())
49     {
50         for (const auto& eachInventory : eachFRU.value())
51         {
52             objectPath = eachInventory["inventoryPath"];
53 
54             if ((eachInventory.find("presence") != eachInventory.end()) &&
55                 (eachInventory.find("preAction") != eachInventory.end()))
56             {
57                 if (!eachInventory["presence"].value("pollingRequired", false))
58                 {
59                     // Polling not required for this FRU , skip.
60                     continue;
61                 }
62 
63                 for (const auto& presStatus : eachInventory["presence"].items())
64                 {
65                     if (presStatus.key() == "pin")
66                     {
67                         presencePinName = presStatus.value();
68                     }
69                     else if (presStatus.key() == "value")
70                     {
71                         presenceValue = presStatus.value();
72                     }
73                 }
74 
75                 // Based on presence pin value, preAction pin will be set/reset
76                 // This action will be taken before vpd collection.
77                 for (const auto& preAction : eachInventory["preAction"].items())
78                 {
79                     if (preAction.key() == "pin")
80                     {
81                         outputPinName = preAction.value();
82                     }
83                     else if (preAction.key() == "value")
84                     {
85                         outputValue = preAction.value();
86                     }
87                 }
88 
89                 if ((eachInventory.find("devAddress") != eachInventory.end()) &&
90                     (eachInventory.find("driverType") != eachInventory.end()) &&
91                     (eachInventory.find("busType") != eachInventory.end()))
92                 {
93                     devNameAddr = eachInventory["devAddress"];
94                     driverType = eachInventory["driverType"];
95                     busType = eachInventory["busType"];
96 
97                     // Init all Gpio info variables
98                     std::shared_ptr<GpioEventHandler> gpioObj =
99                         make_shared<GpioEventHandler>(
100                             presencePinName, presenceValue, outputPinName,
101                             outputValue, devNameAddr, driverType, busType,
102                             objectPath, ioContext);
103 
104                     gpioObjects.push_back(gpioObj);
105                 }
106             }
107         }
108     }
109 }
110 
toggleGpio()111 void GpioEventHandler::toggleGpio()
112 {
113     bool presPinVal = getPresencePinValue();
114     bool isPresent = false;
115 
116     // preserve the new value
117     prevPresPinValue = presPinVal;
118 
119     if (presPinVal == presenceValue)
120     {
121         isPresent = true;
122     }
123 
124     // if FRU went away set the present property to false
125     if (!isPresent)
126     {
127         inventory::ObjectMap objects;
128         inventory::InterfaceMap interfaces;
129         inventory::PropertyMap presProp;
130 
131         presProp.emplace("Present", false);
132         interfaces.emplace("xyz.openbmc_project.Inventory.Item", presProp);
133         objects.emplace(objectPath, move(interfaces));
134 
135         common::utility::callPIM(move(objects));
136     }
137 
138     gpiod::line outputLine = gpiod::find_line(outputPin);
139     if (!outputLine)
140     {
141         cerr << "Error: toggleGpio: couldn't find output line:" << outputPin
142              << ". Skipping update\n";
143 
144         return;
145     }
146 
147     outputLine.request({"FRU presence: update the output GPIO pin",
148                         gpiod::line_request::DIRECTION_OUTPUT, 0},
149                        isPresent ? outputValue : (!outputValue));
150 
151     string cmnd = createBindUnbindDriverCmnd(devNameAddr, busType, driverType,
152                                              isPresent ? "bind" : "unbind");
153 
154     cout << cmnd << endl;
155     executeCmd(cmnd);
156 }
157 
handleTimerExpiry(const boost::system::error_code & ec,std::shared_ptr<boost::asio::steady_timer> & timer)158 void GpioEventHandler::handleTimerExpiry(
159     const boost::system::error_code& ec,
160     std::shared_ptr<boost::asio::steady_timer>& timer)
161 {
162     if (ec == boost::asio::error::operation_aborted)
163     {
164         return;
165     }
166 
167     if (ec)
168     {
169         std::cerr << "Timer wait failed for gpio pin" << ec.message();
170         return;
171     }
172 
173     if (hasEventOccurred())
174     {
175         toggleGpio();
176     }
177     timer->expires_at(
178         std::chrono::steady_clock::now() + std::chrono::seconds(5));
179     timer->async_wait(boost::bind(&GpioEventHandler::handleTimerExpiry, this,
180                                   boost::asio::placeholders::error, timer));
181 }
182 
doEventAndTimerSetup(std::shared_ptr<boost::asio::io_context> & ioContext)183 void GpioEventHandler::doEventAndTimerSetup(
184     std::shared_ptr<boost::asio::io_context>& ioContext)
185 {
186     prevPresPinValue = getPresencePinValue();
187 
188     static vector<std::shared_ptr<boost::asio::steady_timer>> timers;
189 
190     auto timer = make_shared<boost::asio::steady_timer>(
191         *ioContext, std::chrono::seconds(5));
192 
193     timer->async_wait(boost::bind(&GpioEventHandler::handleTimerExpiry, this,
194                                   boost::asio::placeholders::error, timer));
195 
196     timers.push_back(timer);
197 }
198 
199 } // namespace manager
200 } // namespace vpd
201 } // namespace openpower
202