1 #pragma once 2 3 #include "lpcsnoop/snoop.hpp" 4 5 #include <boost/asio.hpp> 6 #include <filesystem> 7 #include <gpiod.hpp> 8 #include <iostream> 9 #include <sdbusplus/asio/connection.hpp> 10 #include <sdbusplus/asio/object_server.hpp> 11 #include <sdbusplus/asio/property.hpp> 12 #include <sdbusplus/bus.hpp> 13 #include <sdbusplus/server.hpp> 14 #include <xyz/openbmc_project/Chassis/Buttons/HostSelector/server.hpp> 15 #include <xyz/openbmc_project/State/Boot/Raw/server.hpp> 16 17 const std::string ipmiSnoopObject = "/xyz/openbmc_project/state/boot/raw"; 18 19 const int hostParseIdx = 3; 20 const int maxPostcode = 255; 21 const int maxPosition = 4; 22 23 bool sevenSegmentLedEnabled = true; 24 25 std::vector<gpiod::line> led_lines; 26 27 using Selector = 28 sdbusplus::xyz::openbmc_project::Chassis::Buttons::server::HostSelector; 29 30 std::unique_ptr<sdbusplus::bus::match_t> matchSignal; 31 32 const std::string selectorService = "xyz.openbmc_project.Chassis.Buttons"; 33 const std::string selectorObject = 34 "/xyz/openbmc_project/Chassis/Buttons/HostSelector"; 35 const std::string selectorIface = 36 "xyz.openbmc_project.Chassis.Buttons.HostSelector"; 37 38 const std::string rawObject = "/xyz/openbmc_project/state/boot"; 39 const std::string rawIface = "xyz.openbmc_project.State.Boot.Raw"; 40 const std::string rawService = "xyz.openbmc_project.State.Boot.Raw"; 41 42 uint32_t getSelectorPosition(sdbusplus::bus_t& bus) 43 { 44 const std::string propertyName = "Position"; 45 46 auto method = 47 bus.new_method_call(selectorService.c_str(), selectorObject.c_str(), 48 "org.freedesktop.DBus.Properties", "Get"); 49 method.append(selectorIface.c_str(), propertyName); 50 51 try 52 { 53 std::variant<uint32_t> value{}; 54 auto reply = bus.call(method); 55 reply.read(value); 56 return std::get<uint32_t>(value); 57 } 58 catch (const sdbusplus::exception_t& ex) 59 { 60 std::cerr << "GetProperty call failed. " << ex.what() << std::endl; 61 return 0; 62 } 63 } 64 65 struct IpmiPostReporter : PostObject 66 { 67 IpmiPostReporter(sdbusplus::bus_t& bus, const char* objPath) : 68 PostObject(bus, objPath), bus(bus), 69 propertiesChangedSignalRaw( 70 bus, 71 sdbusplus::bus::match::rules::propertiesChanged(objPath, rawIface), 72 73 [this, &bus](sdbusplus::message_t& msg) { 74 using primarycode_t = uint64_t; 75 using secondarycode_t = std::vector<uint8_t>; 76 using postcode_t = std::tuple<primarycode_t, secondarycode_t>; 77 78 /* sevenSegmentLedEnabled flag is set when GPIO pins are not 79 there 7 seg display for fewer platforms. So, the code for 80 postcode dispay and Get Selector position can be skipped in 81 those platforms. 82 */ 83 if (!sevenSegmentLedEnabled) 84 { 85 return; 86 } 87 88 std::string objectName; 89 std::string InterfaceName; 90 std::map<std::string, std::variant<postcode_t>> msgData; 91 msg.read(InterfaceName, msgData); 92 93 std::filesystem::path name(msg.get_path()); 94 objectName = name.filename(); 95 96 std::string hostNumStr = objectName.substr(hostParseIdx); 97 size_t hostNum = std::stoi(hostNumStr); 98 99 size_t position = getSelectorPosition(bus); 100 101 if (position > maxPosition) 102 { 103 std::cerr << "Invalid position. Position should be 1 to 4 " 104 "for all hosts " 105 << std::endl; 106 } 107 108 // Check if it was the Value property that changed. 109 auto valPropMap = msgData.find("Value"); 110 if (valPropMap == msgData.end()) 111 { 112 std::cerr << "Value property is not found " << std::endl; 113 return; 114 } 115 uint64_t postcode = 116 std::get<0>(std::get<postcode_t>(valPropMap->second)); 117 118 if (postcode <= maxPostcode) 119 { 120 if (position == hostNum) 121 { 122 uint8_t postcode_8bit = 123 static_cast<uint8_t>(postcode & 0x0000FF); 124 125 // write postcode into seven segment display 126 if (postCodeDisplay(postcode_8bit) < 0) 127 { 128 fprintf(stderr, "Error in display the postcode\n"); 129 } 130 } 131 else 132 { 133 fprintf(stderr, "Host Selector Position and host " 134 "number is not matched..\n"); 135 } 136 } 137 else 138 { 139 fprintf(stderr, "invalid postcode value \n"); 140 } 141 }) 142 { 143 } 144 145 sdbusplus::bus_t& bus; 146 sdbusplus::bus::match_t propertiesChangedSignalRaw; 147 int postCodeDisplay(uint8_t); 148 void getSelectorPositionSignal(sdbusplus::bus_t& bus); 149 }; 150 151 // Configure the seven segment display connected GPIOs direction 152 int configGPIODirOutput() 153 { 154 std::string gpioStr; 155 // Need to define gpio names LED_POST_CODE_0 to 8 in dts file 156 std::string gpioName = "LED_POST_CODE_"; 157 const int value = 0; 158 159 for (int iteration = 0; iteration < 8; iteration++) 160 { 161 gpioStr = gpioName + std::to_string(iteration); 162 gpiod::line gpioLine = gpiod::find_line(gpioStr); 163 164 if (!gpioLine) 165 { 166 std::string errMsg = "Failed to find the " + gpioStr + " line"; 167 std::cerr << errMsg.c_str() << std::endl; 168 169 /* sevenSegmentLedEnabled flag is unset when GPIO pins are not there 170 * 7 seg display for fewer platforms. 171 */ 172 sevenSegmentLedEnabled = false; 173 return -1; 174 } 175 176 led_lines.push_back(gpioLine); 177 // Request GPIO output to specified value 178 try 179 { 180 gpioLine.request({__FUNCTION__, 181 gpiod::line_request::DIRECTION_OUTPUT, 182 gpiod::line_request::FLAG_ACTIVE_LOW}, 183 value); 184 } 185 catch (std::exception&) 186 { 187 std::string errMsg = "Failed to request " + gpioStr + " output"; 188 std::cerr << errMsg.c_str() << std::endl; 189 return -1; 190 } 191 } 192 193 return 0; 194 } 195 196 // Display the received postcode into seven segment display 197 int IpmiPostReporter::postCodeDisplay(uint8_t status) 198 { 199 for (int iteration = 0; iteration < 8; iteration++) 200 { 201 // split byte to write into GPIOs 202 int value = !((status >> iteration) & 0x01); 203 204 led_lines[iteration].set_value(value); 205 } 206 return 0; 207 } 208