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