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