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