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