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