blob: d81e1a103681423c891ab1c38de49a98205fb5ab [file] [log] [blame]
Krzysztof Grobelnyb5645942020-09-29 11:52:45 +02001#include "sensor.hpp"
2
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +01003#include "utils/clock.hpp"
4
Krzysztof Grobelnyb5645942020-09-29 11:52:45 +02005#include <boost/container/flat_map.hpp>
6#include <phosphor-logging/log.hpp>
7#include <sdbusplus/asio/property.hpp>
Krzysztof Grobelnyb5645942020-09-29 11:52:45 +02008
9#include <functional>
Krzysztof Grobelnyb5645942020-09-29 11:52:45 +020010
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +010011Sensor::Sensor(interfaces::Sensor::Id sensorId,
12 const std::string& sensorMetadata, boost::asio::io_context& ioc,
Krzysztof Grobelnyb5645942020-09-29 11:52:45 +020013 const std::shared_ptr<sdbusplus::asio::connection>& bus) :
14 sensorId(std::move(sensorId)),
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +010015 sensorMetadata(sensorMetadata), ioc(ioc), bus(bus)
Krzysztof Grobelnyb5645942020-09-29 11:52:45 +020016{}
17
18Sensor::Id Sensor::makeId(std::string_view service, std::string_view path)
19{
20 return Id("Sensor", service, path);
21}
22
23Sensor::Id Sensor::id() const
24{
25 return sensorId;
26}
27
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +010028std::string Sensor::metadata() const
29{
30 return sensorMetadata;
31}
32
Krzysztof Grobelnyb5645942020-09-29 11:52:45 +020033void Sensor::async_read()
34{
35 uniqueCall([this](auto lock) { async_read(std::move(lock)); });
36}
37
38void Sensor::async_read(std::shared_ptr<utils::UniqueCall::Lock> lock)
39{
40 makeSignalMonitor();
41
42 sdbusplus::asio::getProperty<double>(
43 *bus, sensorId.service, sensorId.path,
44 "xyz.openbmc_project.Sensor.Value", "Value",
Ed Tanous0e7ae5d2021-02-23 14:06:49 -080045 [lock, id = sensorId, weakSelf = weak_from_this()](
46 boost::system::error_code ec, double newValue) {
47 if (ec)
48 {
49 phosphor::logging::log<phosphor::logging::level::WARNING>(
50 "DBus 'GetProperty' call failed on Sensor Value",
51 phosphor::logging::entry("SENSOR_PATH=%s", id.path.c_str()),
52 phosphor::logging::entry("ERROR_CODE=%d", ec.value()));
53 return;
54 }
Krzysztof Grobelnyb5645942020-09-29 11:52:45 +020055 if (auto self = weakSelf.lock())
56 {
57 self->updateValue(newValue);
58 }
59 });
60}
61
62void Sensor::registerForUpdates(
63 const std::weak_ptr<interfaces::SensorListener>& weakListener)
64{
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +000065 listeners.erase(
66 std::remove_if(listeners.begin(), listeners.end(),
67 [](const auto& listener) { return listener.expired(); }),
68 listeners.end());
69
Krzysztof Grobelnyb5645942020-09-29 11:52:45 +020070 if (auto listener = weakListener.lock())
71 {
72 listeners.emplace_back(weakListener);
73
74 if (value)
75 {
76 listener->sensorUpdated(*this, timestamp, *value);
77 }
78 else
79 {
80 async_read();
81 }
82 }
83}
84
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +020085void Sensor::unregisterFromUpdates(
86 const std::weak_ptr<interfaces::SensorListener>& weakListener)
87{
88 if (auto listener = weakListener.lock())
89 {
90 listeners.erase(
91 std::remove_if(
92 listeners.begin(), listeners.end(),
93 [listenerToUnregister = listener.get()](const auto& listener) {
94 return (listener.expired() ||
95 listener.lock().get() == listenerToUnregister);
96 }),
97 listeners.end());
98 }
99}
100
Krzysztof Grobelnyb5645942020-09-29 11:52:45 +0200101void Sensor::updateValue(double newValue)
102{
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100103 timestamp = Clock().steadyTimestamp();
Krzysztof Grobelnyb5645942020-09-29 11:52:45 +0200104
105 if (value == newValue)
106 {
107 for (const auto& weakListener : listeners)
108 {
109 if (auto listener = weakListener.lock())
110 {
111 listener->sensorUpdated(*this, timestamp);
112 }
113 }
114 }
115 else
116 {
117 value = newValue;
118
119 for (const auto& weakListener : listeners)
120 {
121 if (auto listener = weakListener.lock())
122 {
123 listener->sensorUpdated(*this, timestamp, *value);
124 }
125 }
126 }
127}
128
129void Sensor::makeSignalMonitor()
130{
131 if (signalMonitor)
132 {
133 return;
134 }
135
136 using namespace std::string_literals;
137
138 const auto param = "type='signal',member='PropertiesChanged',path='"s +
139 sensorId.path +
140 "',arg0='xyz.openbmc_project.Sensor.Value'"s;
141
Patrick Williams3a62ee12021-12-03 10:13:25 -0600142 signalMonitor = std::make_unique<sdbusplus::bus::match_t>(
Krzysztof Grobelnyb5645942020-09-29 11:52:45 +0200143 *bus, param,
144 [weakSelf = weak_from_this()](sdbusplus::message::message& message) {
145 signalProc(weakSelf, message);
146 });
147}
148
149void Sensor::signalProc(const std::weak_ptr<Sensor>& weakSelf,
150 sdbusplus::message::message& message)
151{
152 if (auto self = weakSelf.lock())
153 {
154 std::string iface;
155 boost::container::flat_map<std::string, ValueVariant>
156 changed_properties;
157 std::vector<std::string> invalidated_properties;
158
159 message.read(iface, changed_properties, invalidated_properties);
160
161 if (iface == "xyz.openbmc_project.Sensor.Value")
162 {
163 const auto it = changed_properties.find("Value");
164 if (it != changed_properties.end())
165 {
166 if (auto val = std::get_if<double>(&it->second))
167 {
168 self->updateValue(*val);
169 }
170 else
171 {
172 phosphor::logging::log<phosphor::logging::level::ERR>(
173 "Failed to receive Value from Sensor "
174 "PropertiesChanged signal",
Wludzik, Jozef982c5b52021-01-02 12:05:21 +0100175 phosphor::logging::entry("SENSOR_PATH=%s",
Krzysztof Grobelnyb5645942020-09-29 11:52:45 +0200176 self->sensorId.path.c_str()));
177 }
178 }
179 }
180 }
181}