1e92aba45SJagpal Singh Gill #include "base_device.hpp"
2e92aba45SJagpal Singh Gill
3e92aba45SJagpal Singh Gill #include <phosphor-logging/lg2.hpp>
47184805aSJagpal 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
BaseDevice(sdbusplus::async::context & ctx,const config::Config & config,PortIntf & serialPort,EventIntf::Events & events)13e92aba45SJagpal Singh Gill BaseDevice::BaseDevice(sdbusplus::async::context& ctx,
147184805aSJagpal Singh Gill const config::Config& config, PortIntf& serialPort,
157184805aSJagpal Singh Gill EventIntf::Events& events) :
167184805aSJagpal Singh Gill ctx(ctx), config(config), serialPort(serialPort), events(events)
17e92aba45SJagpal Singh Gill {
18e92aba45SJagpal Singh Gill createSensors();
19e92aba45SJagpal Singh Gill
20*cf77ef54SJagpal Singh Gill if (!config.firmwareRegisters.empty())
21*cf77ef54SJagpal Singh Gill {
22*cf77ef54SJagpal Singh Gill currentFirmware =
23*cf77ef54SJagpal Singh Gill std::make_unique<DeviceFirmware>(ctx, config, serialPort);
24*cf77ef54SJagpal Singh Gill ctx.spawn(currentFirmware->readVersionRegister());
25*cf77ef54SJagpal Singh Gill }
26*cf77ef54SJagpal Singh Gill
27e92aba45SJagpal Singh Gill info("Successfully created device {NAME}", "NAME", config.name);
28e92aba45SJagpal Singh Gill }
29e92aba45SJagpal Singh Gill
getObjectPath(const std::string & sensorType,const std::string & sensorName)30e92aba45SJagpal Singh Gill static auto getObjectPath(const std::string& sensorType,
31e92aba45SJagpal Singh Gill const std::string& sensorName)
32e92aba45SJagpal Singh Gill -> sdbusplus::message::object_path
33e92aba45SJagpal Singh Gill {
34e92aba45SJagpal Singh Gill return sdbusplus::message::object_path(
35e92aba45SJagpal Singh Gill std::string(SensorValueIntf::namespace_path::value) + "/" + sensorType +
36e92aba45SJagpal Singh Gill "/" + sensorName);
37e92aba45SJagpal Singh Gill }
38e92aba45SJagpal Singh Gill
createSensors()39e92aba45SJagpal Singh Gill auto BaseDevice::createSensors() -> void
40e92aba45SJagpal Singh Gill {
41e92aba45SJagpal Singh Gill for (const auto& sensorRegister : config.sensorRegisters)
42e92aba45SJagpal Singh Gill {
43e92aba45SJagpal Singh Gill SensorValueIntf::properties_t initProperties = {
44e92aba45SJagpal Singh Gill std::numeric_limits<double>::quiet_NaN(),
45e92aba45SJagpal Singh Gill std::numeric_limits<double>::quiet_NaN(),
46e92aba45SJagpal Singh Gill std::numeric_limits<double>::quiet_NaN(), sensorRegister.unit};
47e92aba45SJagpal Singh Gill
48e92aba45SJagpal Singh Gill auto sensorPath = getObjectPath(
49e92aba45SJagpal Singh Gill sensorRegister.pathSuffix, config.name + "_" + sensorRegister.name);
50e92aba45SJagpal Singh Gill
51e92aba45SJagpal Singh Gill auto sensor = std::make_unique<SensorValueIntf>(
52e92aba45SJagpal Singh Gill ctx, sensorPath.str.c_str(), initProperties);
53e92aba45SJagpal Singh Gill
54e92aba45SJagpal Singh Gill sensor->emit_added();
55e92aba45SJagpal Singh Gill
56e92aba45SJagpal Singh Gill sensors.emplace(sensorRegister.name, std::move(sensor));
57e92aba45SJagpal Singh Gill }
58e92aba45SJagpal Singh Gill
59e92aba45SJagpal Singh Gill return;
60e92aba45SJagpal Singh Gill }
61e92aba45SJagpal Singh Gill
getRawIntegerFromRegister(const std::vector<uint16_t> & reg,bool sign)62e92aba45SJagpal Singh Gill static auto getRawIntegerFromRegister(const std::vector<uint16_t>& reg,
63e92aba45SJagpal Singh Gill bool sign) -> int64_t
64e92aba45SJagpal Singh Gill {
65e92aba45SJagpal Singh Gill if (reg.empty())
66e92aba45SJagpal Singh Gill {
67e92aba45SJagpal Singh Gill return 0;
68e92aba45SJagpal Singh Gill }
69e92aba45SJagpal Singh Gill
70e92aba45SJagpal Singh Gill uint64_t accumulator = 0;
71e92aba45SJagpal Singh Gill for (auto val : reg)
72e92aba45SJagpal Singh Gill {
73e92aba45SJagpal Singh Gill accumulator = (accumulator << 16) | val;
74e92aba45SJagpal Singh Gill }
75e92aba45SJagpal Singh Gill
76e92aba45SJagpal Singh Gill int64_t result = 0;
77e92aba45SJagpal Singh Gill
78e92aba45SJagpal Singh Gill if (sign)
79e92aba45SJagpal Singh Gill {
80e92aba45SJagpal Singh Gill if (reg.size() == 1)
81e92aba45SJagpal Singh Gill {
82e92aba45SJagpal Singh Gill result = static_cast<int16_t>(accumulator);
83e92aba45SJagpal Singh Gill }
84e92aba45SJagpal Singh Gill else if (reg.size() == 2)
85e92aba45SJagpal Singh Gill {
86e92aba45SJagpal Singh Gill result = static_cast<int32_t>(accumulator);
87e92aba45SJagpal Singh Gill }
88e92aba45SJagpal Singh Gill else
89e92aba45SJagpal Singh Gill {
90e92aba45SJagpal Singh Gill result = static_cast<int64_t>(accumulator);
91e92aba45SJagpal Singh Gill }
92e92aba45SJagpal Singh Gill }
93e92aba45SJagpal Singh Gill else
94e92aba45SJagpal Singh Gill {
95e92aba45SJagpal Singh Gill if (reg.size() == 1)
96e92aba45SJagpal Singh Gill {
97e92aba45SJagpal Singh Gill result = static_cast<uint16_t>(accumulator);
98e92aba45SJagpal Singh Gill }
99e92aba45SJagpal Singh Gill else if (reg.size() == 2)
100e92aba45SJagpal Singh Gill {
101e92aba45SJagpal Singh Gill result = static_cast<uint32_t>(accumulator);
102e92aba45SJagpal Singh Gill }
103e92aba45SJagpal Singh Gill else
104e92aba45SJagpal Singh Gill {
105e92aba45SJagpal Singh Gill result = static_cast<int64_t>(accumulator);
106e92aba45SJagpal Singh Gill }
107e92aba45SJagpal Singh Gill }
108e92aba45SJagpal Singh Gill
109e92aba45SJagpal Singh Gill return result;
110e92aba45SJagpal Singh Gill }
111e92aba45SJagpal Singh Gill
readSensorRegisters()112e92aba45SJagpal Singh Gill auto BaseDevice::readSensorRegisters() -> sdbusplus::async::task<void>
113e92aba45SJagpal Singh Gill {
114e92aba45SJagpal Singh Gill while (!ctx.stop_requested())
115e92aba45SJagpal Singh Gill {
116e92aba45SJagpal Singh Gill for (const auto& sensorRegister : config.sensorRegisters)
117e92aba45SJagpal Singh Gill {
118e92aba45SJagpal Singh Gill auto sensor = sensors.find(sensorRegister.name);
119e92aba45SJagpal Singh Gill if (sensor == sensors.end())
120e92aba45SJagpal Singh Gill {
121e92aba45SJagpal Singh Gill error("Sensor not found for {NAME}", "NAME",
122e92aba45SJagpal Singh Gill sensorRegister.name);
123e92aba45SJagpal Singh Gill continue;
124e92aba45SJagpal Singh Gill }
125e92aba45SJagpal Singh Gill
126e92aba45SJagpal Singh Gill if (sensorRegister.size > 4)
127e92aba45SJagpal Singh Gill {
128e92aba45SJagpal Singh Gill error("Unsupported size for register {NAME}", "NAME",
129e92aba45SJagpal Singh Gill sensorRegister.name);
130e92aba45SJagpal Singh Gill continue;
131e92aba45SJagpal Singh Gill }
132e92aba45SJagpal Singh Gill
133e92aba45SJagpal Singh Gill auto registers = std::vector<uint16_t>(sensorRegister.size);
134e92aba45SJagpal Singh Gill auto ret = co_await serialPort.readHoldingRegisters(
135e92aba45SJagpal Singh Gill config.address, sensorRegister.offset, config.baudRate,
136e92aba45SJagpal Singh Gill config.parity, registers);
137e92aba45SJagpal Singh Gill if (!ret)
138e92aba45SJagpal Singh Gill {
139e92aba45SJagpal Singh Gill error(
140e92aba45SJagpal Singh Gill "Failed to read holding registers {NAME} for {DEVICE_ADDRESS}",
141e92aba45SJagpal Singh Gill "NAME", sensorRegister.name, "DEVICE_ADDRESS",
142e92aba45SJagpal Singh Gill config.address);
143e92aba45SJagpal Singh Gill continue;
144e92aba45SJagpal Singh Gill }
145e92aba45SJagpal Singh Gill
146e92aba45SJagpal Singh Gill double regVal = static_cast<double>(
147e92aba45SJagpal Singh Gill getRawIntegerFromRegister(registers, sensorRegister.isSigned));
148e92aba45SJagpal Singh Gill if (sensorRegister.format == config::SensorFormat::floatingPoint)
149e92aba45SJagpal Singh Gill {
150e92aba45SJagpal Singh Gill regVal = sensorRegister.shift +
151e92aba45SJagpal Singh Gill (sensorRegister.scale *
152e92aba45SJagpal Singh Gill (regVal / (1ULL << sensorRegister.precision)));
153e92aba45SJagpal Singh Gill }
154e92aba45SJagpal Singh Gill
155e92aba45SJagpal Singh Gill sensor->second->value(regVal);
156e92aba45SJagpal Singh Gill }
157e92aba45SJagpal Singh Gill
1587184805aSJagpal Singh Gill co_await readStatusRegisters();
1597184805aSJagpal Singh Gill
160e92aba45SJagpal Singh Gill constexpr auto pollInterval = 3;
161e92aba45SJagpal Singh Gill co_await sdbusplus::async::sleep_for(
162e92aba45SJagpal Singh Gill ctx, std::chrono::seconds(pollInterval));
163e92aba45SJagpal Singh Gill debug("Polling sensors for {NAME} in {INTERVAL} seconds", "NAME",
164e92aba45SJagpal Singh Gill config.name, "INTERVAL", pollInterval);
165e92aba45SJagpal Singh Gill }
166e92aba45SJagpal Singh Gill
167e92aba45SJagpal Singh Gill co_return;
168e92aba45SJagpal Singh Gill }
169e92aba45SJagpal Singh Gill
getObjectPath(const config::Config & config,config::StatusType type,const std::string & name)1707184805aSJagpal Singh Gill static auto getObjectPath(const config::Config& config, config::StatusType type,
1717184805aSJagpal Singh Gill const std::string& name)
1727184805aSJagpal Singh Gill -> sdbusplus::message::object_path
1737184805aSJagpal Singh Gill {
1747184805aSJagpal Singh Gill switch (type)
1757184805aSJagpal Singh Gill {
1767184805aSJagpal Singh Gill case config::StatusType::sensorReadingCritical:
1777184805aSJagpal Singh Gill case config::StatusType::sensorReadingWarning:
1787184805aSJagpal Singh Gill case config::StatusType::sensorFailure:
1797184805aSJagpal Singh Gill return sdbusplus::message::object_path(
1807184805aSJagpal Singh Gill std::string(SensorValueIntf::namespace_path::value) + "/" +
1817184805aSJagpal Singh Gill name);
1827184805aSJagpal Singh Gill case config::StatusType::controllerFailure:
1837184805aSJagpal Singh Gill return config.inventoryPath;
1847184805aSJagpal Singh Gill case config::StatusType::pumpFailure:
1857184805aSJagpal Singh Gill return sdbusplus::message::object_path(
1867184805aSJagpal Singh Gill "/xyz/openbmc_project/state/pump/" + name);
1877184805aSJagpal Singh Gill case config::StatusType::filterFailure:
1887184805aSJagpal Singh Gill return sdbusplus::message::object_path(
1897184805aSJagpal Singh Gill "/xyz/openbmc_project/state/filter/" + name);
1907184805aSJagpal Singh Gill case config::StatusType::powerFault:
1917184805aSJagpal Singh Gill return sdbusplus::message::object_path(
1927184805aSJagpal Singh Gill "/xyz/openbmc_project/state/power_rail/" + name);
1937184805aSJagpal Singh Gill case config::StatusType::fanFailure:
1947184805aSJagpal Singh Gill return sdbusplus::message::object_path(
1957184805aSJagpal Singh Gill "/xyz/openbmc_project/state/fan/" + name);
1967184805aSJagpal Singh Gill case config::StatusType::leakDetectedCritical:
1977184805aSJagpal Singh Gill case config::StatusType::leakDetectedWarning:
1987184805aSJagpal Singh Gill using DetectorIntf =
1997184805aSJagpal Singh Gill sdbusplus::aserver::xyz::openbmc_project::state::leak::Detector<
2007184805aSJagpal Singh Gill Device>;
2017184805aSJagpal Singh Gill return sdbusplus::message::object_path(
2027184805aSJagpal Singh Gill std::string(DetectorIntf::namespace_path::value) + "/" +
2037184805aSJagpal Singh Gill DetectorIntf::namespace_path::detector + "/" + name);
2047184805aSJagpal Singh Gill case config::StatusType::unknown:
2057184805aSJagpal Singh Gill error("Unknown status type for {NAME}", "NAME", name);
2067184805aSJagpal Singh Gill }
2077184805aSJagpal Singh Gill
2087184805aSJagpal Singh Gill return sdbusplus::message::object_path();
2097184805aSJagpal Singh Gill }
2107184805aSJagpal Singh Gill
readStatusRegisters()2117184805aSJagpal Singh Gill auto BaseDevice::readStatusRegisters() -> sdbusplus::async::task<void>
2127184805aSJagpal Singh Gill {
2137184805aSJagpal Singh Gill for (const auto& [address, statusBits] : config.statusRegisters)
2147184805aSJagpal Singh Gill {
2157184805aSJagpal Singh Gill static constexpr auto maxRegisterSize = 1;
2167184805aSJagpal Singh Gill auto registers = std::vector<uint16_t>(maxRegisterSize);
2177184805aSJagpal Singh Gill
2187184805aSJagpal Singh Gill auto ret = co_await serialPort.readHoldingRegisters(
2197184805aSJagpal Singh Gill config.address, address, config.baudRate, config.parity, registers);
2207184805aSJagpal Singh Gill if (!ret)
2217184805aSJagpal Singh Gill {
2227184805aSJagpal Singh Gill error("Failed to read holding registers for {DEVICE_ADDRESS}",
2237184805aSJagpal Singh Gill "DEVICE_ADDRESS", config.address);
2247184805aSJagpal Singh Gill continue;
2257184805aSJagpal Singh Gill }
2267184805aSJagpal Singh Gill
2277184805aSJagpal Singh Gill for (const auto& statusBit : statusBits)
2287184805aSJagpal Singh Gill {
2297184805aSJagpal Singh Gill static constexpr auto maxBitPoistion = 15;
2307184805aSJagpal Singh Gill if (statusBit.bitPosition > maxBitPoistion)
2317184805aSJagpal Singh Gill {
2327184805aSJagpal Singh Gill error("Invalid status bit position {POSITION} for {NAME}",
2337184805aSJagpal Singh Gill "POSITION", statusBit.bitPosition, "NAME",
2347184805aSJagpal Singh Gill statusBit.name);
2357184805aSJagpal Singh Gill continue;
2367184805aSJagpal Singh Gill }
2377184805aSJagpal Singh Gill auto statusBitValue =
2387184805aSJagpal Singh Gill ((registers[0] & (1 << statusBit.bitPosition)) != 0);
2397184805aSJagpal Singh Gill auto statusAsserted = (statusBitValue == statusBit.value);
2407184805aSJagpal Singh Gill auto objectPath =
2417184805aSJagpal Singh Gill getObjectPath(config, statusBit.type, statusBit.name);
2427184805aSJagpal Singh Gill double sensorValue = std::numeric_limits<double>::quiet_NaN();
2437184805aSJagpal Singh Gill SensorValueIntf::Unit sensorUnit = SensorValueIntf::Unit::Percent;
2447184805aSJagpal Singh Gill auto sensorIter = sensors.find(statusBit.name);
2457184805aSJagpal Singh Gill if (sensorIter != sensors.end())
2467184805aSJagpal Singh Gill {
2477184805aSJagpal Singh Gill sensorValue = sensorIter->second->value();
2487184805aSJagpal Singh Gill sensorUnit = sensorIter->second->unit();
2497184805aSJagpal Singh Gill }
2507184805aSJagpal Singh Gill
2517184805aSJagpal Singh Gill co_await generateEvent(statusBit, objectPath, sensorValue,
2527184805aSJagpal Singh Gill sensorUnit, statusAsserted);
2537184805aSJagpal Singh Gill }
2547184805aSJagpal Singh Gill }
2557184805aSJagpal Singh Gill
2567184805aSJagpal Singh Gill co_return;
2577184805aSJagpal Singh Gill }
2587184805aSJagpal Singh Gill
generateEvent(const config::StatusBit & statusBit,const sdbusplus::message::object_path & objectPath,double sensorValue,SensorValueIntf::Unit sensorUnit,bool statusAsserted)2597184805aSJagpal Singh Gill auto BaseDevice::generateEvent(
2607184805aSJagpal Singh Gill const config::StatusBit& statusBit,
2617184805aSJagpal Singh Gill const sdbusplus::message::object_path& objectPath, double sensorValue,
2627184805aSJagpal Singh Gill SensorValueIntf::Unit sensorUnit, bool statusAsserted)
2637184805aSJagpal Singh Gill -> sdbusplus::async::task<void>
2647184805aSJagpal Singh Gill {
2657184805aSJagpal Singh Gill switch (statusBit.type)
2667184805aSJagpal Singh Gill {
2677184805aSJagpal Singh Gill case config::StatusType::sensorReadingCritical:
2687184805aSJagpal Singh Gill co_await events.generateSensorReadingEvent(
2697184805aSJagpal Singh Gill objectPath, EventIntf::EventLevel::critical, sensorValue,
2707184805aSJagpal Singh Gill sensorUnit, statusAsserted);
2717184805aSJagpal Singh Gill break;
2727184805aSJagpal Singh Gill case config::StatusType::sensorReadingWarning:
2737184805aSJagpal Singh Gill co_await events.generateSensorReadingEvent(
2747184805aSJagpal Singh Gill objectPath, EventIntf::EventLevel::warning, sensorValue,
2757184805aSJagpal Singh Gill sensorUnit, statusAsserted);
2767184805aSJagpal Singh Gill break;
2777184805aSJagpal Singh Gill case config::StatusType::sensorFailure:
2787184805aSJagpal Singh Gill co_await events.generateSensorFailureEvent(objectPath,
2797184805aSJagpal Singh Gill statusAsserted);
2807184805aSJagpal Singh Gill break;
2817184805aSJagpal Singh Gill case config::StatusType::controllerFailure:
2827184805aSJagpal Singh Gill co_await events.generateControllerFailureEvent(
2837184805aSJagpal Singh Gill objectPath, statusBit.name, statusAsserted);
2847184805aSJagpal Singh Gill break;
2857184805aSJagpal Singh Gill case config::StatusType::powerFault:
2867184805aSJagpal Singh Gill co_await events.generatePowerFaultEvent(objectPath, statusBit.name,
2877184805aSJagpal Singh Gill statusAsserted);
2887184805aSJagpal Singh Gill break;
2897184805aSJagpal Singh Gill case config::StatusType::filterFailure:
2907184805aSJagpal Singh Gill co_await events.generateFilterFailureEvent(objectPath,
2917184805aSJagpal Singh Gill statusAsserted);
2927184805aSJagpal Singh Gill break;
2937184805aSJagpal Singh Gill case config::StatusType::pumpFailure:
2947184805aSJagpal Singh Gill co_await events.generatePumpFailureEvent(objectPath,
2957184805aSJagpal Singh Gill statusAsserted);
2967184805aSJagpal Singh Gill break;
2977184805aSJagpal Singh Gill case config::StatusType::fanFailure:
2987184805aSJagpal Singh Gill co_await events.generateFanFailureEvent(objectPath, statusAsserted);
2997184805aSJagpal Singh Gill break;
3007184805aSJagpal Singh Gill case config::StatusType::leakDetectedCritical:
3017184805aSJagpal Singh Gill co_await events.generateLeakDetectedEvent(
3027184805aSJagpal Singh Gill objectPath, EventIntf::EventLevel::critical, statusAsserted);
3037184805aSJagpal Singh Gill break;
3047184805aSJagpal Singh Gill case config::StatusType::leakDetectedWarning:
3057184805aSJagpal Singh Gill co_await events.generateLeakDetectedEvent(
3067184805aSJagpal Singh Gill objectPath, EventIntf::EventLevel::warning, statusAsserted);
3077184805aSJagpal Singh Gill break;
3087184805aSJagpal Singh Gill case config::StatusType::unknown:
3097184805aSJagpal Singh Gill error("Unknown status type for {NAME}", "NAME", statusBit.name);
3107184805aSJagpal Singh Gill break;
3117184805aSJagpal Singh Gill }
3127184805aSJagpal Singh Gill }
3137184805aSJagpal Singh Gill
314e92aba45SJagpal Singh Gill } // namespace phosphor::modbus::rtu::device
315