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 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 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 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 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(std::chrono::steady_clock::now() + 178 std::chrono::seconds(5)); 179 timer->async_wait(boost::bind(&GpioEventHandler::handleTimerExpiry, this, 180 boost::asio::placeholders::error, timer)); 181 } 182 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