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