Dawn Framework 1.0
Universal data acquisition framework for embedded systems
rtu.cxx
1// dawn/src/proto/modbus/rtu.cxx
2//
3// SPDX-License-Identifier: Apache-2.0
4//
5
6#include "dawn/proto/modbus/rtu.hxx"
7
8#include "dawn/io/common.hxx"
9
10using namespace dawn;
11
12int CProtoModbusRtu::configureDesc(const CDescObject &desc)
13{
14 SObjectCfg::SObjectCfgItem *item = nullptr;
15 size_t offset = 0;
16
17 for (size_t i = 0; i < desc.getSize(); i++)
18 {
19 item = desc.objectCfgItemNext(offset);
20
22 {
23 DAWNERR("Unsupported Modbus RTU config 0x%08" PRIx32 "\n", item->cfgid.v);
24 return -EINVAL;
25 }
26
27 switch (item->cfgid.s.id)
28 {
30 {
31 for (size_t j = 0; j < item->cfgid.s.size;)
32 {
33 SProtoModbusIOBind *tmp = reinterpret_cast<SProtoModbusIOBind *>(item->data + j);
34
35 allocObject(tmp);
36
37 j += sizeof(SProtoModbusIOBind) / 4 + tmp->size;
38 }
39
40 break;
41 }
42
44 {
45 path = reinterpret_cast<const char *>(&item->data);
46 break;
47 }
48
50 {
51 baud = static_cast<uint32_t>(item->data[0]);
52 break;
53 }
54
55 default:
56 {
57 DAWNERR("Unsupported Modbus RTU config 0x%08" PRIx32 "\n", item->cfgid.v);
58 return -EINVAL;
59 }
60 }
61 }
62
63 return OK;
64}
65
66void CProtoModbusRtu::allocObject(SProtoModbusIOBind *alloc)
67{
68 for (size_t i = 0; i < alloc->size; i++)
69 {
70 DAWNINFO("allocate object 0x%" PRIx32 "\n", alloc->objid[i]);
71
72 // Allocate object in map
73
74 setObjectMapItem(alloc->objid[i], nullptr);
75 }
76
77 // Store config for later
78
79 valloc_push_back(alloc);
80};
81
82void CProtoModbusRtu::thread()
83{
84 DAWNINFO("start modbus thread\n");
85
86 do
87 {
88 int ret;
89
90 /* Poll */
91
92 ret = nxmb_poll(mbhandle);
93 if (ret < 0 && ret != -ETIMEDOUT && ret != -EAGAIN)
94 {
95 DAWNERR("nxmb_poll error: %d\n", ret);
96 break;
97 }
98 }
99 while (!workerThread().shouldQuit());
100
101 // Mark thread quit done
102
103 workerThread().markThreadFinished();
104}
105
106int CProtoModbusRtu::modbusInitialize()
107{
108 struct nxmb_config_s config;
109 int ret;
110
111 memset(&config, 0, sizeof(config));
112 config.unit_id = saddr;
113 config.is_client = false;
114 config.mode = NXMB_MODE_RTU;
115
116 switch (parity)
117 {
118 case 0:
119 case 'N':
120 config.transport.serial.parity = NXMB_PAR_NONE;
121 break;
122 case 1:
123 case 'O':
124 config.transport.serial.parity = NXMB_PAR_ODD;
125 break;
126 case 2:
127 case 'E':
128 config.transport.serial.parity = NXMB_PAR_EVEN;
129 break;
130 default:
131 DAWNERR("ERROR: Invalid parity setting: %d\n", parity);
132 return -EINVAL;
133 }
134
135 config.transport.serial.devpath = path;
136 config.transport.serial.baudrate = baud;
137
138 ret = nxmb_create(&mbhandle, &config);
139 if (ret < 0)
140 {
141 DAWNERR("ERROR: nxmb_create failed: %d\n", ret);
142 return ret;
143 }
144
145 memset(&callbacks, 0, sizeof(callbacks));
146#ifdef CONFIG_DAWN_PROTO_MODBUS_COIL
147 callbacks.coil_cb = [](FAR uint8_t *buf,
148 uint16_t addr,
149 uint16_t ncoils,
150 enum nxmb_regmode_e mode,
151 FAR void *priv) -> int
152 { return static_cast<CProtoModbusRegs *>(priv)->coilsCb(buf, addr, ncoils, mode, priv); };
153#endif
154#ifdef CONFIG_DAWN_PROTO_MODBUS_DISCRETE
155 callbacks.discrete_cb =
156 [](FAR uint8_t *buf, uint16_t addr, uint16_t ndiscrete, FAR void *priv) -> int
157 { return static_cast<CProtoModbusRegs *>(priv)->discreteCb(buf, addr, ndiscrete, priv); };
158#endif
159#ifdef CONFIG_DAWN_PROTO_MODBUS_INPUT
160 callbacks.input_cb = [](FAR uint8_t *buf, uint16_t addr, uint16_t nregs, FAR void *priv) -> int
161 { return static_cast<CProtoModbusRegs *>(priv)->inputCb(buf, addr, nregs, priv); };
162#endif
163#ifdef CONFIG_DAWN_PROTO_MODBUS_HOLDING
164 callbacks.holding_cb = [](FAR uint8_t *buf,
165 uint16_t addr,
166 uint16_t nregs,
167 enum nxmb_regmode_e mode,
168 FAR void *priv) -> int
169 { return static_cast<CProtoModbusRegs *>(priv)->holdingCb(buf, addr, nregs, mode, priv); };
170#endif
171 callbacks.priv = static_cast<CProtoModbusRegs *>(this);
172
173 ret = nxmb_set_callbacks(mbhandle, &callbacks);
174 if (ret < 0)
175 {
176 DAWNERR("ERROR: nxmb_set_callbacks failed: %d\n", ret);
177 nxmb_destroy(mbhandle);
178 return ret;
179 }
180
181 ret = nxmb_enable(mbhandle);
182 if (ret < 0)
183 {
184 DAWNERR("ERROR: nxmb_enable failed: %d\n", ret);
185 nxmb_destroy(mbhandle);
186 mbhandle = NULL;
187 return ret;
188 }
189
190 return OK;
191}
192
193//***************************************************************************
194// Public Methods
195//***************************************************************************
196
197CProtoModbusRtu::~CProtoModbusRtu()
198{
199 deinit();
200}
201
203{
204 int ret;
205
206 // Configure object
207
208 ret = configureDesc(getDesc());
209 if (ret != OK)
210 {
211 DAWNERR("Modbus RTU configure failed (error %d)\n", ret);
212 return ret;
213 }
214
215 return OK;
216}
217
219{
220 int ret;
221
222 // NxModbus supports multi-instance, no singleton management needed
223
224 // Initialize modbus stack
225
226 ret = modbusInitialize();
227 if (ret < 0)
228 {
229 return ret;
230 }
231
232 // Create modbus registers after IO bindings are resolved
233
234 ret = createRegs();
235 if (ret < 0)
236 {
237 DAWNERR("failed to create registers %d\n", ret);
238 if (mbhandle != NULL)
239 {
240 nxmb_disable(mbhandle);
241 nxmb_destroy(mbhandle);
242 mbhandle = NULL;
243 }
244 return ret;
245 }
246
247 return OK;
248}
249
251{
252 destroyRegs();
253
254 // Release hardware resources
255
256 if (mbhandle != NULL)
257 {
258 nxmb_disable(mbhandle);
259 nxmb_destroy(mbhandle);
260 mbhandle = NULL;
261 }
262
263 return OK;
264}
265
267{
268 int ret;
269
270 // Start thread
271
272 ret = startWorkerThread([this]() { thread(); });
273 if (ret < 0)
274 {
275 DAWNERR("failed to start thread %d\n", ret);
276 return ret;
277 }
278
279 return OK;
280};
281
283{
284 /* Stop thread */
285
287
288 return OK;
289};
290
292{
293 return workerThreadRunning();
294}
void setObjectMapItem(SObjectId::ObjectId id, CObject *obj)
Set an item in the object map.
Definition bindable.cxx:23
Descriptor wrapper for individual object configuration.
size_t getSize() const
Get number of configuration items for this object.
SObjectCfg::SObjectCfgItem * objectCfgItemNext(size_t &offset) const
Get config item at current offset and advance past it.
CDescObject & getDesc()
Get descriptor object for this object.
Definition object.cxx:190
@ PROTO_CLASS_MODBUS_RTU
Modbus RTU (serial implementation).
Definition common.hxx:67
Modbus register management base class (shared RTU/TCP logic).
Definition regs.hxx:30
int configure()
Configure object from descriptor data.
Definition rtu.cxx:202
int init()
One-time initialize object after bindings are resolved.
Definition rtu.cxx:218
int doStop()
Stop implementation hook.
Definition rtu.cxx:282
int doStart()
Start implementation hook.
Definition rtu.cxx:266
int deinit()
De-initialize object.
Definition rtu.cxx:250
bool hasThread() const
Check if a background thread is active.
Definition rtu.cxx:291
@ PROTO_MODBUS_CFG_IOBIND
I/O object binding (register map).
Definition rtu.hxx:32
@ PROTO_MODBUS_CFG_PATH
Serial device path.
Definition rtu.hxx:33
@ PROTO_MODBUS_CFG_BAUD
Serial baud rate.
Definition rtu.hxx:34
bool workerThreadRunning() const
Check if the worker thread is running.
Definition thread.hxx:269
int stopWorkerThread()
Stop the worker thread.
Definition thread.hxx:258
int startWorkerThread(Func &&func)
Start the worker thread with a given function.
Definition thread.hxx:246
CThreadedObject & workerThread()
Get a reference to this thread controller.
Definition thread.hxx:280
Out-of-tree user-extension hooks for Dawn.
Definition bindable.hxx:13
Single configuration item within object.
ObjectCfgData_t data[]
Configuration data array (flexible, size from cfgid.s.size).
UObjectCfgId cfgid
Configuration ID header (type, class, id, size, rw, dtype).
ObjectCfgId v
Raw 32-bit ConfigID value (for storage, comparison).
Definition objectcfg.hxx:82
uint32_t cls
Object class (bits 21-29, max 511).
uint32_t id
Configuration identifier (bits 0-4, max 31).
Definition objectcfg.hxx:94
uint32_t size
Configuration data size in 32-bit words (bits 5-14, max 1023).
struct dawn::SObjectCfg::UObjectCfgId::@10 s
Bit-field structure for named member access.