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, 39 weakSelf = weak_from_this()](boost::system::error_code ec) { 40 phosphor::logging::log<phosphor::logging::level::WARNING>( 41 "DBus 'GetProperty' call failed on Sensor Value", 42 phosphor::logging::entry("SENSOR_PATH=%s", id.path.c_str()), 43 phosphor::logging::entry("ERROR_CODE=%d", ec.value())); 44 }, 45 [lock, weakSelf = weak_from_this()](double newValue) { 46 if (auto self = weakSelf.lock()) 47 { 48 self->updateValue(newValue); 49 } 50 }); 51 } 52 53 void Sensor::registerForUpdates( 54 const std::weak_ptr<interfaces::SensorListener>& weakListener) 55 { 56 listeners.erase( 57 std::remove_if(listeners.begin(), listeners.end(), 58 [](const auto& listener) { return listener.expired(); }), 59 listeners.end()); 60 61 if (auto listener = weakListener.lock()) 62 { 63 listeners.emplace_back(weakListener); 64 65 if (value) 66 { 67 listener->sensorUpdated(*this, timestamp, *value); 68 } 69 else 70 { 71 async_read(); 72 } 73 } 74 } 75 76 void Sensor::updateValue(double newValue) 77 { 78 timestamp = std::time(0); 79 80 if (value == newValue) 81 { 82 for (const auto& weakListener : listeners) 83 { 84 if (auto listener = weakListener.lock()) 85 { 86 listener->sensorUpdated(*this, timestamp); 87 } 88 } 89 } 90 else 91 { 92 value = newValue; 93 94 for (const auto& weakListener : listeners) 95 { 96 if (auto listener = weakListener.lock()) 97 { 98 listener->sensorUpdated(*this, timestamp, *value); 99 } 100 } 101 } 102 } 103 104 void Sensor::makeSignalMonitor() 105 { 106 if (signalMonitor) 107 { 108 return; 109 } 110 111 using namespace std::string_literals; 112 113 const auto param = "type='signal',member='PropertiesChanged',path='"s + 114 sensorId.path + 115 "',arg0='xyz.openbmc_project.Sensor.Value'"s; 116 117 signalMonitor = std::make_unique<sdbusplus::bus::match::match>( 118 *bus, param, 119 [weakSelf = weak_from_this()](sdbusplus::message::message& message) { 120 signalProc(weakSelf, message); 121 }); 122 } 123 124 void Sensor::signalProc(const std::weak_ptr<Sensor>& weakSelf, 125 sdbusplus::message::message& message) 126 { 127 if (auto self = weakSelf.lock()) 128 { 129 std::string iface; 130 boost::container::flat_map<std::string, ValueVariant> 131 changed_properties; 132 std::vector<std::string> invalidated_properties; 133 134 message.read(iface, changed_properties, invalidated_properties); 135 136 if (iface == "xyz.openbmc_project.Sensor.Value") 137 { 138 const auto it = changed_properties.find("Value"); 139 if (it != changed_properties.end()) 140 { 141 if (auto val = std::get_if<double>(&it->second)) 142 { 143 self->updateValue(*val); 144 } 145 else 146 { 147 phosphor::logging::log<phosphor::logging::level::ERR>( 148 "Failed to receive Value from Sensor " 149 "PropertiesChanged signal", 150 phosphor::logging::entry("SENSOR_PATH=%s", 151 self->sensorId.path.c_str())); 152 } 153 } 154 } 155 } 156 } 157