1 /*
2 * Copyright (c) 2020 PHYTEC Messtechnik GmbH
3 * Copyright (c) 2021 Nordic Semiconductor ASA
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 /*
9 * This file is based on mb.c and mb_util.c from uC/Modbus Stack.
10 *
11 * uC/Modbus
12 * The Embedded Modbus Stack
13 *
14 * Copyright 2003-2020 Silicon Laboratories Inc. www.silabs.com
15 *
16 * SPDX-License-Identifier: APACHE-2.0
17 *
18 * This software is subject to an open source license and is distributed by
19 * Silicon Laboratories Inc. pursuant to the terms of the Apache License,
20 * Version 2.0 available at www.apache.org/licenses/LICENSE-2.0.
21 */
22
23 #include <zephyr/logging/log.h>
24 LOG_MODULE_REGISTER(modbus_serial, CONFIG_MODBUS_LOG_LEVEL);
25
26 #include <zephyr/kernel.h>
27 #include <string.h>
28 #include <zephyr/sys/byteorder.h>
29 #include <zephyr/sys/crc.h>
30 #include <modbus_internal.h>
31
modbus_serial_tx_on(struct modbus_context * ctx)32 static void modbus_serial_tx_on(struct modbus_context *ctx)
33 {
34 struct modbus_serial_config *cfg = ctx->cfg;
35
36 if (cfg->de != NULL) {
37 gpio_pin_set(cfg->de->port, cfg->de->pin, 1);
38 }
39
40 uart_irq_tx_enable(cfg->dev);
41 }
42
modbus_serial_tx_off(struct modbus_context * ctx)43 static void modbus_serial_tx_off(struct modbus_context *ctx)
44 {
45 struct modbus_serial_config *cfg = ctx->cfg;
46
47 uart_irq_tx_disable(cfg->dev);
48 if (cfg->de != NULL) {
49 gpio_pin_set(cfg->de->port, cfg->de->pin, 0);
50 }
51 }
52
modbus_serial_rx_on(struct modbus_context * ctx)53 static void modbus_serial_rx_on(struct modbus_context *ctx)
54 {
55 struct modbus_serial_config *cfg = ctx->cfg;
56
57 if (cfg->re != NULL) {
58 gpio_pin_set(cfg->re->port, cfg->re->pin, 1);
59 }
60
61 uart_irq_rx_enable(cfg->dev);
62 }
63
modbus_serial_rx_off(struct modbus_context * ctx)64 static void modbus_serial_rx_off(struct modbus_context *ctx)
65 {
66 struct modbus_serial_config *cfg = ctx->cfg;
67
68 uart_irq_rx_disable(cfg->dev);
69 if (cfg->re != NULL) {
70 gpio_pin_set(cfg->re->port, cfg->re->pin, 0);
71 }
72 }
73
74 #ifdef CONFIG_MODBUS_ASCII_MODE
75 /* The function calculates an 8-bit Longitudinal Redundancy Check. */
modbus_ascii_get_lrc(uint8_t * src,size_t length)76 static uint8_t modbus_ascii_get_lrc(uint8_t *src, size_t length)
77 {
78 uint8_t lrc = 0;
79 uint8_t tmp;
80 uint8_t *pblock = src;
81
82 while (length-- > 0) {
83 /* Add the data byte to LRC, increment data pointer. */
84 if (hex2bin(pblock, 2, &tmp, sizeof(tmp)) != sizeof(tmp)) {
85 return 0;
86 }
87
88 lrc += tmp;
89 pblock += 2;
90 }
91
92 /* Two complement the binary sum */
93 lrc = ~lrc + 1;
94
95 return lrc;
96 }
97
98 /* Parses and converts an ASCII mode frame into a Modbus RTU frame. */
modbus_ascii_rx_adu(struct modbus_context * ctx)99 static int modbus_ascii_rx_adu(struct modbus_context *ctx)
100 {
101 struct modbus_serial_config *cfg = ctx->cfg;
102 uint8_t *pmsg;
103 uint8_t *prx_data;
104 uint16_t rx_size;
105 uint8_t frame_lrc;
106 uint8_t calc_lrc;
107
108 rx_size = cfg->uart_buf_ctr;
109 prx_data = &ctx->rx_adu.data[0];
110
111 if (!(rx_size & 0x01)) {
112 LOG_WRN("Message should have an odd number of bytes");
113 return -EMSGSIZE;
114 }
115
116 if (rx_size < MODBUS_ASCII_MIN_MSG_SIZE) {
117 LOG_WRN("Frame length error");
118 return -EMSGSIZE;
119 }
120
121 if ((cfg->uart_buf[0] != MODBUS_ASCII_START_FRAME_CHAR) ||
122 (cfg->uart_buf[rx_size - 2] != MODBUS_ASCII_END_FRAME_CHAR1) ||
123 (cfg->uart_buf[rx_size - 1] != MODBUS_ASCII_END_FRAME_CHAR2)) {
124 LOG_WRN("Frame character error");
125 return -EMSGSIZE;
126 }
127
128 /* Take away for the ':', CR, and LF */
129 rx_size -= 3;
130 /* Point past the ':' to the address. */
131 pmsg = &cfg->uart_buf[1];
132
133 hex2bin(pmsg, 2, &ctx->rx_adu.unit_id, 1);
134 pmsg += 2;
135 rx_size -= 2;
136 hex2bin(pmsg, 2, &ctx->rx_adu.fc, 1);
137 pmsg += 2;
138 rx_size -= 2;
139
140 /* Get the data from the message */
141 ctx->rx_adu.length = 0;
142 while (rx_size > 2) {
143 hex2bin(pmsg, 2, prx_data, 1);
144 prx_data++;
145 pmsg += 2;
146 rx_size -= 2;
147 /* Increment the number of Modbus packets received */
148 ctx->rx_adu.length++;
149 }
150
151 /* Extract the message's LRC */
152 hex2bin(pmsg, 2, &frame_lrc, 1);
153 ctx->rx_adu.crc = frame_lrc;
154
155 /*
156 * The LRC is calculated on the ADDR, FC and Data fields,
157 * not the ':', CR/LF and LRC placed in the message
158 * by the sender. We thus need to subtract 5 'ASCII' characters
159 * from the received message to exclude these.
160 */
161 calc_lrc = modbus_ascii_get_lrc(&cfg->uart_buf[1],
162 (cfg->uart_buf_ctr - 5) / 2);
163
164 if (calc_lrc != frame_lrc) {
165 LOG_ERR("Calculated LRC does not match received LRC");
166 return -EIO;
167 }
168
169 return 0;
170 }
171
modbus_ascii_bin2hex(uint8_t value,uint8_t * pbuf)172 static uint8_t *modbus_ascii_bin2hex(uint8_t value, uint8_t *pbuf)
173 {
174 uint8_t u_nibble = (value >> 4) & 0x0F;
175 uint8_t l_nibble = value & 0x0F;
176
177 hex2char(u_nibble, pbuf);
178 pbuf++;
179 hex2char(l_nibble, pbuf);
180 pbuf++;
181
182 return pbuf;
183 }
184
modbus_ascii_tx_adu(struct modbus_context * ctx)185 static void modbus_ascii_tx_adu(struct modbus_context *ctx)
186 {
187 struct modbus_serial_config *cfg = ctx->cfg;
188 uint16_t tx_bytes = 0;
189 uint8_t lrc;
190 uint8_t *pbuf;
191
192 /* Place the start-of-frame character into output buffer */
193 cfg->uart_buf[0] = MODBUS_ASCII_START_FRAME_CHAR;
194 tx_bytes = 1;
195
196 pbuf = &cfg->uart_buf[1];
197 pbuf = modbus_ascii_bin2hex(ctx->tx_adu.unit_id, pbuf);
198 tx_bytes += 2;
199 pbuf = modbus_ascii_bin2hex(ctx->tx_adu.fc, pbuf);
200 tx_bytes += 2;
201
202 for (int i = 0; i < ctx->tx_adu.length; i++) {
203 pbuf = modbus_ascii_bin2hex(ctx->tx_adu.data[i], pbuf);
204 tx_bytes += 2;
205 }
206
207 /*
208 * Add the LRC checksum in the packet.
209 *
210 * The LRC is calculated on the ADDR, FC and Data fields,
211 * not the ':' which was inserted in the uart_buf[].
212 * Thus we subtract 1 ASCII character from the LRC.
213 * The LRC and CR/LF bytes are not YET in the .uart_buf[].
214 */
215 lrc = modbus_ascii_get_lrc(&cfg->uart_buf[1], (tx_bytes - 1) / 2);
216 pbuf = modbus_ascii_bin2hex(lrc, pbuf);
217 tx_bytes += 2;
218
219 *pbuf++ = MODBUS_ASCII_END_FRAME_CHAR1;
220 *pbuf++ = MODBUS_ASCII_END_FRAME_CHAR2;
221 tx_bytes += 2;
222
223 /* Update the total number of bytes to send */
224 cfg->uart_buf_ctr = tx_bytes;
225 cfg->uart_buf_ptr = &cfg->uart_buf[0];
226
227 LOG_DBG("Start frame transmission");
228 modbus_serial_rx_off(ctx);
229 modbus_serial_tx_on(ctx);
230 }
231 #else
modbus_ascii_rx_adu(struct modbus_context * ctx)232 static int modbus_ascii_rx_adu(struct modbus_context *ctx)
233 {
234 return 0;
235 }
236
modbus_ascii_tx_adu(struct modbus_context * ctx)237 static void modbus_ascii_tx_adu(struct modbus_context *ctx)
238 {
239 }
240 #endif
241
242 /* Copy Modbus RTU frame and check if the CRC is valid. */
modbus_rtu_rx_adu(struct modbus_context * ctx)243 static int modbus_rtu_rx_adu(struct modbus_context *ctx)
244 {
245 struct modbus_serial_config *cfg = ctx->cfg;
246 uint16_t calc_crc;
247 uint16_t crc_idx;
248 uint8_t *data_ptr;
249
250 /* Is the message long enough? */
251 if ((cfg->uart_buf_ctr < MODBUS_RTU_MIN_MSG_SIZE) ||
252 (cfg->uart_buf_ctr > CONFIG_MODBUS_BUFFER_SIZE)) {
253 LOG_WRN("Frame length error");
254 return -EMSGSIZE;
255 }
256
257 ctx->rx_adu.unit_id = cfg->uart_buf[0];
258 ctx->rx_adu.fc = cfg->uart_buf[1];
259 data_ptr = &cfg->uart_buf[2];
260 /* Payload length without node address, function code, and CRC */
261 ctx->rx_adu.length = cfg->uart_buf_ctr - 4;
262 /* CRC index */
263 crc_idx = cfg->uart_buf_ctr - sizeof(uint16_t);
264
265 memcpy(ctx->rx_adu.data, data_ptr, ctx->rx_adu.length);
266
267 ctx->rx_adu.crc = sys_get_le16(&cfg->uart_buf[crc_idx]);
268 /* Calculate CRC over address, function code, and payload */
269 calc_crc = crc16_ansi(&cfg->uart_buf[0],
270 cfg->uart_buf_ctr - sizeof(ctx->rx_adu.crc));
271
272 if (ctx->rx_adu.crc != calc_crc) {
273 LOG_WRN("Calculated CRC does not match received CRC");
274 return -EIO;
275 }
276
277 return 0;
278 }
279
rtu_tx_adu(struct modbus_context * ctx)280 static void rtu_tx_adu(struct modbus_context *ctx)
281 {
282 struct modbus_serial_config *cfg = ctx->cfg;
283 uint16_t tx_bytes = 0;
284 uint8_t *data_ptr;
285
286 cfg->uart_buf[0] = ctx->tx_adu.unit_id;
287 cfg->uart_buf[1] = ctx->tx_adu.fc;
288 tx_bytes = 2 + ctx->tx_adu.length;
289 data_ptr = &cfg->uart_buf[2];
290
291 memcpy(data_ptr, ctx->tx_adu.data, ctx->tx_adu.length);
292
293 ctx->tx_adu.crc = crc16_ansi(&cfg->uart_buf[0], ctx->tx_adu.length + 2);
294 sys_put_le16(ctx->tx_adu.crc,
295 &cfg->uart_buf[ctx->tx_adu.length + 2]);
296 tx_bytes += 2;
297
298 cfg->uart_buf_ctr = tx_bytes;
299 cfg->uart_buf_ptr = &cfg->uart_buf[0];
300
301 LOG_HEXDUMP_DBG(cfg->uart_buf, cfg->uart_buf_ctr, "uart_buf");
302 LOG_DBG("Start frame transmission");
303 modbus_serial_rx_off(ctx);
304 modbus_serial_tx_on(ctx);
305 }
306
307 /*
308 * A byte has been received from a serial port. We just store it in the buffer
309 * for processing when a complete packet has been received.
310 */
cb_handler_rx(struct modbus_context * ctx)311 static void cb_handler_rx(struct modbus_context *ctx)
312 {
313 struct modbus_serial_config *cfg = ctx->cfg;
314
315 if ((ctx->mode == MODBUS_MODE_ASCII) &&
316 IS_ENABLED(CONFIG_MODBUS_ASCII_MODE)) {
317 uint8_t c;
318
319 if (uart_fifo_read(cfg->dev, &c, 1) != 1) {
320 LOG_ERR("Failed to read UART");
321 return;
322 }
323
324 if (c == MODBUS_ASCII_START_FRAME_CHAR) {
325 /* Restart a new frame */
326 cfg->uart_buf_ptr = &cfg->uart_buf[0];
327 cfg->uart_buf_ctr = 0;
328 }
329
330 if (cfg->uart_buf_ctr < CONFIG_MODBUS_BUFFER_SIZE) {
331 *cfg->uart_buf_ptr++ = c;
332 cfg->uart_buf_ctr++;
333 }
334
335 if (c == MODBUS_ASCII_END_FRAME_CHAR2) {
336 k_work_submit(&ctx->server_work);
337 }
338
339 } else {
340 int n;
341
342 if (cfg->uart_buf_ctr == CONFIG_MODBUS_BUFFER_SIZE) {
343 /* Buffer full. Disable interrupt until timeout. */
344 modbus_serial_rx_disable(ctx);
345 return;
346 }
347
348 /* Restart timer on a new character */
349 k_timer_start(&cfg->rtu_timer,
350 K_USEC(cfg->rtu_timeout), K_NO_WAIT);
351
352 n = uart_fifo_read(cfg->dev, cfg->uart_buf_ptr,
353 (CONFIG_MODBUS_BUFFER_SIZE -
354 cfg->uart_buf_ctr));
355
356 cfg->uart_buf_ptr += n;
357 cfg->uart_buf_ctr += n;
358 }
359 }
360
cb_handler_tx(struct modbus_context * ctx)361 static void cb_handler_tx(struct modbus_context *ctx)
362 {
363 struct modbus_serial_config *cfg = ctx->cfg;
364 int n;
365
366 if (cfg->uart_buf_ctr > 0) {
367 n = uart_fifo_fill(cfg->dev, cfg->uart_buf_ptr,
368 cfg->uart_buf_ctr);
369 cfg->uart_buf_ctr -= n;
370 cfg->uart_buf_ptr += n;
371 return;
372 }
373
374 /* Must wait till the transmission is complete or
375 * RS-485 transceiver could be disabled before all data has
376 * been transmitted and message will be corrupted.
377 */
378 if (uart_irq_tx_complete(cfg->dev)) {
379 /* Disable transmission */
380 cfg->uart_buf_ptr = &cfg->uart_buf[0];
381 modbus_serial_tx_off(ctx);
382 modbus_serial_rx_on(ctx);
383 }
384 }
385
uart_cb_handler(const struct device * dev,void * app_data)386 static void uart_cb_handler(const struct device *dev, void *app_data)
387 {
388 struct modbus_context *ctx = (struct modbus_context *)app_data;
389
390 if (ctx == NULL) {
391 LOG_ERR("Modbus hardware is not properly initialized");
392 return;
393 }
394
395 if (uart_irq_update(dev) && uart_irq_is_pending(dev)) {
396
397 if (uart_irq_rx_ready(dev)) {
398 cb_handler_rx(ctx);
399 }
400
401 if (uart_irq_tx_ready(dev)) {
402 cb_handler_tx(ctx);
403 }
404 }
405 }
406
407 /* This function is called when the RTU framing timer expires. */
rtu_tmr_handler(struct k_timer * t_id)408 static void rtu_tmr_handler(struct k_timer *t_id)
409 {
410 struct modbus_context *ctx;
411
412 ctx = (struct modbus_context *)k_timer_user_data_get(t_id);
413
414 if (ctx == NULL) {
415 LOG_ERR("Failed to get Modbus context");
416 return;
417 }
418
419 k_work_submit(&ctx->server_work);
420 }
421
configure_gpio(struct modbus_context * ctx)422 static int configure_gpio(struct modbus_context *ctx)
423 {
424 struct modbus_serial_config *cfg = ctx->cfg;
425
426 if (cfg->de != NULL) {
427 if (!device_is_ready(cfg->de->port)) {
428 return -ENODEV;
429 }
430
431 if (gpio_pin_configure_dt(cfg->de, GPIO_OUTPUT_INACTIVE)) {
432 return -EIO;
433 }
434 }
435
436
437 if (cfg->re != NULL) {
438 if (!device_is_ready(cfg->re->port)) {
439 return -ENODEV;
440 }
441
442 if (gpio_pin_configure_dt(cfg->re, GPIO_OUTPUT_INACTIVE)) {
443 return -EIO;
444 }
445 }
446
447 return 0;
448 }
449
configure_uart(struct modbus_context * ctx,struct modbus_iface_param * param)450 static inline int configure_uart(struct modbus_context *ctx,
451 struct modbus_iface_param *param)
452 {
453 struct modbus_serial_config *cfg = ctx->cfg;
454 struct uart_config uart_cfg = {
455 .baudrate = param->serial.baud,
456 .flow_ctrl = UART_CFG_FLOW_CTRL_NONE,
457 };
458
459 if (ctx->mode == MODBUS_MODE_ASCII) {
460 uart_cfg.data_bits = UART_CFG_DATA_BITS_7;
461 } else {
462 uart_cfg.data_bits = UART_CFG_DATA_BITS_8;
463 }
464
465 switch (param->serial.parity) {
466 case UART_CFG_PARITY_ODD:
467 case UART_CFG_PARITY_EVEN:
468 uart_cfg.parity = param->serial.parity;
469 uart_cfg.stop_bits = UART_CFG_STOP_BITS_1;
470 break;
471 case UART_CFG_PARITY_NONE:
472 /* Use of no parity requires 2 stop bits */
473 uart_cfg.parity = param->serial.parity;
474 uart_cfg.stop_bits = UART_CFG_STOP_BITS_2;
475 break;
476 default:
477 return -EINVAL;
478 }
479
480 if (ctx->client) {
481 /* Allow custom stop bit settings only in client mode */
482 switch (param->serial.stop_bits_client) {
483 case UART_CFG_STOP_BITS_0_5:
484 case UART_CFG_STOP_BITS_1:
485 case UART_CFG_STOP_BITS_1_5:
486 case UART_CFG_STOP_BITS_2:
487 uart_cfg.stop_bits = param->serial.stop_bits_client;
488 break;
489 default:
490 return -EINVAL;
491 }
492 }
493
494 if (uart_configure(cfg->dev, &uart_cfg) != 0) {
495 LOG_ERR("Failed to configure UART");
496 return -EINVAL;
497 }
498
499 return 0;
500 }
501
modbus_serial_rx_disable(struct modbus_context * ctx)502 void modbus_serial_rx_disable(struct modbus_context *ctx)
503 {
504 modbus_serial_rx_off(ctx);
505 }
506
modbus_serial_rx_enable(struct modbus_context * ctx)507 void modbus_serial_rx_enable(struct modbus_context *ctx)
508 {
509 modbus_serial_rx_on(ctx);
510 }
511
modbus_serial_rx_adu(struct modbus_context * ctx)512 int modbus_serial_rx_adu(struct modbus_context *ctx)
513 {
514 struct modbus_serial_config *cfg = ctx->cfg;
515 int rc = 0;
516
517 switch (ctx->mode) {
518 case MODBUS_MODE_RTU:
519 rc = modbus_rtu_rx_adu(ctx);
520 break;
521 case MODBUS_MODE_ASCII:
522 if (!IS_ENABLED(CONFIG_MODBUS_ASCII_MODE)) {
523 return -ENOTSUP;
524 }
525
526 rc = modbus_ascii_rx_adu(ctx);
527 break;
528 default:
529 LOG_ERR("Unsupported MODBUS mode");
530 return -ENOTSUP;
531 }
532
533 cfg->uart_buf_ctr = 0;
534 cfg->uart_buf_ptr = &cfg->uart_buf[0];
535
536 return rc;
537 }
538
modbus_serial_tx_adu(struct modbus_context * ctx)539 int modbus_serial_tx_adu(struct modbus_context *ctx)
540 {
541 switch (ctx->mode) {
542 case MODBUS_MODE_RTU:
543 rtu_tx_adu(ctx);
544 return 0;
545 case MODBUS_MODE_ASCII:
546 if (IS_ENABLED(CONFIG_MODBUS_ASCII_MODE)) {
547 modbus_ascii_tx_adu(ctx);
548 return 0;
549 }
550 default:
551 break;
552 }
553
554 return -ENOTSUP;
555 }
556
modbus_serial_init(struct modbus_context * ctx,struct modbus_iface_param param)557 int modbus_serial_init(struct modbus_context *ctx,
558 struct modbus_iface_param param)
559 {
560 struct modbus_serial_config *cfg = ctx->cfg;
561 const uint32_t if_delay_max = 3500000;
562 const uint32_t numof_bits = 11;
563
564 switch (param.mode) {
565 case MODBUS_MODE_RTU:
566 case MODBUS_MODE_ASCII:
567 ctx->mode = param.mode;
568 break;
569 default:
570 return -ENOTSUP;
571 }
572
573 if (!device_is_ready(cfg->dev)) {
574 LOG_ERR("Bus device %s is not ready", cfg->dev->name);
575 return -ENODEV;
576 }
577
578 if (IS_ENABLED(CONFIG_UART_USE_RUNTIME_CONFIGURE)) {
579 if (configure_uart(ctx, ¶m) != 0) {
580 return -EINVAL;
581 }
582 }
583
584 if (param.serial.baud <= 38400) {
585 cfg->rtu_timeout = (numof_bits * if_delay_max) /
586 param.serial.baud;
587 } else {
588 cfg->rtu_timeout = (numof_bits * if_delay_max) / 38400;
589 }
590
591 if (configure_gpio(ctx) != 0) {
592 return -EIO;
593 }
594
595 cfg->uart_buf_ctr = 0;
596 cfg->uart_buf_ptr = &cfg->uart_buf[0];
597
598 uart_irq_callback_user_data_set(cfg->dev, uart_cb_handler, ctx);
599 k_timer_init(&cfg->rtu_timer, rtu_tmr_handler, NULL);
600 k_timer_user_data_set(&cfg->rtu_timer, ctx);
601
602 modbus_serial_rx_on(ctx);
603 LOG_INF("RTU timeout %u us", cfg->rtu_timeout);
604
605 return 0;
606 }
607
modbus_serial_disable(struct modbus_context * ctx)608 void modbus_serial_disable(struct modbus_context *ctx)
609 {
610 modbus_serial_tx_off(ctx);
611 modbus_serial_rx_off(ctx);
612 k_timer_stop(&ctx->cfg->rtu_timer);
613 }
614