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 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 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 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