blob: 9223264d497a022a4aa0948ff4982a67faf9fbb0 [file] [log] [blame]
#include "IpmbSDRSensor.hpp"
#include "IpmbSensor.hpp"
#include "Utils.hpp"
#include <boost/asio/error.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/post.hpp>
#include <boost/asio/steady_timer.hpp>
#include <boost/container/flat_map.hpp>
#include <sdbusplus/asio/connection.hpp>
#include <sdbusplus/asio/object_server.hpp>
#include <sdbusplus/bus.hpp>
#include <sdbusplus/bus/match.hpp>
#include <sdbusplus/message.hpp>
#include <array>
#include <chrono>
#include <cstddef>
#include <cstdint>
#include <functional>
#include <iostream>
#include <memory>
#include <string>
#include <variant>
#include <vector>
std::unique_ptr<boost::asio::steady_timer> initCmdTimer;
boost::container::flat_map<std::string, std::shared_ptr<IpmbSensor>> sensors;
boost::container::flat_map<uint8_t, std::shared_ptr<IpmbSDRDevice>> sdrsensor;
void sdrHandler(
boost::container::flat_map<uint8_t, std::shared_ptr<IpmbSDRDevice>>
sdrsensor,
sdbusplus::message_t& message,
std::shared_ptr<sdbusplus::asio::connection>& dbusConnection)
{
std::string objectName;
SensorBaseConfigMap values;
message.read(objectName, values);
auto findBus = values.find("Bus");
if (findBus == values.end())
{
return;
}
uint8_t busIndex = loadVariant<uint8_t>(values, "Bus");
auto& sdrsen = sdrsensor[busIndex];
sdrsen = nullptr;
sdrsen = std::make_shared<IpmbSDRDevice>(dbusConnection, busIndex);
sdrsen->getSDRRepositoryInfo();
}
void reinitSensors(sdbusplus::message_t& message)
{
constexpr const size_t reinitWaitSeconds = 2;
std::string objectName;
boost::container::flat_map<std::string, std::variant<std::string>> values;
message.read(objectName, values);
auto findStatus = values.find(power::property);
if (findStatus != values.end())
{
bool powerStatus =
std::get<std::string>(findStatus->second).ends_with(".Running");
if (powerStatus)
{
if (!initCmdTimer)
{
// this should be impossible
return;
}
// we seem to send this command too fast sometimes, wait before
// sending
initCmdTimer->expires_after(
std::chrono::seconds(reinitWaitSeconds));
initCmdTimer->async_wait([](const boost::system::error_code ec) {
if (ec == boost::asio::error::operation_aborted)
{
return; // we're being canceled
}
for (const auto& [name, sensor] : sensors)
{
if (sensor)
{
sensor->runInitCmd();
}
}
});
}
}
}
int main()
{
boost::asio::io_context io;
auto systemBus = std::make_shared<sdbusplus::asio::connection>(io);
sdbusplus::asio::object_server objectServer(systemBus, true);
objectServer.add_manager("/xyz/openbmc_project/sensors");
systemBus->request_name("xyz.openbmc_project.IpmbSensor");
initCmdTimer = std::make_unique<boost::asio::steady_timer>(io);
boost::asio::post(
io, [&]() { createSensors(io, objectServer, sensors, systemBus); });
boost::asio::steady_timer configTimer(io);
std::function<void(sdbusplus::message_t&)> eventHandler =
[&](sdbusplus::message_t&) {
configTimer.expires_after(std::chrono::seconds(1));
// create a timer because normally multiple properties change
configTimer.async_wait([&](const boost::system::error_code& ec) {
if (ec == boost::asio::error::operation_aborted)
{
return; // we're being canceled
}
createSensors(io, objectServer, sensors, systemBus);
if (sensors.empty())
{
std::cout << "Configuration not detected\n";
}
});
};
std::vector<std::unique_ptr<sdbusplus::bus::match_t>> matches =
setupPropertiesChangedMatches(
*systemBus, std::to_array<const char*>({sensorType}), eventHandler);
sdbusplus::bus::match_t powerChangeMatch(
static_cast<sdbusplus::bus_t&>(*systemBus),
"type='signal',interface='" + std::string(properties::interface) +
"',path='" + std::string(power::path) + "',arg0='" +
std::string(power::interface) + "'",
reinitSensors);
auto matchSignal = std::make_shared<sdbusplus::bus::match_t>(
static_cast<sdbusplus::bus_t&>(*systemBus),
"type='signal',member='PropertiesChanged',path_namespace='" +
std::string(inventoryPath) + "',arg0namespace='" +
configInterfaceName(sdrInterface) + "'",
[&systemBus](sdbusplus::message_t& msg) {
sdrHandler(sdrsensor, msg, systemBus);
});
// Watch for entity-manager to remove configuration interfaces
// so the corresponding sensors can be removed.
auto ifaceRemovedMatch = std::make_shared<sdbusplus::bus::match_t>(
static_cast<sdbusplus::bus_t&>(*systemBus),
"type='signal',member='InterfacesRemoved',arg0path='" +
std::string(inventoryPath) + "/'",
[](sdbusplus::message_t& msg) { interfaceRemoved(msg, sensors); });
setupManufacturingModeMatch(*systemBus);
io.run();
return 0;
}