1 #include "sensor.hpp" 2 3 #include "utils/clock.hpp" 4 5 #include <boost/container/flat_map.hpp> 6 #include <phosphor-logging/log.hpp> 7 #include <sdbusplus/asio/property.hpp> 8 9 #include <functional> 10 11 Sensor::Sensor(interfaces::Sensor::Id sensorId, 12 const std::string& sensorMetadata, boost::asio::io_context& ioc, 13 const std::shared_ptr<sdbusplus::asio::connection>& bus) : 14 sensorId(std::move(sensorId)), 15 sensorMetadata(sensorMetadata), ioc(ioc), bus(bus) 16 {} 17 18 Sensor::Id Sensor::makeId(std::string_view service, std::string_view path) 19 { 20 return Id("Sensor", service, path); 21 } 22 23 Sensor::Id Sensor::id() const 24 { 25 return sensorId; 26 } 27 28 std::string Sensor::metadata() const 29 { 30 return sensorMetadata; 31 } 32 33 void Sensor::async_read() 34 { 35 uniqueCall([this](auto lock) { async_read(std::move(lock)); }); 36 } 37 38 void 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", 45 [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 } 55 if (auto self = weakSelf.lock()) 56 { 57 self->updateValue(newValue); 58 } 59 }); 60 } 61 62 void Sensor::registerForUpdates( 63 const std::weak_ptr<interfaces::SensorListener>& weakListener) 64 { 65 listeners.erase( 66 std::remove_if(listeners.begin(), listeners.end(), 67 [](const auto& listener) { return listener.expired(); }), 68 listeners.end()); 69 70 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 85 void 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 101 void Sensor::updateValue(double newValue) 102 { 103 timestamp = Clock().timestamp(); 104 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 129 void 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 142 signalMonitor = std::make_unique<sdbusplus::bus::match_t>( 143 *bus, param, 144 [weakSelf = weak_from_this()](sdbusplus::message::message& message) { 145 signalProc(weakSelf, message); 146 }); 147 } 148 149 void 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", 175 phosphor::logging::entry("SENSOR_PATH=%s", 176 self->sensorId.path.c_str())); 177 } 178 } 179 } 180 } 181 } 182