1 /*
2 * Copyright (c) 2020 PHYTEC Messtechnik GmbH
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include "test_modbus.h"
8
9 #include <zephyr/logging/log.h>
10 LOG_MODULE_REGISTER(mbc_test, LOG_LEVEL_INF);
11
12 #ifdef CONFIG_MODBUS_CLIENT
13 const static uint16_t fp_offset = MB_TEST_FP_OFFSET;
14 const static uint8_t node = MB_TEST_NODE_ADDR;
15 const static uint16_t offset_oor = 32;
16 const static uint16_t fp_offset_oor = fp_offset + offset_oor;
17
18 static uint8_t client_iface;
19
test_get_client_iface(void)20 uint8_t test_get_client_iface(void)
21 {
22 return client_iface;
23 }
24
test_coil_wr_rd(void)25 void test_coil_wr_rd(void)
26 {
27 const uint8_t coil_qty = 16;
28 uint8_t coil[3] = {0};
29 int err;
30
31 for (uint16_t idx = 0; idx < coil_qty; idx++) {
32 err = modbus_write_coil(client_iface, node, idx, true);
33 zassert_equal(err, 0, "FC05 request failed");
34 }
35
36 err = modbus_read_coils(client_iface, node, 0, coil, coil_qty);
37 zassert_equal(err, 0, "FC01 request failed");
38
39 zassert_equal(coil[0], 0xff, "FC05 verify coil 0-7 failed");
40 zassert_equal(coil[1], 0xff, "FC05 verify coil 8-15 failed");
41
42 for (uint16_t numof = 1; numof <= coil_qty; numof++) {
43 err = modbus_write_coils(client_iface, node, 0, coil, numof);
44 zassert_equal(err, 0, "FC15 request failed");
45 }
46
47 coil[0] = 0xaa; coil[1] = 0xbb;
48 err = modbus_write_coils(client_iface, node, 0, coil, coil_qty);
49 zassert_equal(err, 0, "FC15 request failed");
50
51 err = modbus_read_coils(client_iface, node, 0, coil, coil_qty);
52 zassert_equal(err, 0, "FC01 request failed");
53
54 zassert_equal(coil[0], 0xaa, "FC15 verify coil 0-7 failed");
55 zassert_equal(coil[1], 0xbb, "FC15 verify coil 8-15 failed");
56
57 err = modbus_write_coil(client_iface, node, offset_oor, true);
58 zassert_not_equal(err, 0, "FC05 out of range request not failed");
59
60 err = modbus_write_coils(client_iface, node, offset_oor, coil, coil_qty);
61 zassert_not_equal(err, 0, "FC15 out of range request not failed");
62 }
63
test_di_rd(void)64 void test_di_rd(void)
65 {
66 const uint8_t di_qty = 16;
67 uint8_t di[4] = {0};
68 int err;
69
70 err = modbus_read_dinputs(client_iface, node, 0, di, di_qty);
71 zassert_equal(err, 0, "FC02 request failed");
72
73 zassert_equal(di[0], 0xaa, "FC02 verify di 0-7 failed");
74 zassert_equal(di[1], 0xbb, "FC02 verify di 8-15 failed");
75
76 err = modbus_read_dinputs(client_iface, node, 0, di, di_qty + 1);
77 zassert_not_equal(err, 0, "FC02 out of range request not failed");
78
79 err = modbus_read_dinputs(client_iface, node, offset_oor, di, di_qty);
80 zassert_not_equal(err, 0, "FC02 out of range request not failed");
81 }
82
test_input_reg(void)83 void test_input_reg(void)
84 {
85 uint16_t ir[8] = {0};
86 int err;
87
88 err = modbus_write_holding_reg(client_iface, node, 0, 0xcafe);
89 zassert_equal(err, 0, "FC06 write request for FC04 failed");
90
91 err = modbus_read_input_regs(client_iface, node, 0, ir, ARRAY_SIZE(ir));
92 zassert_equal(err, 0, "FC04 request failed");
93
94 zassert_equal(ir[0], 0xcafe, "FC04 verify failed");
95
96 err = modbus_read_input_regs(client_iface,
97 node,
98 offset_oor,
99 ir,
100 ARRAY_SIZE(ir));
101 zassert_not_equal(err, 0, "FC04 out of range request not failed");
102 }
103
test_holding_reg(void)104 void test_holding_reg(void)
105 {
106 uint16_t hr_wr[8] = {0, 2, 1, 3, 5, 4, 7, 6};
107 uint16_t hr_rd[8] = {0};
108 float fhr_wr[4] = {48.56470489501953125, 0.3, 0.2, 0.1};
109 float fhr_rd[4] = {0.0};
110 int err;
111
112 /* Test FC06 | FC03 */
113 for (uint16_t idx = 0; idx < ARRAY_SIZE(hr_wr); idx++) {
114 err = modbus_write_holding_reg(client_iface, node, idx, hr_wr[idx]);
115 zassert_equal(err, 0, "FC06 write request failed");
116 }
117
118 err = modbus_write_holding_reg(client_iface, node, offset_oor, 0xcafe);
119 zassert_not_equal(err, 0, "FC06 out of range request not failed");
120
121 err = modbus_read_holding_regs(client_iface, node, 0,
122 hr_rd, ARRAY_SIZE(hr_rd));
123 zassert_equal(err, 0, "FC03 read request failed");
124
125 LOG_HEXDUMP_DBG(hr_rd, sizeof(hr_rd), "FC06, hr_rd");
126 zassert_equal(memcmp(hr_wr, hr_rd, sizeof(hr_wr)), 0,
127 "FC06 verify failed");
128
129 err = modbus_read_holding_regs(client_iface,
130 node,
131 offset_oor,
132 hr_rd,
133 ARRAY_SIZE(hr_rd));
134 zassert_not_equal(err, 0, "FC03 out of range request not failed");
135
136 /* Test FC16 | FC03 */
137 err = modbus_write_holding_regs(client_iface, node, 0,
138 hr_wr, ARRAY_SIZE(hr_wr));
139 zassert_equal(err, 0, "FC16 write request failed");
140
141 err = modbus_read_holding_regs(client_iface, node, 0,
142 hr_rd, ARRAY_SIZE(hr_rd));
143 zassert_equal(err, 0, "FC03 read request failed");
144
145 LOG_HEXDUMP_DBG(hr_rd, sizeof(hr_rd), "FC16, hr_rd");
146 zassert_equal(memcmp(hr_wr, hr_rd, sizeof(hr_wr)), 0,
147 "FC16 verify failed");
148
149 /* Test FC16 | FC03 */
150 for (uint16_t idx = 0; idx < ARRAY_SIZE(fhr_wr); idx++) {
151 err = modbus_write_holding_regs_fp(client_iface,
152 node,
153 fp_offset + idx * 2,
154 &fhr_wr[0], 1);
155 zassert_equal(err, 0, "FC16 write request failed");
156 }
157
158 err = modbus_write_holding_regs_fp(client_iface,
159 node,
160 fp_offset,
161 fhr_wr,
162 ARRAY_SIZE(fhr_wr));
163 zassert_equal(err, 0, "FC16 FP request failed");
164
165 err = modbus_write_holding_regs_fp(client_iface,
166 node,
167 fp_offset_oor,
168 fhr_wr,
169 ARRAY_SIZE(fhr_wr));
170 zassert_not_equal(err, 0, "FC16 FP out of range request not failed");
171
172 err = modbus_read_holding_regs_fp(client_iface,
173 node,
174 fp_offset_oor,
175 fhr_wr,
176 ARRAY_SIZE(fhr_wr));
177 zassert_not_equal(err, 0, "FC16 FP out of range request not failed");
178
179 err = modbus_write_holding_regs(client_iface, node, fp_offset,
180 hr_wr, ARRAY_SIZE(hr_wr) - 1);
181 zassert_not_equal(err, 0, "FC16 write to FP address request not failed");
182
183 err = modbus_read_holding_regs(client_iface, node, fp_offset,
184 hr_rd, ARRAY_SIZE(hr_rd) - 1);
185 zassert_not_equal(err, 0, "FC16 read from FP address request not failed");
186
187 err = modbus_read_holding_regs_fp(client_iface,
188 node,
189 fp_offset,
190 fhr_rd,
191 ARRAY_SIZE(fhr_rd));
192 zassert_equal(err, 0, "FC03 read request failed");
193
194 LOG_HEXDUMP_DBG(fhr_rd, sizeof(fhr_rd), "FC16FP, fhr_rd");
195 zassert_equal(memcmp(fhr_wr, fhr_rd, sizeof(fhr_wr)), 0,
196 "FC16FP verify failed");
197 }
198
test_diagnostic(void)199 void test_diagnostic(void)
200 {
201 uint16_t data = 0xcafe;
202 int err;
203
204 for (uint16_t sf = 0x0A; sf < 0x0F; sf++) {
205 err = modbus_request_diagnostic(client_iface, node, sf, 0, &data);
206 zassert_equal(err, 0, "FC08:0x%04x request failed", sf);
207 }
208
209 err = modbus_request_diagnostic(client_iface, node, 0xFF, 0, &data);
210 zassert_not_equal(err, 0, "FC08 not supported request not failed");
211 }
212
213 static struct modbus_iface_param client_param = {
214 .mode = MODBUS_MODE_RTU,
215 .rx_timeout = MB_TEST_RESPONSE_TO,
216 .serial = {
217 .baud = MB_TEST_BAUDRATE_LOW,
218 .parity = UART_CFG_PARITY_ODD,
219 },
220 };
221
222 /*
223 * This test performed on hardware requires two UART controllers
224 * on the board (with RX/TX lines connected crosswise).
225 * The exact mapping is not required, we assume that both controllers
226 * have similar capabilities and use the instance with index 0
227 * as interface for the client.
228 */
229 #if DT_NODE_EXISTS(DT_INST(0, zephyr_modbus_serial))
230 static const char rtu_iface_name[] = {DEVICE_DT_NAME(DT_INST(0, zephyr_modbus_serial))};
231 #else
232 static const char rtu_iface_name[] = "";
233 #endif
234
test_client_setup_low_none(void)235 void test_client_setup_low_none(void)
236 {
237 int err;
238
239 client_iface = modbus_iface_get_by_name(rtu_iface_name);
240 client_param.mode = MODBUS_MODE_RTU;
241 client_param.serial.baud = MB_TEST_BAUDRATE_LOW;
242 client_param.serial.parity = UART_CFG_PARITY_NONE;
243
244 err = modbus_init_client(client_iface, client_param);
245 zassert_equal(err, 0, "Failed to configure RTU client");
246 }
247
test_client_setup_low_odd(void)248 void test_client_setup_low_odd(void)
249 {
250 int err;
251
252 client_iface = modbus_iface_get_by_name(rtu_iface_name);
253 client_param.mode = MODBUS_MODE_RTU;
254 client_param.serial.baud = MB_TEST_BAUDRATE_LOW;
255 client_param.serial.parity = UART_CFG_PARITY_ODD;
256
257 err = modbus_init_client(client_iface, client_param);
258 zassert_equal(err, 0, "Failed to configure RTU client");
259 }
260
test_client_setup_high_even(void)261 void test_client_setup_high_even(void)
262 {
263 int err;
264
265 client_iface = modbus_iface_get_by_name(rtu_iface_name);
266 client_param.mode = MODBUS_MODE_RTU;
267 client_param.serial.baud = MB_TEST_BAUDRATE_HIGH;
268 client_param.serial.parity = UART_CFG_PARITY_EVEN;
269
270 err = modbus_init_client(client_iface, client_param);
271 zassert_equal(err, 0, "Failed to configure RTU client");
272 }
273
test_client_setup_ascii(void)274 void test_client_setup_ascii(void)
275 {
276 int err;
277
278 client_iface = modbus_iface_get_by_name(rtu_iface_name);
279 client_param.mode = MODBUS_MODE_ASCII;
280 client_param.serial.baud = MB_TEST_BAUDRATE_HIGH;
281 client_param.serial.parity = UART_CFG_PARITY_EVEN;
282
283 err = modbus_init_client(client_iface, client_param);
284
285 zassert_equal(err, 0, "Failed to configure RTU client");
286 }
287
test_client_setup_raw(void)288 void test_client_setup_raw(void)
289 {
290 char iface_name[] = "RAW_0";
291 int err;
292
293 client_iface = modbus_iface_get_by_name(iface_name);
294 client_param.mode = MODBUS_MODE_RAW;
295 client_param.rawcb.raw_tx_cb = client_raw_cb;
296 client_param.rawcb.user_data = NULL;
297
298 err = modbus_init_client(client_iface, client_param);
299 zassert_equal(err, 0, "Failed to configure RAW client");
300 }
301
test_client_disable(void)302 void test_client_disable(void)
303 {
304 int err;
305
306 err = modbus_disable(client_iface);
307 zassert_equal(err, 0, "Failed to disable RTU client");
308 }
309
310 #else
311
test_client_setup_low_none(void)312 void test_client_setup_low_none(void)
313 {
314 ztest_test_skip();
315 }
316
test_client_setup_low_odd(void)317 void test_client_setup_low_odd(void)
318 {
319 ztest_test_skip();
320 }
321
test_client_setup_high_even(void)322 void test_client_setup_high_even(void)
323 {
324 ztest_test_skip();
325 }
326
test_client_setup_ascii(void)327 void test_client_setup_ascii(void)
328 {
329 ztest_test_skip();
330 }
331
test_coil_wr_rd(void)332 void test_coil_wr_rd(void)
333 {
334 ztest_test_skip();
335 }
336
test_di_rd(void)337 void test_di_rd(void)
338 {
339 ztest_test_skip();
340 }
341
test_input_reg(void)342 void test_input_reg(void)
343 {
344 ztest_test_skip();
345 }
346
test_holding_reg(void)347 void test_holding_reg(void)
348 {
349 ztest_test_skip();
350 }
351
test_diagnostic(void)352 void test_diagnostic(void)
353 {
354 ztest_test_skip();
355 }
356
test_client_disable(void)357 void test_client_disable(void)
358 {
359 ztest_test_skip();
360 }
361
test_client_setup_raw(void)362 void test_client_setup_raw(void)
363 {
364 ztest_test_skip();
365 }
366 #endif
367