1*d7be555eSGeorge Liu #include "IpmbSDRSensor.hpp"
2*d7be555eSGeorge Liu #include "IpmbSensor.hpp"
3*d7be555eSGeorge Liu #include "Utils.hpp"
4*d7be555eSGeorge Liu 
5*d7be555eSGeorge Liu #include <boost/asio/error.hpp>
6*d7be555eSGeorge Liu #include <boost/asio/io_context.hpp>
7*d7be555eSGeorge Liu #include <boost/asio/post.hpp>
8*d7be555eSGeorge Liu #include <boost/asio/steady_timer.hpp>
9*d7be555eSGeorge Liu #include <boost/container/flat_map.hpp>
10*d7be555eSGeorge Liu #include <sdbusplus/asio/connection.hpp>
11*d7be555eSGeorge Liu #include <sdbusplus/asio/object_server.hpp>
12*d7be555eSGeorge Liu #include <sdbusplus/bus.hpp>
13*d7be555eSGeorge Liu #include <sdbusplus/bus/match.hpp>
14*d7be555eSGeorge Liu #include <sdbusplus/message.hpp>
15*d7be555eSGeorge Liu 
16*d7be555eSGeorge Liu #include <array>
17*d7be555eSGeorge Liu #include <chrono>
18*d7be555eSGeorge Liu #include <cstddef>
19*d7be555eSGeorge Liu #include <cstdint>
20*d7be555eSGeorge Liu #include <functional>
21*d7be555eSGeorge Liu #include <iostream>
22*d7be555eSGeorge Liu #include <memory>
23*d7be555eSGeorge Liu #include <string>
24*d7be555eSGeorge Liu #include <variant>
25*d7be555eSGeorge Liu #include <vector>
26*d7be555eSGeorge Liu 
27*d7be555eSGeorge Liu std::unique_ptr<boost::asio::steady_timer> initCmdTimer;
28*d7be555eSGeorge Liu boost::container::flat_map<std::string, std::shared_ptr<IpmbSensor>> sensors;
29*d7be555eSGeorge Liu boost::container::flat_map<uint8_t, std::shared_ptr<IpmbSDRDevice>> sdrsensor;
30*d7be555eSGeorge Liu 
sdrHandler(boost::container::flat_map<uint8_t,std::shared_ptr<IpmbSDRDevice>> sdrsensor,sdbusplus::message_t & message,std::shared_ptr<sdbusplus::asio::connection> & dbusConnection)31*d7be555eSGeorge Liu void sdrHandler(
32*d7be555eSGeorge Liu     boost::container::flat_map<uint8_t, std::shared_ptr<IpmbSDRDevice>>
33*d7be555eSGeorge Liu         sdrsensor,
34*d7be555eSGeorge Liu     sdbusplus::message_t& message,
35*d7be555eSGeorge Liu     std::shared_ptr<sdbusplus::asio::connection>& dbusConnection)
36*d7be555eSGeorge Liu {
37*d7be555eSGeorge Liu     std::string objectName;
38*d7be555eSGeorge Liu     SensorBaseConfigMap values;
39*d7be555eSGeorge Liu     message.read(objectName, values);
40*d7be555eSGeorge Liu 
41*d7be555eSGeorge Liu     auto findBus = values.find("Bus");
42*d7be555eSGeorge Liu     if (findBus == values.end())
43*d7be555eSGeorge Liu     {
44*d7be555eSGeorge Liu         return;
45*d7be555eSGeorge Liu     }
46*d7be555eSGeorge Liu 
47*d7be555eSGeorge Liu     uint8_t busIndex = loadVariant<uint8_t>(values, "Bus");
48*d7be555eSGeorge Liu 
49*d7be555eSGeorge Liu     auto& sdrsen = sdrsensor[busIndex];
50*d7be555eSGeorge Liu     sdrsen = nullptr;
51*d7be555eSGeorge Liu     sdrsen = std::make_shared<IpmbSDRDevice>(dbusConnection, busIndex);
52*d7be555eSGeorge Liu     sdrsen->getSDRRepositoryInfo();
53*d7be555eSGeorge Liu }
54*d7be555eSGeorge Liu 
reinitSensors(sdbusplus::message_t & message)55*d7be555eSGeorge Liu void reinitSensors(sdbusplus::message_t& message)
56*d7be555eSGeorge Liu {
57*d7be555eSGeorge Liu     constexpr const size_t reinitWaitSeconds = 2;
58*d7be555eSGeorge Liu     std::string objectName;
59*d7be555eSGeorge Liu     boost::container::flat_map<std::string, std::variant<std::string>> values;
60*d7be555eSGeorge Liu     message.read(objectName, values);
61*d7be555eSGeorge Liu 
62*d7be555eSGeorge Liu     auto findStatus = values.find(power::property);
63*d7be555eSGeorge Liu     if (findStatus != values.end())
64*d7be555eSGeorge Liu     {
65*d7be555eSGeorge Liu         bool powerStatus =
66*d7be555eSGeorge Liu             std::get<std::string>(findStatus->second).ends_with(".Running");
67*d7be555eSGeorge Liu         if (powerStatus)
68*d7be555eSGeorge Liu         {
69*d7be555eSGeorge Liu             if (!initCmdTimer)
70*d7be555eSGeorge Liu             {
71*d7be555eSGeorge Liu                 // this should be impossible
72*d7be555eSGeorge Liu                 return;
73*d7be555eSGeorge Liu             }
74*d7be555eSGeorge Liu             // we seem to send this command too fast sometimes, wait before
75*d7be555eSGeorge Liu             // sending
76*d7be555eSGeorge Liu             initCmdTimer->expires_after(
77*d7be555eSGeorge Liu                 std::chrono::seconds(reinitWaitSeconds));
78*d7be555eSGeorge Liu 
79*d7be555eSGeorge Liu             initCmdTimer->async_wait([](const boost::system::error_code ec) {
80*d7be555eSGeorge Liu                 if (ec == boost::asio::error::operation_aborted)
81*d7be555eSGeorge Liu                 {
82*d7be555eSGeorge Liu                     return; // we're being canceled
83*d7be555eSGeorge Liu                 }
84*d7be555eSGeorge Liu 
85*d7be555eSGeorge Liu                 for (const auto& [name, sensor] : sensors)
86*d7be555eSGeorge Liu                 {
87*d7be555eSGeorge Liu                     if (sensor)
88*d7be555eSGeorge Liu                     {
89*d7be555eSGeorge Liu                         sensor->runInitCmd();
90*d7be555eSGeorge Liu                     }
91*d7be555eSGeorge Liu                 }
92*d7be555eSGeorge Liu             });
93*d7be555eSGeorge Liu         }
94*d7be555eSGeorge Liu     }
95*d7be555eSGeorge Liu }
96*d7be555eSGeorge Liu 
main()97*d7be555eSGeorge Liu int main()
98*d7be555eSGeorge Liu {
99*d7be555eSGeorge Liu     boost::asio::io_context io;
100*d7be555eSGeorge Liu     auto systemBus = std::make_shared<sdbusplus::asio::connection>(io);
101*d7be555eSGeorge Liu     sdbusplus::asio::object_server objectServer(systemBus, true);
102*d7be555eSGeorge Liu     objectServer.add_manager("/xyz/openbmc_project/sensors");
103*d7be555eSGeorge Liu     systemBus->request_name("xyz.openbmc_project.IpmbSensor");
104*d7be555eSGeorge Liu 
105*d7be555eSGeorge Liu     initCmdTimer = std::make_unique<boost::asio::steady_timer>(io);
106*d7be555eSGeorge Liu 
107*d7be555eSGeorge Liu     boost::asio::post(io, [&]() {
108*d7be555eSGeorge Liu         createSensors(io, objectServer, sensors, systemBus);
109*d7be555eSGeorge Liu     });
110*d7be555eSGeorge Liu 
111*d7be555eSGeorge Liu     boost::asio::steady_timer configTimer(io);
112*d7be555eSGeorge Liu 
113*d7be555eSGeorge Liu     std::function<void(sdbusplus::message_t&)> eventHandler =
114*d7be555eSGeorge Liu         [&](sdbusplus::message_t&) {
115*d7be555eSGeorge Liu             configTimer.expires_after(std::chrono::seconds(1));
116*d7be555eSGeorge Liu             // create a timer because normally multiple properties change
117*d7be555eSGeorge Liu             configTimer.async_wait([&](const boost::system::error_code& ec) {
118*d7be555eSGeorge Liu                 if (ec == boost::asio::error::operation_aborted)
119*d7be555eSGeorge Liu                 {
120*d7be555eSGeorge Liu                     return; // we're being canceled
121*d7be555eSGeorge Liu                 }
122*d7be555eSGeorge Liu                 createSensors(io, objectServer, sensors, systemBus);
123*d7be555eSGeorge Liu                 if (sensors.empty())
124*d7be555eSGeorge Liu                 {
125*d7be555eSGeorge Liu                     std::cout << "Configuration not detected\n";
126*d7be555eSGeorge Liu                 }
127*d7be555eSGeorge Liu             });
128*d7be555eSGeorge Liu         };
129*d7be555eSGeorge Liu 
130*d7be555eSGeorge Liu     std::vector<std::unique_ptr<sdbusplus::bus::match_t>> matches =
131*d7be555eSGeorge Liu         setupPropertiesChangedMatches(
132*d7be555eSGeorge Liu             *systemBus, std::to_array<const char*>({sensorType}), eventHandler);
133*d7be555eSGeorge Liu 
134*d7be555eSGeorge Liu     sdbusplus::bus::match_t powerChangeMatch(
135*d7be555eSGeorge Liu         static_cast<sdbusplus::bus_t&>(*systemBus),
136*d7be555eSGeorge Liu         "type='signal',interface='" + std::string(properties::interface) +
137*d7be555eSGeorge Liu             "',path='" + std::string(power::path) + "',arg0='" +
138*d7be555eSGeorge Liu             std::string(power::interface) + "'",
139*d7be555eSGeorge Liu         reinitSensors);
140*d7be555eSGeorge Liu 
141*d7be555eSGeorge Liu     auto matchSignal = std::make_shared<sdbusplus::bus::match_t>(
142*d7be555eSGeorge Liu         static_cast<sdbusplus::bus_t&>(*systemBus),
143*d7be555eSGeorge Liu         "type='signal',member='PropertiesChanged',path_namespace='" +
144*d7be555eSGeorge Liu             std::string(inventoryPath) + "',arg0namespace='" +
145*d7be555eSGeorge Liu             configInterfaceName(sdrInterface) + "'",
146*d7be555eSGeorge Liu         [&systemBus](sdbusplus::message_t& msg) {
147*d7be555eSGeorge Liu             sdrHandler(sdrsensor, msg, systemBus);
148*d7be555eSGeorge Liu         });
149*d7be555eSGeorge Liu 
150*d7be555eSGeorge Liu     // Watch for entity-manager to remove configuration interfaces
151*d7be555eSGeorge Liu     // so the corresponding sensors can be removed.
152*d7be555eSGeorge Liu     auto ifaceRemovedMatch = std::make_shared<sdbusplus::bus::match_t>(
153*d7be555eSGeorge Liu         static_cast<sdbusplus::bus_t&>(*systemBus),
154*d7be555eSGeorge Liu         "type='signal',member='InterfacesRemoved',arg0path='" +
155*d7be555eSGeorge Liu             std::string(inventoryPath) + "/'",
156*d7be555eSGeorge Liu         [](sdbusplus::message_t& msg) { interfaceRemoved(msg, sensors); });
157*d7be555eSGeorge Liu 
158*d7be555eSGeorge Liu     setupManufacturingModeMatch(*systemBus);
159*d7be555eSGeorge Liu     io.run();
160*d7be555eSGeorge Liu     return 0;
161*d7be555eSGeorge Liu }
162