xref: /openbmc/openpower-vpd-parser/vpd-manager/gpioMonitor.cpp (revision 8e15b93ada4ab399db36dec5f525ff93bacb5353)
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                 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                 devNameAddr = eachInventory["devAddress"];
90                 driverType = eachInventory["driverType"];
91                 busType = eachInventory["busType"];
92 
93                 // Init all Gpio info variables
94                 std::shared_ptr<GpioEventHandler> gpioObj =
95                     make_shared<GpioEventHandler>(
96                         presencePinName, presenceValue, outputPinName,
97                         outputValue, devNameAddr, driverType, busType,
98                         objectPath, event);
99 
100                 gpioObjects.push_back(gpioObj);
101             }
102         }
103     }
104 }
105 
106 void GpioEventHandler::toggleGpio()
107 {
108     bool presPinVal = getPresencePinValue();
109     bool isPresent = false;
110 
111     // preserve the new value
112     prevPresPinValue = presPinVal;
113 
114     if (presPinVal == presenceValue)
115     {
116         isPresent = true;
117     }
118 
119     // if FRU went away set the present property to false
120     if (!isPresent)
121     {
122         inventory::ObjectMap objects;
123         inventory::InterfaceMap interfaces;
124         inventory::PropertyMap presProp;
125 
126         presProp.emplace("Present", false);
127         interfaces.emplace("xyz.openbmc_project.Inventory.Item", presProp);
128         objects.emplace(objectPath, move(interfaces));
129 
130         common::utility::callPIM(move(objects));
131     }
132 
133     gpiod::line outputLine = gpiod::find_line(outputPin);
134     if (!outputLine)
135     {
136         cerr << "Error: toggleGpio: couldn't find output line:" << outputPin
137              << ". Skipping update\n";
138 
139         return;
140     }
141 
142     outputLine.request({"FRU presence: update the output GPIO pin",
143                         gpiod::line_request::DIRECTION_OUTPUT, 0},
144                        isPresent ? outputValue : (!outputValue));
145 
146     string cmnd = createBindUnbindDriverCmnd(devNameAddr, busType, driverType,
147                                              isPresent ? "bind" : "unbind");
148 
149     cout << cmnd << endl;
150     executeCmd(cmnd);
151 }
152 
153 void GpioEventHandler::doEventAndTimerSetup(sdeventplus::Event& event)
154 {
155     prevPresPinValue = getPresencePinValue();
156 
157     static vector<shared_ptr<Timer>> timers;
158     shared_ptr<Timer> timer = make_shared<Timer>(
159         event,
160         [this](Timer&) {
161             if (hasEventOccurred())
162             {
163                 toggleGpio();
164             }
165         },
166         std::chrono::seconds{5s});
167 
168     timers.push_back(timer);
169 }
170 
171 } // namespace manager
172 } // namespace vpd
173 } // namespace openpower