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