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