blob: efebc5d1d240eb983dd274d02bb86a51eb4f614f [file] [log] [blame]
#include "sensor.hpp"
#include "utils/clock.hpp"
#include <boost/container/flat_map.hpp>
#include <phosphor-logging/log.hpp>
#include <sdbusplus/asio/property.hpp>
#include <functional>
Sensor::Sensor(interfaces::Sensor::Id sensorId,
const std::string& sensorMetadata, boost::asio::io_context& ioc,
const std::shared_ptr<sdbusplus::asio::connection>& bus) :
sensorId(std::move(sensorId)),
sensorMetadata(sensorMetadata), ioc(ioc), bus(bus)
{}
Sensor::Id Sensor::makeId(std::string_view service, std::string_view path)
{
return Id("Sensor", service, path);
}
Sensor::Id Sensor::id() const
{
return sensorId;
}
std::string Sensor::metadata() const
{
return sensorMetadata;
}
std::string Sensor::getName() const
{
return sensorMetadata.empty() ? sensorId.path : sensorMetadata;
}
void Sensor::async_read()
{
uniqueCall([this](auto lock) { async_read(std::move(lock)); });
}
void Sensor::async_read(std::shared_ptr<utils::UniqueCall::Lock> lock)
{
makeSignalMonitor();
sdbusplus::asio::getProperty<double>(
*bus, sensorId.service, sensorId.path,
"xyz.openbmc_project.Sensor.Value", "Value",
[lock, id = sensorId, weakSelf = weak_from_this()](
boost::system::error_code ec, double newValue) {
if (ec)
{
phosphor::logging::log<phosphor::logging::level::WARNING>(
"DBus 'GetProperty' call failed on Sensor Value",
phosphor::logging::entry("SENSOR_PATH=%s", id.path.c_str()),
phosphor::logging::entry("ERROR_CODE=%d", ec.value()));
return;
}
if (auto self = weakSelf.lock())
{
self->updateValue(newValue);
}
});
}
void Sensor::registerForUpdates(
const std::weak_ptr<interfaces::SensorListener>& weakListener)
{
listeners.erase(
std::remove_if(listeners.begin(), listeners.end(),
[](const auto& listener) { return listener.expired(); }),
listeners.end());
if (auto listener = weakListener.lock())
{
listeners.emplace_back(weakListener);
if (value)
{
listener->sensorUpdated(*this, timestamp, *value);
}
else
{
async_read();
}
}
}
void Sensor::unregisterFromUpdates(
const std::weak_ptr<interfaces::SensorListener>& weakListener)
{
if (auto listener = weakListener.lock())
{
listeners.erase(
std::remove_if(
listeners.begin(), listeners.end(),
[listenerToUnregister = listener.get()](const auto& listener) {
return (listener.expired() ||
listener.lock().get() == listenerToUnregister);
}),
listeners.end());
}
}
void Sensor::updateValue(double newValue)
{
timestamp = Clock().steadyTimestamp();
if (value != newValue)
{
value = newValue;
for (const auto& weakListener : listeners)
{
if (auto listener = weakListener.lock())
{
listener->sensorUpdated(*this, timestamp, *value);
}
}
}
}
void Sensor::makeSignalMonitor()
{
if (signalMonitor)
{
return;
}
using namespace std::string_literals;
const auto param = "type='signal',member='PropertiesChanged',path='"s +
sensorId.path +
"',arg0='xyz.openbmc_project.Sensor.Value'"s;
signalMonitor = std::make_unique<sdbusplus::bus::match_t>(
*bus, param,
[weakSelf = weak_from_this()](sdbusplus::message_t& message) {
signalProc(weakSelf, message);
});
}
void Sensor::signalProc(const std::weak_ptr<Sensor>& weakSelf,
sdbusplus::message_t& message)
{
if (auto self = weakSelf.lock())
{
std::string iface;
boost::container::flat_map<std::string, ValueVariant>
changed_properties;
std::vector<std::string> invalidated_properties;
message.read(iface, changed_properties, invalidated_properties);
if (iface == "xyz.openbmc_project.Sensor.Value")
{
const auto it = changed_properties.find("Value");
if (it != changed_properties.end())
{
if (auto val = std::get_if<double>(&it->second))
{
self->updateValue(*val);
}
else
{
phosphor::logging::log<phosphor::logging::level::ERR>(
"Failed to receive Value from Sensor "
"PropertiesChanged signal",
phosphor::logging::entry("SENSOR_PATH=%s",
self->sensorId.path.c_str()));
}
}
}
}
}
LabeledSensorInfo Sensor::getLabeledSensorInfo() const
{
return LabeledSensorInfo(sensorId.service, sensorId.path, sensorMetadata);
}