blob: 73d1ca605c4a859e22bc61c1da07e49388b77d8c [file] [log] [blame]
Jagpal Singh Gille92aba42025-10-16 00:00:13 -07001#include "base_device.hpp"
2
3#include <phosphor-logging/lg2.hpp>
4
5#include <numeric>
6
7namespace phosphor::modbus::rtu::device
8{
9
10PHOSPHOR_LOG2_USING;
11
12BaseDevice::BaseDevice(sdbusplus::async::context& ctx,
13 const config::Config& config, PortIntf& serialPort) :
14 ctx(ctx), config(config), serialPort(serialPort)
15{
16 createSensors();
17
18 info("Successfully created device {NAME}", "NAME", config.name);
19}
20
21static auto getObjectPath(const std::string& sensorType,
22 const std::string& sensorName)
23 -> sdbusplus::message::object_path
24{
25 return sdbusplus::message::object_path(
26 std::string(SensorValueIntf::namespace_path::value) + "/" + sensorType +
27 "/" + sensorName);
28}
29
30auto BaseDevice::createSensors() -> void
31{
32 for (const auto& sensorRegister : config.sensorRegisters)
33 {
34 SensorValueIntf::properties_t initProperties = {
35 std::numeric_limits<double>::quiet_NaN(),
36 std::numeric_limits<double>::quiet_NaN(),
37 std::numeric_limits<double>::quiet_NaN(), sensorRegister.unit};
38
39 auto sensorPath = getObjectPath(
40 sensorRegister.pathSuffix, config.name + "_" + sensorRegister.name);
41
42 auto sensor = std::make_unique<SensorValueIntf>(
43 ctx, sensorPath.str.c_str(), initProperties);
44
45 sensor->emit_added();
46
47 sensors.emplace(sensorRegister.name, std::move(sensor));
48 }
49
50 return;
51}
52
53static auto getRawIntegerFromRegister(const std::vector<uint16_t>& reg,
54 bool sign) -> int64_t
55{
56 if (reg.empty())
57 {
58 return 0;
59 }
60
61 uint64_t accumulator = 0;
62 for (auto val : reg)
63 {
64 accumulator = (accumulator << 16) | val;
65 }
66
67 int64_t result = 0;
68
69 if (sign)
70 {
71 if (reg.size() == 1)
72 {
73 result = static_cast<int16_t>(accumulator);
74 }
75 else if (reg.size() == 2)
76 {
77 result = static_cast<int32_t>(accumulator);
78 }
79 else
80 {
81 result = static_cast<int64_t>(accumulator);
82 }
83 }
84 else
85 {
86 if (reg.size() == 1)
87 {
88 result = static_cast<uint16_t>(accumulator);
89 }
90 else if (reg.size() == 2)
91 {
92 result = static_cast<uint32_t>(accumulator);
93 }
94 else
95 {
96 result = static_cast<int64_t>(accumulator);
97 }
98 }
99
100 return result;
101}
102
103auto BaseDevice::readSensorRegisters() -> sdbusplus::async::task<void>
104{
105 while (!ctx.stop_requested())
106 {
107 for (const auto& sensorRegister : config.sensorRegisters)
108 {
109 auto sensor = sensors.find(sensorRegister.name);
110 if (sensor == sensors.end())
111 {
112 error("Sensor not found for {NAME}", "NAME",
113 sensorRegister.name);
114 continue;
115 }
116
117 if (sensorRegister.size > 4)
118 {
119 error("Unsupported size for register {NAME}", "NAME",
120 sensorRegister.name);
121 continue;
122 }
123
124 auto registers = std::vector<uint16_t>(sensorRegister.size);
125 auto ret = co_await serialPort.readHoldingRegisters(
126 config.address, sensorRegister.offset, config.baudRate,
127 config.parity, registers);
128 if (!ret)
129 {
130 error(
131 "Failed to read holding registers {NAME} for {DEVICE_ADDRESS}",
132 "NAME", sensorRegister.name, "DEVICE_ADDRESS",
133 config.address);
134 continue;
135 }
136
137 double regVal = static_cast<double>(
138 getRawIntegerFromRegister(registers, sensorRegister.isSigned));
139 if (sensorRegister.format == config::SensorFormat::floatingPoint)
140 {
141 regVal = sensorRegister.shift +
142 (sensorRegister.scale *
143 (regVal / (1ULL << sensorRegister.precision)));
144 }
145
146 sensor->second->value(regVal);
147 }
148
149 constexpr auto pollInterval = 3;
150 co_await sdbusplus::async::sleep_for(
151 ctx, std::chrono::seconds(pollInterval));
152 debug("Polling sensors for {NAME} in {INTERVAL} seconds", "NAME",
153 config.name, "INTERVAL", pollInterval);
154 }
155
156 co_return;
157}
158
159} // namespace phosphor::modbus::rtu::device