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