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