Skip to content

Commit c2fd84f

Browse files
Maksim Salaudkalowsk
authored andcommitted
modbus: serial: Ignore received data when reception is disabled
A byte received when reception has been disabled corrupts internal state of the server (e.g. during transmission of a reply in server mode). The reponse packet is corrupted and its transmission is aborted and the data in the buffer is treated by the server as a new incoming packet. Since the buffer is corrupted CRC doesn't match and the following log message is printed: <wrn> modbus_serial: Calculated CRC does not match received CRC This condition happens when uart_irq_rx_ready() returns true if there is a new byte in the receive FIFO even with disabled RX interrupt. The issue has been discovered on a nucleo_u083rc board with a RS485 transceiver with the RI signal floating (a pull-down gives more stable reproduction). The pull-down ensures that RI is low during transmission which is seen as byte 0 with a framing error by the receiver. The byte is received by the MCU and corrupts the response. Similar effect can be achieved by not disabling the receiver during transmission (i.e. nRE is driven by the MCU and is fixed low). The fix discards any data received when reception has been disabled. Signed-off-by: Maksim Salau <msalau@iotecha.com>
1 parent 66f5d70 commit c2fd84f

File tree

2 files changed

+21
-0
lines changed

2 files changed

+21
-0
lines changed

subsys/modbus/modbus_internal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ struct modbus_serial_config {
8888
};
8989

9090
#define MODBUS_STATE_CONFIGURED 0
91+
#define MODBUS_STATE_RX_ENABLED 1
9192

9293
struct modbus_context {
9394
/* Interface name */

subsys/modbus/modbus_serial.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,17 @@ static void modbus_serial_tx_off(struct modbus_context *ctx)
5050
}
5151
}
5252

53+
static void modbus_serial_rx_fifo_drain(struct modbus_context *ctx)
54+
{
55+
struct modbus_serial_config *cfg = ctx->cfg;
56+
uint8_t buf[8];
57+
int n;
58+
59+
do {
60+
n = uart_fifo_read(cfg->dev, buf, sizeof(buf));
61+
} while (n == sizeof(buf));
62+
}
63+
5364
static void modbus_serial_rx_on(struct modbus_context *ctx)
5465
{
5566
struct modbus_serial_config *cfg = ctx->cfg;
@@ -58,6 +69,7 @@ static void modbus_serial_rx_on(struct modbus_context *ctx)
5869
gpio_pin_set(cfg->re->port, cfg->re->pin, 1);
5970
}
6071

72+
atomic_set_bit(&ctx->state, MODBUS_STATE_RX_ENABLED);
6173
uart_irq_rx_enable(cfg->dev);
6274
}
6375

@@ -66,6 +78,8 @@ static void modbus_serial_rx_off(struct modbus_context *ctx)
6678
struct modbus_serial_config *cfg = ctx->cfg;
6779

6880
uart_irq_rx_disable(cfg->dev);
81+
atomic_clear_bit(&ctx->state, MODBUS_STATE_RX_ENABLED);
82+
6983
if (cfg->re != NULL) {
7084
gpio_pin_set(cfg->re->port, cfg->re->pin, 0);
7185
}
@@ -312,6 +326,11 @@ static void cb_handler_rx(struct modbus_context *ctx)
312326
{
313327
struct modbus_serial_config *cfg = ctx->cfg;
314328

329+
if (!atomic_test_bit(&ctx->state, MODBUS_STATE_RX_ENABLED)) {
330+
modbus_serial_rx_fifo_drain(ctx);
331+
return;
332+
}
333+
315334
if ((ctx->mode == MODBUS_MODE_ASCII) &&
316335
IS_ENABLED(CONFIG_MODBUS_ASCII_MODE)) {
317336
uint8_t c;
@@ -379,6 +398,7 @@ static void cb_handler_tx(struct modbus_context *ctx)
379398
/* Disable transmission */
380399
cfg->uart_buf_ptr = &cfg->uart_buf[0];
381400
modbus_serial_tx_off(ctx);
401+
modbus_serial_rx_fifo_drain(ctx);
382402
modbus_serial_rx_on(ctx);
383403
}
384404
}

0 commit comments

Comments
 (0)