Dawn Framework 1.0
Universal data acquisition framework for embedded systems
tcp.cxx
1// dawn/src/proto/modbus/tcp.cxx
2//
3// SPDX-License-Identifier: Apache-2.0
4//
5
6#include "dawn/proto/modbus/tcp.hxx"
7
8#include "dawn/io/common.hxx"
9
10using namespace dawn;
11
12int CProtoModbusTcp::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 TCP config 0x%08" PRIx32 "\n", item->cfgid.v);
24 return -EINVAL;
25 }
26
27 switch (item->cfgid.s.id)
28 {
29 case PROTO_MODBUS_TCP_CFG_IOBIND:
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 j += sizeof(SProtoModbusIOBind) / 4 + tmp->size;
37 }
38
39 break;
40 }
41
42 case PROTO_MODBUS_TCP_CFG_PORT:
43 {
44 port = static_cast<uint16_t>(item->data[0]);
45 break;
46 }
47
48 default:
49 {
50 DAWNERR("Unsupported Modbus TCP config 0x%08" PRIx32 "\n", item->cfgid.v);
51 return -EINVAL;
52 }
53 }
54 }
55
56 return OK;
57}
58
59void CProtoModbusTcp::allocObject(SProtoModbusIOBind *alloc)
60{
61 for (size_t i = 0; i < alloc->size; i++)
62 {
63 DAWNINFO("allocate object 0x%" PRIx32 "\n", alloc->objid[i]);
64
65 setObjectMapItem(alloc->objid[i], nullptr);
66 }
67
68 valloc_push_back(alloc);
69};
70
71void CProtoModbusTcp::thread()
72{
73 DAWNINFO("start modbus tcp thread\n");
74
75 do
76 {
77 int ret;
78
79 ret = nxmb_poll(mbhandle);
80 if (ret < 0 && ret != -ETIMEDOUT && ret != -EAGAIN && ret != -ECONNRESET)
81 {
82 DAWNERR("nxmb_poll error: %d\n", ret);
83 break;
84 }
85 }
86 while (!workerThread().shouldQuit());
87
88 workerThread().markThreadFinished();
89}
90
91int CProtoModbusTcp::modbusInitialize()
92{
93 struct nxmb_config_s config;
94 int ret;
95
96 memset(&config, 0, sizeof(config));
97 config.unit_id = saddr;
98 config.is_client = false;
99 config.mode = NXMB_MODE_TCP;
100 config.transport.tcp.port = port;
101 config.transport.tcp.host = NULL;
102 config.transport.tcp.bindaddr = NULL;
103
104 ret = nxmb_create(&mbhandle, &config);
105 if (ret < 0)
106 {
107 DAWNERR("ERROR: nxmb_create failed: %d\n", ret);
108 return ret;
109 }
110
111 memset(&callbacks, 0, sizeof(callbacks));
112#ifdef CONFIG_DAWN_PROTO_MODBUS_COIL
113 callbacks.coil_cb = [](FAR uint8_t *buf,
114 uint16_t addr,
115 uint16_t ncoils,
116 enum nxmb_regmode_e mode,
117 FAR void *priv) -> int
118 { return static_cast<CProtoModbusRegs *>(priv)->coilsCb(buf, addr, ncoils, mode, priv); };
119#endif
120#ifdef CONFIG_DAWN_PROTO_MODBUS_DISCRETE
121 callbacks.discrete_cb =
122 [](FAR uint8_t *buf, uint16_t addr, uint16_t ndiscrete, FAR void *priv) -> int
123 { return static_cast<CProtoModbusRegs *>(priv)->discreteCb(buf, addr, ndiscrete, priv); };
124#endif
125#ifdef CONFIG_DAWN_PROTO_MODBUS_INPUT
126 callbacks.input_cb = [](FAR uint8_t *buf, uint16_t addr, uint16_t nregs, FAR void *priv) -> int
127 { return static_cast<CProtoModbusRegs *>(priv)->inputCb(buf, addr, nregs, priv); };
128#endif
129#ifdef CONFIG_DAWN_PROTO_MODBUS_HOLDING
130 callbacks.holding_cb = [](FAR uint8_t *buf,
131 uint16_t addr,
132 uint16_t nregs,
133 enum nxmb_regmode_e mode,
134 FAR void *priv) -> int
135 { return static_cast<CProtoModbusRegs *>(priv)->holdingCb(buf, addr, nregs, mode, priv); };
136#endif
137 callbacks.priv = static_cast<CProtoModbusRegs *>(this);
138
139 ret = nxmb_set_callbacks(mbhandle, &callbacks);
140 if (ret < 0)
141 {
142 DAWNERR("ERROR: nxmb_set_callbacks failed: %d\n", ret);
143 nxmb_destroy(mbhandle);
144 return ret;
145 }
146
147 ret = nxmb_enable(mbhandle);
148 if (ret < 0)
149 {
150 DAWNERR("ERROR: nxmb_enable failed: %d\n", ret);
151 nxmb_destroy(mbhandle);
152 mbhandle = NULL;
153 return ret;
154 }
155
156 return OK;
157}
158
159CProtoModbusTcp::~CProtoModbusTcp()
160{
161 deinit();
162}
163
165{
166 int ret;
167
168 ret = configureDesc(getDesc());
169 if (ret != OK)
170 {
171 DAWNERR("Modbus TCP configure failed (error %d)\n", ret);
172 return ret;
173 }
174
175 return OK;
176}
177
179{
180 int ret;
181
182 ret = modbusInitialize();
183 if (ret < 0)
184 {
185 return ret;
186 }
187
188 ret = createRegs();
189 if (ret < 0)
190 {
191 DAWNERR("failed to create registers %d\n", ret);
192 if (mbhandle != NULL)
193 {
194 nxmb_disable(mbhandle);
195 nxmb_destroy(mbhandle);
196 mbhandle = NULL;
197 }
198 return ret;
199 }
200
201 return OK;
202}
203
205{
206 destroyRegs();
207
208 if (mbhandle != NULL)
209 {
210 nxmb_disable(mbhandle);
211 nxmb_destroy(mbhandle);
212 mbhandle = NULL;
213 }
214
215 return OK;
216}
217
219{
220 int ret;
221
222 ret = startWorkerThread([this]() { thread(); });
223 if (ret < 0)
224 {
225 DAWNERR("failed to start thread %d\n", ret);
226 return ret;
227 }
228
229 return OK;
230};
231
233{
235
236 return OK;
237};
238
240{
241 return workerThreadRunning();
242}
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_TCP
Modbus TCP (network implementation).
Definition common.hxx:71
Modbus register management base class (shared RTU/TCP logic).
Definition regs.hxx:30
int init()
One-time initialize object after bindings are resolved.
Definition tcp.cxx:178
int doStart()
Start implementation hook.
Definition tcp.cxx:218
int doStop()
Stop implementation hook.
Definition tcp.cxx:232
bool hasThread() const
Check if a background thread is active.
Definition tcp.cxx:239
int configure()
Configure object from descriptor data.
Definition tcp.cxx:164
int deinit()
De-initialize object.
Definition tcp.cxx:204
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.