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