blob: d38fbd9500dcaddf8da9c604616bcc3a1a84b472 [file] [log] [blame]
Krzysztof Grobelnyb5645942020-09-29 11:52:45 +02001#include "sensor.hpp"
2
3#include "utils/detached_timer.hpp"
4
5#include <boost/container/flat_map.hpp>
6#include <phosphor-logging/log.hpp>
7#include <sdbusplus/asio/property.hpp>
8#include <sdbusplus/bus/match.hpp>
9
10#include <functional>
11#include <iostream>
12
13Sensor::Sensor(interfaces::Sensor::Id sensorId, boost::asio::io_context& ioc,
14 const std::shared_ptr<sdbusplus::asio::connection>& bus) :
15 sensorId(std::move(sensorId)),
16 ioc(ioc), bus(bus)
17{}
18
19Sensor::Id Sensor::makeId(std::string_view service, std::string_view path)
20{
21 return Id("Sensor", service, path);
22}
23
24Sensor::Id Sensor::id() const
25{
26 return sensorId;
27}
28
29void Sensor::async_read()
30{
31 uniqueCall([this](auto lock) { async_read(std::move(lock)); });
32}
33
34void Sensor::async_read(std::shared_ptr<utils::UniqueCall::Lock> lock)
35{
36 makeSignalMonitor();
37
38 sdbusplus::asio::getProperty<double>(
39 *bus, sensorId.service, sensorId.path,
40 "xyz.openbmc_project.Sensor.Value", "Value",
41 [lock, id = sensorId,
42 weakSelf = weak_from_this()](boost::system::error_code ec) {
43 phosphor::logging::log<phosphor::logging::level::ERR>(
44 "DBus 'GetProperty' call failed on Sensor Value",
45 phosphor::logging::entry("sensor=%s, ec=%lu", id.str().c_str(),
46 ec.value()));
47
48 if (auto self = weakSelf.lock())
49 {
50
51 constexpr auto retryIntervalAfterFailedRead =
52 std::chrono::seconds(30);
53 utils::makeDetachedTimer(
54 self->ioc, retryIntervalAfterFailedRead, [weakSelf] {
55 if (auto self = weakSelf.lock())
56 {
57 self->async_read();
58 }
59 });
60 }
61 },
62 [lock, weakSelf = weak_from_this()](double newValue) {
63 if (auto self = weakSelf.lock())
64 {
65 self->updateValue(newValue);
66 }
67 });
68}
69
70void Sensor::registerForUpdates(
71 const std::weak_ptr<interfaces::SensorListener>& weakListener)
72{
73 if (auto listener = weakListener.lock())
74 {
75 listeners.emplace_back(weakListener);
76
77 if (value)
78 {
79 listener->sensorUpdated(*this, timestamp, *value);
80 }
81 else
82 {
83 async_read();
84 }
85 }
86}
87
88void Sensor::updateValue(double newValue)
89{
90 timestamp = std::time(0);
91
92 if (value == newValue)
93 {
94 for (const auto& weakListener : listeners)
95 {
96 if (auto listener = weakListener.lock())
97 {
98 listener->sensorUpdated(*this, timestamp);
99 }
100 }
101 }
102 else
103 {
104 value = newValue;
105
106 for (const auto& weakListener : listeners)
107 {
108 if (auto listener = weakListener.lock())
109 {
110 listener->sensorUpdated(*this, timestamp, *value);
111 }
112 }
113 }
114}
115
116void Sensor::makeSignalMonitor()
117{
118 if (signalMonitor)
119 {
120 return;
121 }
122
123 using namespace std::string_literals;
124
125 const auto param = "type='signal',member='PropertiesChanged',path='"s +
126 sensorId.path +
127 "',arg0='xyz.openbmc_project.Sensor.Value'"s;
128
129 signalMonitor = std::make_unique<sdbusplus::bus::match::match>(
130 *bus, param,
131 [weakSelf = weak_from_this()](sdbusplus::message::message& message) {
132 signalProc(weakSelf, message);
133 });
134}
135
136void Sensor::signalProc(const std::weak_ptr<Sensor>& weakSelf,
137 sdbusplus::message::message& message)
138{
139 if (auto self = weakSelf.lock())
140 {
141 std::string iface;
142 boost::container::flat_map<std::string, ValueVariant>
143 changed_properties;
144 std::vector<std::string> invalidated_properties;
145
146 message.read(iface, changed_properties, invalidated_properties);
147
148 if (iface == "xyz.openbmc_project.Sensor.Value")
149 {
150 const auto it = changed_properties.find("Value");
151 if (it != changed_properties.end())
152 {
153 if (auto val = std::get_if<double>(&it->second))
154 {
155 self->updateValue(*val);
156 }
157 else
158 {
159 phosphor::logging::log<phosphor::logging::level::ERR>(
160 "Failed to receive Value from Sensor "
161 "PropertiesChanged signal",
162 phosphor::logging::entry("sensor=%s",
163 self->sensorId.path.c_str()));
164 }
165 }
166 }
167 }
168}