xref: /openbmc/phosphor-modbus/rtu/device/base_device.cpp (revision 7184805ae4ede906935133e3e0f8ee2468bc781b)
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