1e92aba45SJagpal Singh Gill #include "base_device.hpp" 2e92aba45SJagpal Singh Gill 3e92aba45SJagpal Singh Gill #include <phosphor-logging/lg2.hpp> 4*7184805aSJagpal Singh Gill #include <xyz/openbmc_project/State/Leak/Detector/aserver.hpp> 5e92aba45SJagpal Singh Gill 6e92aba45SJagpal Singh Gill #include <numeric> 7e92aba45SJagpal Singh Gill 8e92aba45SJagpal Singh Gill namespace phosphor::modbus::rtu::device 9e92aba45SJagpal Singh Gill { 10e92aba45SJagpal Singh Gill 11e92aba45SJagpal Singh Gill PHOSPHOR_LOG2_USING; 12e92aba45SJagpal Singh Gill 13e92aba45SJagpal Singh Gill BaseDevice::BaseDevice(sdbusplus::async::context& ctx, 14*7184805aSJagpal Singh Gill const config::Config& config, PortIntf& serialPort, 15*7184805aSJagpal Singh Gill EventIntf::Events& events) : 16*7184805aSJagpal Singh Gill ctx(ctx), config(config), serialPort(serialPort), events(events) 17e92aba45SJagpal Singh Gill { 18e92aba45SJagpal Singh Gill createSensors(); 19e92aba45SJagpal Singh Gill 20e92aba45SJagpal Singh Gill info("Successfully created device {NAME}", "NAME", config.name); 21e92aba45SJagpal Singh Gill } 22e92aba45SJagpal Singh Gill 23e92aba45SJagpal Singh Gill static auto getObjectPath(const std::string& sensorType, 24e92aba45SJagpal Singh Gill const std::string& sensorName) 25e92aba45SJagpal Singh Gill -> sdbusplus::message::object_path 26e92aba45SJagpal Singh Gill { 27e92aba45SJagpal Singh Gill return sdbusplus::message::object_path( 28e92aba45SJagpal Singh Gill std::string(SensorValueIntf::namespace_path::value) + "/" + sensorType + 29e92aba45SJagpal Singh Gill "/" + sensorName); 30e92aba45SJagpal Singh Gill } 31e92aba45SJagpal Singh Gill 32e92aba45SJagpal Singh Gill auto BaseDevice::createSensors() -> void 33e92aba45SJagpal Singh Gill { 34e92aba45SJagpal Singh Gill for (const auto& sensorRegister : config.sensorRegisters) 35e92aba45SJagpal Singh Gill { 36e92aba45SJagpal Singh Gill SensorValueIntf::properties_t initProperties = { 37e92aba45SJagpal Singh Gill std::numeric_limits<double>::quiet_NaN(), 38e92aba45SJagpal Singh Gill std::numeric_limits<double>::quiet_NaN(), 39e92aba45SJagpal Singh Gill std::numeric_limits<double>::quiet_NaN(), sensorRegister.unit}; 40e92aba45SJagpal Singh Gill 41e92aba45SJagpal Singh Gill auto sensorPath = getObjectPath( 42e92aba45SJagpal Singh Gill sensorRegister.pathSuffix, config.name + "_" + sensorRegister.name); 43e92aba45SJagpal Singh Gill 44e92aba45SJagpal Singh Gill auto sensor = std::make_unique<SensorValueIntf>( 45e92aba45SJagpal Singh Gill ctx, sensorPath.str.c_str(), initProperties); 46e92aba45SJagpal Singh Gill 47e92aba45SJagpal Singh Gill sensor->emit_added(); 48e92aba45SJagpal Singh Gill 49e92aba45SJagpal Singh Gill sensors.emplace(sensorRegister.name, std::move(sensor)); 50e92aba45SJagpal Singh Gill } 51e92aba45SJagpal Singh Gill 52e92aba45SJagpal Singh Gill return; 53e92aba45SJagpal Singh Gill } 54e92aba45SJagpal Singh Gill 55e92aba45SJagpal Singh Gill static auto getRawIntegerFromRegister(const std::vector<uint16_t>& reg, 56e92aba45SJagpal Singh Gill bool sign) -> int64_t 57e92aba45SJagpal Singh Gill { 58e92aba45SJagpal Singh Gill if (reg.empty()) 59e92aba45SJagpal Singh Gill { 60e92aba45SJagpal Singh Gill return 0; 61e92aba45SJagpal Singh Gill } 62e92aba45SJagpal Singh Gill 63e92aba45SJagpal Singh Gill uint64_t accumulator = 0; 64e92aba45SJagpal Singh Gill for (auto val : reg) 65e92aba45SJagpal Singh Gill { 66e92aba45SJagpal Singh Gill accumulator = (accumulator << 16) | val; 67e92aba45SJagpal Singh Gill } 68e92aba45SJagpal Singh Gill 69e92aba45SJagpal Singh Gill int64_t result = 0; 70e92aba45SJagpal Singh Gill 71e92aba45SJagpal Singh Gill if (sign) 72e92aba45SJagpal Singh Gill { 73e92aba45SJagpal Singh Gill if (reg.size() == 1) 74e92aba45SJagpal Singh Gill { 75e92aba45SJagpal Singh Gill result = static_cast<int16_t>(accumulator); 76e92aba45SJagpal Singh Gill } 77e92aba45SJagpal Singh Gill else if (reg.size() == 2) 78e92aba45SJagpal Singh Gill { 79e92aba45SJagpal Singh Gill result = static_cast<int32_t>(accumulator); 80e92aba45SJagpal Singh Gill } 81e92aba45SJagpal Singh Gill else 82e92aba45SJagpal Singh Gill { 83e92aba45SJagpal Singh Gill result = static_cast<int64_t>(accumulator); 84e92aba45SJagpal Singh Gill } 85e92aba45SJagpal Singh Gill } 86e92aba45SJagpal Singh Gill else 87e92aba45SJagpal Singh Gill { 88e92aba45SJagpal Singh Gill if (reg.size() == 1) 89e92aba45SJagpal Singh Gill { 90e92aba45SJagpal Singh Gill result = static_cast<uint16_t>(accumulator); 91e92aba45SJagpal Singh Gill } 92e92aba45SJagpal Singh Gill else if (reg.size() == 2) 93e92aba45SJagpal Singh Gill { 94e92aba45SJagpal Singh Gill result = static_cast<uint32_t>(accumulator); 95e92aba45SJagpal Singh Gill } 96e92aba45SJagpal Singh Gill else 97e92aba45SJagpal Singh Gill { 98e92aba45SJagpal Singh Gill result = static_cast<int64_t>(accumulator); 99e92aba45SJagpal Singh Gill } 100e92aba45SJagpal Singh Gill } 101e92aba45SJagpal Singh Gill 102e92aba45SJagpal Singh Gill return result; 103e92aba45SJagpal Singh Gill } 104e92aba45SJagpal Singh Gill 105e92aba45SJagpal Singh Gill auto BaseDevice::readSensorRegisters() -> sdbusplus::async::task<void> 106e92aba45SJagpal Singh Gill { 107e92aba45SJagpal Singh Gill while (!ctx.stop_requested()) 108e92aba45SJagpal Singh Gill { 109e92aba45SJagpal Singh Gill for (const auto& sensorRegister : config.sensorRegisters) 110e92aba45SJagpal Singh Gill { 111e92aba45SJagpal Singh Gill auto sensor = sensors.find(sensorRegister.name); 112e92aba45SJagpal Singh Gill if (sensor == sensors.end()) 113e92aba45SJagpal Singh Gill { 114e92aba45SJagpal Singh Gill error("Sensor not found for {NAME}", "NAME", 115e92aba45SJagpal Singh Gill sensorRegister.name); 116e92aba45SJagpal Singh Gill continue; 117e92aba45SJagpal Singh Gill } 118e92aba45SJagpal Singh Gill 119e92aba45SJagpal Singh Gill if (sensorRegister.size > 4) 120e92aba45SJagpal Singh Gill { 121e92aba45SJagpal Singh Gill error("Unsupported size for register {NAME}", "NAME", 122e92aba45SJagpal Singh Gill sensorRegister.name); 123e92aba45SJagpal Singh Gill continue; 124e92aba45SJagpal Singh Gill } 125e92aba45SJagpal Singh Gill 126e92aba45SJagpal Singh Gill auto registers = std::vector<uint16_t>(sensorRegister.size); 127e92aba45SJagpal Singh Gill auto ret = co_await serialPort.readHoldingRegisters( 128e92aba45SJagpal Singh Gill config.address, sensorRegister.offset, config.baudRate, 129e92aba45SJagpal Singh Gill config.parity, registers); 130e92aba45SJagpal Singh Gill if (!ret) 131e92aba45SJagpal Singh Gill { 132e92aba45SJagpal Singh Gill error( 133e92aba45SJagpal Singh Gill "Failed to read holding registers {NAME} for {DEVICE_ADDRESS}", 134e92aba45SJagpal Singh Gill "NAME", sensorRegister.name, "DEVICE_ADDRESS", 135e92aba45SJagpal Singh Gill config.address); 136e92aba45SJagpal Singh Gill continue; 137e92aba45SJagpal Singh Gill } 138e92aba45SJagpal Singh Gill 139e92aba45SJagpal Singh Gill double regVal = static_cast<double>( 140e92aba45SJagpal Singh Gill getRawIntegerFromRegister(registers, sensorRegister.isSigned)); 141e92aba45SJagpal Singh Gill if (sensorRegister.format == config::SensorFormat::floatingPoint) 142e92aba45SJagpal Singh Gill { 143e92aba45SJagpal Singh Gill regVal = sensorRegister.shift + 144e92aba45SJagpal Singh Gill (sensorRegister.scale * 145e92aba45SJagpal Singh Gill (regVal / (1ULL << sensorRegister.precision))); 146e92aba45SJagpal Singh Gill } 147e92aba45SJagpal Singh Gill 148e92aba45SJagpal Singh Gill sensor->second->value(regVal); 149e92aba45SJagpal Singh Gill } 150e92aba45SJagpal Singh Gill 151*7184805aSJagpal Singh Gill co_await readStatusRegisters(); 152*7184805aSJagpal Singh Gill 153e92aba45SJagpal Singh Gill constexpr auto pollInterval = 3; 154e92aba45SJagpal Singh Gill co_await sdbusplus::async::sleep_for( 155e92aba45SJagpal Singh Gill ctx, std::chrono::seconds(pollInterval)); 156e92aba45SJagpal Singh Gill debug("Polling sensors for {NAME} in {INTERVAL} seconds", "NAME", 157e92aba45SJagpal Singh Gill config.name, "INTERVAL", pollInterval); 158e92aba45SJagpal Singh Gill } 159e92aba45SJagpal Singh Gill 160e92aba45SJagpal Singh Gill co_return; 161e92aba45SJagpal Singh Gill } 162e92aba45SJagpal Singh Gill 163*7184805aSJagpal Singh Gill static auto getObjectPath(const config::Config& config, config::StatusType type, 164*7184805aSJagpal Singh Gill const std::string& name) 165*7184805aSJagpal Singh Gill -> sdbusplus::message::object_path 166*7184805aSJagpal Singh Gill { 167*7184805aSJagpal Singh Gill switch (type) 168*7184805aSJagpal Singh Gill { 169*7184805aSJagpal Singh Gill case config::StatusType::sensorReadingCritical: 170*7184805aSJagpal Singh Gill case config::StatusType::sensorReadingWarning: 171*7184805aSJagpal Singh Gill case config::StatusType::sensorFailure: 172*7184805aSJagpal Singh Gill return sdbusplus::message::object_path( 173*7184805aSJagpal Singh Gill std::string(SensorValueIntf::namespace_path::value) + "/" + 174*7184805aSJagpal Singh Gill name); 175*7184805aSJagpal Singh Gill case config::StatusType::controllerFailure: 176*7184805aSJagpal Singh Gill return config.inventoryPath; 177*7184805aSJagpal Singh Gill case config::StatusType::pumpFailure: 178*7184805aSJagpal Singh Gill return sdbusplus::message::object_path( 179*7184805aSJagpal Singh Gill "/xyz/openbmc_project/state/pump/" + name); 180*7184805aSJagpal Singh Gill case config::StatusType::filterFailure: 181*7184805aSJagpal Singh Gill return sdbusplus::message::object_path( 182*7184805aSJagpal Singh Gill "/xyz/openbmc_project/state/filter/" + name); 183*7184805aSJagpal Singh Gill case config::StatusType::powerFault: 184*7184805aSJagpal Singh Gill return sdbusplus::message::object_path( 185*7184805aSJagpal Singh Gill "/xyz/openbmc_project/state/power_rail/" + name); 186*7184805aSJagpal Singh Gill case config::StatusType::fanFailure: 187*7184805aSJagpal Singh Gill return sdbusplus::message::object_path( 188*7184805aSJagpal Singh Gill "/xyz/openbmc_project/state/fan/" + name); 189*7184805aSJagpal Singh Gill case config::StatusType::leakDetectedCritical: 190*7184805aSJagpal Singh Gill case config::StatusType::leakDetectedWarning: 191*7184805aSJagpal Singh Gill using DetectorIntf = 192*7184805aSJagpal Singh Gill sdbusplus::aserver::xyz::openbmc_project::state::leak::Detector< 193*7184805aSJagpal Singh Gill Device>; 194*7184805aSJagpal Singh Gill return sdbusplus::message::object_path( 195*7184805aSJagpal Singh Gill std::string(DetectorIntf::namespace_path::value) + "/" + 196*7184805aSJagpal Singh Gill DetectorIntf::namespace_path::detector + "/" + name); 197*7184805aSJagpal Singh Gill case config::StatusType::unknown: 198*7184805aSJagpal Singh Gill error("Unknown status type for {NAME}", "NAME", name); 199*7184805aSJagpal Singh Gill } 200*7184805aSJagpal Singh Gill 201*7184805aSJagpal Singh Gill return sdbusplus::message::object_path(); 202*7184805aSJagpal Singh Gill } 203*7184805aSJagpal Singh Gill 204*7184805aSJagpal Singh Gill auto BaseDevice::readStatusRegisters() -> sdbusplus::async::task<void> 205*7184805aSJagpal Singh Gill { 206*7184805aSJagpal Singh Gill for (const auto& [address, statusBits] : config.statusRegisters) 207*7184805aSJagpal Singh Gill { 208*7184805aSJagpal Singh Gill static constexpr auto maxRegisterSize = 1; 209*7184805aSJagpal Singh Gill auto registers = std::vector<uint16_t>(maxRegisterSize); 210*7184805aSJagpal Singh Gill 211*7184805aSJagpal Singh Gill auto ret = co_await serialPort.readHoldingRegisters( 212*7184805aSJagpal Singh Gill config.address, address, config.baudRate, config.parity, registers); 213*7184805aSJagpal Singh Gill if (!ret) 214*7184805aSJagpal Singh Gill { 215*7184805aSJagpal Singh Gill error("Failed to read holding registers for {DEVICE_ADDRESS}", 216*7184805aSJagpal Singh Gill "DEVICE_ADDRESS", config.address); 217*7184805aSJagpal Singh Gill continue; 218*7184805aSJagpal Singh Gill } 219*7184805aSJagpal Singh Gill 220*7184805aSJagpal Singh Gill for (const auto& statusBit : statusBits) 221*7184805aSJagpal Singh Gill { 222*7184805aSJagpal Singh Gill static constexpr auto maxBitPoistion = 15; 223*7184805aSJagpal Singh Gill if (statusBit.bitPosition > maxBitPoistion) 224*7184805aSJagpal Singh Gill { 225*7184805aSJagpal Singh Gill error("Invalid status bit position {POSITION} for {NAME}", 226*7184805aSJagpal Singh Gill "POSITION", statusBit.bitPosition, "NAME", 227*7184805aSJagpal Singh Gill statusBit.name); 228*7184805aSJagpal Singh Gill continue; 229*7184805aSJagpal Singh Gill } 230*7184805aSJagpal Singh Gill auto statusBitValue = 231*7184805aSJagpal Singh Gill ((registers[0] & (1 << statusBit.bitPosition)) != 0); 232*7184805aSJagpal Singh Gill auto statusAsserted = (statusBitValue == statusBit.value); 233*7184805aSJagpal Singh Gill auto objectPath = 234*7184805aSJagpal Singh Gill getObjectPath(config, statusBit.type, statusBit.name); 235*7184805aSJagpal Singh Gill double sensorValue = std::numeric_limits<double>::quiet_NaN(); 236*7184805aSJagpal Singh Gill SensorValueIntf::Unit sensorUnit = SensorValueIntf::Unit::Percent; 237*7184805aSJagpal Singh Gill auto sensorIter = sensors.find(statusBit.name); 238*7184805aSJagpal Singh Gill if (sensorIter != sensors.end()) 239*7184805aSJagpal Singh Gill { 240*7184805aSJagpal Singh Gill sensorValue = sensorIter->second->value(); 241*7184805aSJagpal Singh Gill sensorUnit = sensorIter->second->unit(); 242*7184805aSJagpal Singh Gill } 243*7184805aSJagpal Singh Gill 244*7184805aSJagpal Singh Gill co_await generateEvent(statusBit, objectPath, sensorValue, 245*7184805aSJagpal Singh Gill sensorUnit, statusAsserted); 246*7184805aSJagpal Singh Gill } 247*7184805aSJagpal Singh Gill } 248*7184805aSJagpal Singh Gill 249*7184805aSJagpal Singh Gill co_return; 250*7184805aSJagpal Singh Gill } 251*7184805aSJagpal Singh Gill 252*7184805aSJagpal Singh Gill auto BaseDevice::generateEvent( 253*7184805aSJagpal Singh Gill const config::StatusBit& statusBit, 254*7184805aSJagpal Singh Gill const sdbusplus::message::object_path& objectPath, double sensorValue, 255*7184805aSJagpal Singh Gill SensorValueIntf::Unit sensorUnit, bool statusAsserted) 256*7184805aSJagpal Singh Gill -> sdbusplus::async::task<void> 257*7184805aSJagpal Singh Gill { 258*7184805aSJagpal Singh Gill switch (statusBit.type) 259*7184805aSJagpal Singh Gill { 260*7184805aSJagpal Singh Gill case config::StatusType::sensorReadingCritical: 261*7184805aSJagpal Singh Gill co_await events.generateSensorReadingEvent( 262*7184805aSJagpal Singh Gill objectPath, EventIntf::EventLevel::critical, sensorValue, 263*7184805aSJagpal Singh Gill sensorUnit, statusAsserted); 264*7184805aSJagpal Singh Gill break; 265*7184805aSJagpal Singh Gill case config::StatusType::sensorReadingWarning: 266*7184805aSJagpal Singh Gill co_await events.generateSensorReadingEvent( 267*7184805aSJagpal Singh Gill objectPath, EventIntf::EventLevel::warning, sensorValue, 268*7184805aSJagpal Singh Gill sensorUnit, statusAsserted); 269*7184805aSJagpal Singh Gill break; 270*7184805aSJagpal Singh Gill case config::StatusType::sensorFailure: 271*7184805aSJagpal Singh Gill co_await events.generateSensorFailureEvent(objectPath, 272*7184805aSJagpal Singh Gill statusAsserted); 273*7184805aSJagpal Singh Gill break; 274*7184805aSJagpal Singh Gill case config::StatusType::controllerFailure: 275*7184805aSJagpal Singh Gill co_await events.generateControllerFailureEvent( 276*7184805aSJagpal Singh Gill objectPath, statusBit.name, statusAsserted); 277*7184805aSJagpal Singh Gill break; 278*7184805aSJagpal Singh Gill case config::StatusType::powerFault: 279*7184805aSJagpal Singh Gill co_await events.generatePowerFaultEvent(objectPath, statusBit.name, 280*7184805aSJagpal Singh Gill statusAsserted); 281*7184805aSJagpal Singh Gill break; 282*7184805aSJagpal Singh Gill case config::StatusType::filterFailure: 283*7184805aSJagpal Singh Gill co_await events.generateFilterFailureEvent(objectPath, 284*7184805aSJagpal Singh Gill statusAsserted); 285*7184805aSJagpal Singh Gill break; 286*7184805aSJagpal Singh Gill case config::StatusType::pumpFailure: 287*7184805aSJagpal Singh Gill co_await events.generatePumpFailureEvent(objectPath, 288*7184805aSJagpal Singh Gill statusAsserted); 289*7184805aSJagpal Singh Gill break; 290*7184805aSJagpal Singh Gill case config::StatusType::fanFailure: 291*7184805aSJagpal Singh Gill co_await events.generateFanFailureEvent(objectPath, statusAsserted); 292*7184805aSJagpal Singh Gill break; 293*7184805aSJagpal Singh Gill case config::StatusType::leakDetectedCritical: 294*7184805aSJagpal Singh Gill co_await events.generateLeakDetectedEvent( 295*7184805aSJagpal Singh Gill objectPath, EventIntf::EventLevel::critical, statusAsserted); 296*7184805aSJagpal Singh Gill break; 297*7184805aSJagpal Singh Gill case config::StatusType::leakDetectedWarning: 298*7184805aSJagpal Singh Gill co_await events.generateLeakDetectedEvent( 299*7184805aSJagpal Singh Gill objectPath, EventIntf::EventLevel::warning, statusAsserted); 300*7184805aSJagpal Singh Gill break; 301*7184805aSJagpal Singh Gill case config::StatusType::unknown: 302*7184805aSJagpal Singh Gill error("Unknown status type for {NAME}", "NAME", statusBit.name); 303*7184805aSJagpal Singh Gill break; 304*7184805aSJagpal Singh Gill } 305*7184805aSJagpal Singh Gill } 306*7184805aSJagpal Singh Gill 307e92aba45SJagpal Singh Gill } // namespace phosphor::modbus::rtu::device 308