1 #include <aos/kernel.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5
6 #include "mbmaster.h"
7 #include "py/builtin.h"
8 #include "py/obj.h"
9 #include "py/runtime.h"
10 #include "py/stackctrl.h"
11 #include "ulog/ulog.h"
12
13 #define LOG_TAG "modbus"
14
15 static mb_handler_t *mb_handler = NULL;
16
mp_modbus_init(size_t n_args,const mp_obj_t * args)17 STATIC mp_obj_t mp_modbus_init(size_t n_args, const mp_obj_t *args)
18 {
19 if (mb_handler != NULL) {
20 mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("Device busy, deinit firstly"));
21 return mp_const_none;
22 }
23
24 if (n_args == 0) {
25 mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("Args invalid"));
26 return mp_const_none;
27 }
28
29 uint8_t port = 1;
30 uint32_t baud_rate = 9600;
31 mb_parity_t parity = MB_PAR_NONE;
32 uint32_t timeout = 200;
33
34 if (n_args == 1) {
35 port = mp_obj_get_int(args[0]);
36 } else if (n_args == 2) {
37 port = mp_obj_get_int(args[0]);
38 baud_rate = mp_obj_get_int(args[1]);
39 } else if (n_args == 3) {
40 port = mp_obj_get_int(args[0]);
41 baud_rate = mp_obj_get_int(args[1]);
42 parity = mp_obj_get_int(args[2]);
43 } else if (n_args == 4) {
44 port = mp_obj_get_int(args[0]);
45 baud_rate = mp_obj_get_int(args[1]);
46 parity = mp_obj_get_int(args[2]);
47 int t = mp_obj_get_int(args[3]);
48 if (t < 0) {
49 timeout = AOS_WAIT_FOREVER;
50 } else {
51 timeout = t;
52 }
53 }
54
55 if (parity != MB_PAR_NONE && parity != MB_PAR_ODD && parity != MB_PAR_EVEN) {
56 mp_raise_OSError(EINVAL);
57 return mp_const_none;
58 }
59
60 mp_int_t status = mbmaster_rtu_init(&mb_handler, port, baud_rate, parity, timeout);
61 return MP_OBJ_NEW_SMALL_INT(-status);
62 }
63 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_modbus_init_obj, 0, 4, mp_modbus_init);
64
mp_modbus_deinit(size_t n_args,const mp_obj_t * args)65 STATIC mp_obj_t mp_modbus_deinit(size_t n_args, const mp_obj_t *args)
66 {
67 if (mb_handler == NULL) {
68 mp_raise_OSError(EBADF);
69 return mp_const_none;
70 }
71
72 mp_int_t status = mbmaster_rtu_uninit(mb_handler);
73 if (status == MB_SUCCESS) {
74 mb_handler = NULL;
75 }
76
77 return MP_OBJ_NEW_SMALL_INT(-status);
78 }
79 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR(mp_modbus_deinit_obj, 0, mp_modbus_deinit);
80
mp_writeHoldingRegister(size_t n_args,const mp_obj_t * args)81 STATIC mp_obj_t mp_writeHoldingRegister(size_t n_args, const mp_obj_t *args)
82 {
83 if (n_args != 4) {
84 mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("Should input 4 args"));
85 return mp_const_none;
86 }
87
88 uint32_t timeout;
89 uint16_t resp_addr = 0;
90 uint8_t exception_code = 0;
91 uint16_t resp_data = 0;
92 uint8_t slave_addr = mp_obj_get_int(args[0]);
93 uint16_t register_addr = mp_obj_get_int(args[1]);
94 uint16_t register_value = mp_obj_get_int(args[2]);
95 int t = mp_obj_get_int(args[3]);
96 if (t < 0) {
97 timeout = AOS_WAIT_FOREVER;
98 } else {
99 timeout = t;
100 }
101
102 mb_status_t status = mbmaster_write_single_register(mb_handler, slave_addr, register_addr, register_value,
103 &resp_addr, &resp_data, &exception_code, timeout);
104 if (status == MB_SUCCESS && register_value == resp_data) {
105 LOGD(LOG_TAG, "write single register ok");
106 } else {
107 LOGE(LOG_TAG, "write single register error");
108 }
109
110 mp_obj_t tuple[4] = {
111 MP_OBJ_NEW_SMALL_INT(-status),
112 mp_obj_new_int_from_uint(resp_addr),
113 mp_obj_new_int_from_uint(resp_data),
114 mp_obj_new_int_from_uint(exception_code),
115 };
116
117 return mp_obj_new_tuple(4, tuple);
118 }
119 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR(mp_writeHoldingRegister_obj, 4, mp_writeHoldingRegister);
120
mp_writeMultipleHoldingRegisters(size_t n_args,const mp_obj_t * args)121 STATIC mp_obj_t mp_writeMultipleHoldingRegisters(size_t n_args, const mp_obj_t *args)
122 {
123 if (n_args != 5) {
124 mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("Should input 5 args"));
125 return mp_const_none;
126 }
127
128 uint16_t resp_addr = 0;
129 uint16_t resp_quantity = 0;
130 uint16_t exception_code = 0;
131 uint8_t slave_addr = mp_obj_get_int(args[0]);
132 uint16_t start_addr = mp_obj_get_int(args[1]);
133 uint16_t reg_quantity = mp_obj_get_int(args[2]);
134
135 mp_buffer_info_t bufinfo;
136 mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_READ);
137 if (bufinfo.len < reg_quantity) {
138 mp_raise_msg(&mp_type_ValueError, MP_ERROR_TEXT("bytearray size should not smaller than "
139 "twice of reg_quantity"));
140 return mp_const_none;
141 }
142
143 uint32_t timeout;
144 int t = mp_obj_get_int(args[4]);
145 if (t < 0) {
146 timeout = AOS_WAIT_FOREVER;
147 } else {
148 timeout = t;
149 }
150
151 mb_status_t status =
152 mbmaster_write_multiple_registers(mb_handler, slave_addr, start_addr, reg_quantity, bufinfo.buf, &resp_addr,
153 &resp_quantity, &exception_code, timeout);
154 if (status != MB_SUCCESS) {
155 LOGE(LOG_TAG, "WriteMultipleHoldingRegisters error");
156 }
157
158 mp_obj_t tuple[4] = {
159 MP_OBJ_NEW_SMALL_INT(-status),
160 mp_obj_new_int_from_uint(resp_addr),
161 mp_obj_new_int_from_uint(resp_quantity),
162 mp_obj_new_int_from_uint(exception_code),
163 };
164
165 return mp_obj_new_tuple(4, tuple);
166 }
167 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR(mp_writeMultipleHoldingRegisters_obj, 5, mp_writeMultipleHoldingRegisters);
168
mp_writeCoil(size_t n_args,const mp_obj_t * args)169 STATIC mp_obj_t mp_writeCoil(size_t n_args, const mp_obj_t *args)
170 {
171 if (n_args != 4) {
172 mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("Should input 4 args"));
173 return mp_const_none;
174 }
175
176 uint16_t resp_addr = 0;
177 uint16_t resp_value = 0;
178 uint8_t exception_code = 0;
179 uint8_t slave_addr = mp_obj_get_int(args[0]);
180 uint16_t coil_addr = mp_obj_get_int(args[1]);
181 uint16_t coil_value = mp_obj_get_int(args[2]);
182 uint32_t timeout;
183 int t = mp_obj_get_int(args[3]);
184 if (t < 0) {
185 timeout = AOS_WAIT_FOREVER;
186 } else {
187 timeout = t;
188 }
189
190 mb_status_t status = mbmaster_write_single_coil(mb_handler, slave_addr, coil_addr, coil_value, &resp_addr,
191 &resp_value, &exception_code, timeout);
192 if (status != MB_SUCCESS || coil_value != resp_value) {
193 LOGE(LOG_TAG, "write single register error");
194 }
195
196 mp_obj_t tuple[4] = {
197 MP_OBJ_NEW_SMALL_INT(-status),
198 mp_obj_new_int_from_uint(resp_addr),
199 mp_obj_new_int_from_uint(resp_value),
200 mp_obj_new_int_from_uint(exception_code),
201 };
202
203 return mp_obj_new_tuple(4, tuple);
204 }
205 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR(mp_writeCoil_obj, 4, mp_writeCoil);
206
mp_writeMultipleCoils(size_t n_args,const mp_obj_t * args)207 STATIC mp_obj_t mp_writeMultipleCoils(size_t n_args, const mp_obj_t *args)
208 {
209 if (n_args != 5) {
210 mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("Should input 5 args"));
211 return mp_const_none;
212 }
213
214 uint16_t resp_addr = 0;
215 uint16_t resp_quantity = 0;
216 uint16_t exception_code = 0;
217 uint8_t slave_addr = mp_obj_get_int(args[0]);
218 uint16_t start_addr = mp_obj_get_int(args[1]);
219 uint16_t reg_quantity = mp_obj_get_int(args[2]);
220
221 mp_buffer_info_t bufinfo;
222 mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_READ);
223
224 uint32_t timeout;
225 int t = mp_obj_get_int(args[4]);
226 if (t < 0) {
227 timeout = AOS_WAIT_FOREVER;
228 } else {
229 timeout = t;
230 }
231
232 mb_status_t status = mbmaster_write_multiple_coils(mb_handler, slave_addr, start_addr, reg_quantity, bufinfo.buf,
233 &resp_addr, &resp_quantity, &exception_code, timeout);
234 if (status != MB_SUCCESS) {
235 LOGE(LOG_TAG, "writeMultipleCoils error");
236 }
237
238 mp_obj_t tuple[4] = {
239 MP_OBJ_NEW_SMALL_INT(-status),
240 mp_obj_new_int_from_uint(resp_addr),
241 mp_obj_new_int_from_uint(resp_quantity),
242 mp_obj_new_int_from_uint(exception_code),
243 };
244
245 return mp_obj_new_tuple(4, tuple);
246 }
247 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR(mp_writeMultipleCoils_obj, 5, mp_writeMultipleCoils);
248
mp_readHoldingRegisters(size_t n_args,const mp_obj_t * args)249 STATIC mp_obj_t mp_readHoldingRegisters(size_t n_args, const mp_obj_t *args)
250 {
251 if (n_args != 5) {
252 mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("Should input 5 args"));
253 return mp_const_none;
254 }
255
256 uint8_t resp_quantity = 0;
257 uint8_t slave_addr = mp_obj_get_int(args[0]);
258 uint16_t start_addr = mp_obj_get_int(args[1]);
259 uint16_t reg_quantity = mp_obj_get_int(args[2]);
260
261 mp_buffer_info_t bufinfo;
262 mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_WRITE);
263
264 uint32_t timeout;
265 int t = mp_obj_get_int(args[4]);
266 if (t < 0) {
267 timeout = AOS_WAIT_FOREVER;
268 } else {
269 timeout = t;
270 }
271
272 mb_status_t status = mbmaster_read_holding_registers(mb_handler, slave_addr, start_addr, reg_quantity, bufinfo.buf,
273 &resp_quantity, timeout);
274 if (status != MB_SUCCESS) {
275 LOGE(LOG_TAG, "readHoldingRegisters error");
276 }
277
278 mp_obj_t tuple[2] = {
279 MP_OBJ_NEW_SMALL_INT(-status),
280 mp_obj_new_int_from_uint(resp_quantity),
281 };
282
283 return mp_obj_new_tuple(2, tuple);
284 }
285 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR(mp_readHoldingRegisters_obj, 5, mp_readHoldingRegisters);
286
mp_readInputRegisters(size_t n_args,const mp_obj_t * args)287 STATIC mp_obj_t mp_readInputRegisters(size_t n_args, const mp_obj_t *args)
288 {
289 if (n_args != 5) {
290 mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("Should input 5 args"));
291 return mp_const_none;
292 }
293
294 uint16_t resp_quantity = 0;
295 uint8_t slave_addr = mp_obj_get_int(args[0]);
296 uint16_t start_addr = mp_obj_get_int(args[1]);
297 uint16_t reg_quantity = mp_obj_get_int(args[2]);
298
299 mp_buffer_info_t bufinfo;
300 mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_WRITE);
301
302 uint32_t timeout;
303 int t = mp_obj_get_int(args[4]);
304 if (t < 0) {
305 timeout = AOS_WAIT_FOREVER;
306 } else {
307 timeout = t;
308 }
309
310 mb_status_t status = mbmaster_read_input_registers(mb_handler, slave_addr, start_addr, reg_quantity, bufinfo.buf,
311 &resp_quantity, timeout);
312 if (status != MB_SUCCESS) {
313 LOGE(LOG_TAG, "readInputRegisters error");
314 }
315
316 mp_obj_t tuple[2] = {
317 MP_OBJ_NEW_SMALL_INT(-status),
318 mp_obj_new_int_from_uint(resp_quantity),
319 };
320
321 return mp_obj_new_tuple(2, tuple);
322 }
323 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR(mp_readInputRegisters_obj, 5, mp_readInputRegisters);
324
mp_readDiscreteInputs(size_t n_args,const mp_obj_t * args)325 STATIC mp_obj_t mp_readDiscreteInputs(size_t n_args, const mp_obj_t *args)
326 {
327 if (n_args != 5) {
328 mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("Should input 5 args"));
329 return mp_const_none;
330 }
331
332 uint16_t resp_quantity = 0;
333 uint8_t slave_addr = mp_obj_get_int(args[0]);
334 uint16_t start_addr = mp_obj_get_int(args[1]);
335 uint16_t reg_quantity = mp_obj_get_int(args[2]);
336
337 mp_buffer_info_t bufinfo;
338 mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_WRITE);
339
340 uint32_t timeout;
341 int t = mp_obj_get_int(args[4]);
342 if (t < 0) {
343 timeout = AOS_WAIT_FOREVER;
344 } else {
345 timeout = t;
346 }
347
348 mb_status_t status = mbmaster_read_discrete_inputs(mb_handler, slave_addr, start_addr, reg_quantity, bufinfo.buf,
349 &resp_quantity, timeout);
350 if (status != MB_SUCCESS) {
351 LOGE(LOG_TAG, "readDiscreteInputs error");
352 }
353
354 mp_obj_t tuple[2] = {
355 MP_OBJ_NEW_SMALL_INT(-status),
356 mp_obj_new_int_from_uint(resp_quantity),
357 };
358
359 return mp_obj_new_tuple(2, tuple);
360 }
361 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR(mp_readDiscreteInputs_obj, 5, mp_readDiscreteInputs);
362
mp_readCoils(size_t n_args,const mp_obj_t * args)363 STATIC mp_obj_t mp_readCoils(size_t n_args, const mp_obj_t *args)
364 {
365 if (n_args != 5) {
366 mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("Should input 5 args"));
367 return mp_const_none;
368 }
369
370 uint16_t resp_quantity = 0;
371 uint8_t slave_addr = mp_obj_get_int(args[0]);
372 uint16_t start_addr = mp_obj_get_int(args[1]);
373 uint16_t reg_quantity = mp_obj_get_int(args[2]);
374
375 mp_buffer_info_t bufinfo;
376 mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_WRITE);
377
378 uint32_t timeout;
379 int t = mp_obj_get_int(args[4]);
380 if (t < 0) {
381 timeout = AOS_WAIT_FOREVER;
382 } else {
383 timeout = t;
384 }
385
386 mb_status_t status =
387 mbmaster_read_coils(mb_handler, slave_addr, start_addr, reg_quantity, bufinfo.buf, &resp_quantity, timeout);
388 if (status != MB_SUCCESS) {
389 LOGE(LOG_TAG, "read_coils error");
390 }
391
392 mp_obj_t tuple[2] = {
393 MP_OBJ_NEW_SMALL_INT(-status),
394 mp_obj_new_int_from_uint(resp_quantity),
395 };
396
397 return mp_obj_new_tuple(2, tuple);
398 }
399 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR(mp_readCoils_obj, 5, mp_readCoils);
400
mp_slave_framerecv(size_t n_args,const mp_obj_t * args)401 STATIC mp_obj_t mp_slave_framerecv(size_t n_args, const mp_obj_t *args)
402 {
403 if (mb_handler == NULL) {
404 mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("slave not inited"));
405 return mp_const_none;
406 }
407
408 // 1. recv frame from master
409 MP_THREAD_GIL_EXIT();
410 mb_status_t status = mb_handler->frame_recv(mb_handler);
411 MP_THREAD_GIL_ENTER();
412 if (status == MB_SUCCESS) {
413 // 2. disassemble frame
414 status = mb_handler->adu_disassemble(mb_handler);
415 if (status != MB_SUCCESS) {
416 LOGE(LOG_TAG, "Failed to disassemble frame");
417 }
418 }
419
420 mp_obj_t tuple[2];
421 tuple[0] = MP_OBJ_NEW_SMALL_INT(-status);
422 tuple[1] =
423 status == MB_SUCCESS ? mp_obj_new_bytes(mb_handler->mb_frame_buff, mb_handler->mb_frame_length) : mp_const_none;
424
425 return mp_obj_new_tuple(2, tuple);
426 }
427 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR(mp_slave_framerecv_obj, 0, mp_slave_framerecv);
428
mp_slave_framesend(size_t n_args,const mp_obj_t * args)429 STATIC mp_obj_t mp_slave_framesend(size_t n_args, const mp_obj_t *args)
430 {
431 if (mb_handler == NULL) {
432 mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("slave not inited"));
433 return mp_const_none;
434 }
435
436 uint16_t slave_addr = mp_obj_get_int(args[0]);
437 mp_buffer_info_t bufinfo;
438 mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ);
439
440 uint32_t timeout;
441 int t = mp_obj_get_int(args[2]);
442 if (t < 0) {
443 timeout = AOS_WAIT_FOREVER;
444 } else {
445 timeout = t;
446 }
447
448 mb_handler->slave_addr = slave_addr;
449 mb_handler->pdu_length = bufinfo.len;
450
451 memcpy(&mb_handler->mb_frame_buff[ADU_SER_PDU_OFF], bufinfo.buf, bufinfo.len);
452
453 mb_status_t status = mb_handler->adu_assemble(mb_handler);
454
455 MP_THREAD_GIL_EXIT();
456 status = mb_handler->frame_send(mb_handler, timeout);
457 MP_THREAD_GIL_ENTER();
458 if (status != MB_SUCCESS) {
459 LOGE(LOG_TAG, "frame send failed");
460 }
461
462 mp_obj_t tuple[2] = {
463 MP_OBJ_NEW_SMALL_INT(-status),
464 mp_obj_new_int_from_uint(mb_handler->mb_frame_length),
465 };
466
467 return mp_obj_new_tuple(2, tuple);
468 }
469 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR(mp_slave_framesend_obj, 2, mp_slave_framesend);
470
471 STATIC const mp_rom_map_elem_t modbus_module_globals_table[] = {
472 { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_modbus) },
473 { MP_OBJ_NEW_QSTR(MP_QSTR_init), MP_ROM_PTR(&mp_modbus_init_obj) },
474 { MP_OBJ_NEW_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&mp_modbus_deinit_obj) },
475 { MP_OBJ_NEW_QSTR(MP_QSTR_writeHoldingRegister), MP_ROM_PTR(&mp_writeHoldingRegister_obj) },
476 { MP_OBJ_NEW_QSTR(MP_QSTR_writeMultipleHoldingRegisters), MP_ROM_PTR(&mp_writeMultipleHoldingRegisters_obj) },
477 { MP_OBJ_NEW_QSTR(MP_QSTR_writeCoil), MP_ROM_PTR(&mp_writeCoil_obj) },
478 { MP_OBJ_NEW_QSTR(MP_QSTR_writeMultipleCoils), MP_ROM_PTR(&mp_writeMultipleCoils_obj) },
479 { MP_OBJ_NEW_QSTR(MP_QSTR_readHoldingRegisters), MP_ROM_PTR(&mp_readHoldingRegisters_obj) },
480 { MP_OBJ_NEW_QSTR(MP_QSTR_readInputRegisters), MP_ROM_PTR(&mp_readInputRegisters_obj) },
481 { MP_OBJ_NEW_QSTR(MP_QSTR_readDiscreteInputs), MP_ROM_PTR(&mp_readDiscreteInputs_obj) },
482 { MP_OBJ_NEW_QSTR(MP_QSTR_readCoils), MP_ROM_PTR(&mp_readCoils_obj) },
483 { MP_OBJ_NEW_QSTR(MP_QSTR_recv), MP_ROM_PTR(&mp_slave_framerecv_obj) },
484 { MP_OBJ_NEW_QSTR(MP_QSTR_send), MP_ROM_PTR(&mp_slave_framesend_obj) },
485
486 { MP_ROM_QSTR(MP_QSTR_PARITY_NONE), MP_ROM_INT(MB_PAR_NONE) },
487 { MP_ROM_QSTR(MP_QSTR_PARITY_ODD), MP_ROM_INT(MB_PAR_ODD) },
488 { MP_ROM_QSTR(MP_QSTR_PARITY_EVEN), MP_ROM_INT(MB_PAR_EVEN) },
489 };
490
491 STATIC MP_DEFINE_CONST_DICT(modbus_module_globals, modbus_module_globals_table);
492
493 const mp_obj_module_t modbus_module = {
494 .base = { &mp_type_module },
495 .globals = (mp_obj_dict_t *)&modbus_module_globals,
496 };
497