1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
|
From 8d4f9a1a77f59eb3ed79267f58fac949835aebfc Mon Sep 17 00:00:00 2001
From: Vitor Soares <vitor.soares@toradex.com>
Date: Thu, 30 Oct 2025 14:52:57 +0000
Subject: [PATCH] Fix serial setup handling to respect user intent
Commit 77320571e63c ("Check if rs485 is already configured on the port")
attempted to respect RS485 settings already configured on the port (e.g.
via Device Tree). However, it unintentionally ignored user input,
causing issues such as:
- Inability to change delay settings
- Failure to explicitly disable RS485
- Broken UART loopback and RTS/CTS flow-control tests when RS485 was
pre-enabled
The original intent was valid for existing configurations (bare -q), but
the tool should prioritize user intent, especially in testing scenarios.
This update restores predictable, user-driven behavior:
- RS485 can be explicitly enabled, disabled, or reconfigured
- Current configurations are respected when appropriate
Upstream-Status: Submitted [https://github.com/cbrake/linux-serial-test/pull/68]
Fixes: 77320571e63c ("Check if rs485 is already configured on the port")
Signed-off-by: Vitor Soares <vitor.soares@toradex.com>
---
linux-serial-test.c | 48 ++++++++++++++++++++++++++++-----------------
1 file changed, 30 insertions(+), 18 deletions(-)
diff --git a/linux-serial-test.c b/linux-serial-test.c
index 294f53882570..119bf58e663d 100644
--- a/linux-serial-test.c
+++ b/linux-serial-test.c
@@ -60,6 +60,7 @@ int _cl_no_tx_param = 0;
int _cl_rx_delay = 0;
int _cl_tx_delay = 0;
int _cl_tx_bytes = 0;
+int _cl_rs485 = 0;
int _cl_rs485_after_delay = -1;
int _cl_rs485_before_delay = 0;
int _cl_rs485_rts_after_send = 0;
@@ -315,7 +316,9 @@ static void display_help(void)
" -q, --rs485 Enable RS485 direction control on port, and set delay from when TX is\n"
" finished and RS485 driver enable is de-asserted. Delay is specified in\n"
" bit times. To optionally specify a delay from when the driver is enabled\n"
- " to start of TX use 'after_delay.before_delay' (-q 1.1)\n"
+ " to start of TX use 'after_delay.before_delay' (-q 1.1). If no value is\n"
+ " given, delay defaults to 0. Existing RS485 configuration is respected if\n"
+ " already enabled.\n"
" -Q, --rs485_rts Deassert RTS on send, assert after send. Omitting -Q inverts this logic.\n"
" -m, --no-modem Do not clobber against any modem lines.\n"
" -o, --tx-time Number of seconds to transmit for (defaults to 0, meaning no limit)\n"
@@ -335,7 +338,7 @@ static void process_options(int argc, char * argv[])
{
for (;;) {
int option_index = 0;
- static const char *short_options = "hb:p:d:D:TRsSy:z:cBertq:Qml:a:w:o:i:P:kKAI:O:W:Znf";
+ static const char *short_options = "hb:p:d:D:TRsSy:z:cBertq::Qml:a:w:o:i:P:kKAI:O:W:Znf";
static const struct option long_options[] = {
{"help", no_argument, 0, 0},
{"baud", required_argument, 0, 'b'},
@@ -359,7 +362,7 @@ static void process_options(int argc, char * argv[])
{"rx-delay", required_argument, 0, 'l'},
{"tx-delay", required_argument, 0, 'a'},
{"tx-bytes", required_argument, 0, 'w'},
- {"rs485", required_argument, 0, 'q'},
+ {"rs485", optional_argument, 0, 'q'},
{"rs485_rts", no_argument, 0, 'Q'},
{"no-modem", no_argument, 0, 'm'},
{"tx-time", required_argument, 0, 'o'},
@@ -467,8 +470,12 @@ static void process_options(int argc, char * argv[])
}
case 'q': {
char *endptr;
- _cl_rs485_after_delay = strtol(optarg, &endptr, 0);
- _cl_rs485_before_delay = strtol(endptr+1, &endptr, 0);
+ _cl_rs485 = 1;
+
+ if (optarg) {
+ _cl_rs485_after_delay = strtol(optarg, &endptr, 0);
+ _cl_rs485_before_delay = strtol(endptr+1, &endptr, 0);
+ }
break;
}
case 'Q':
@@ -707,15 +714,20 @@ static void setup_serial_port(int baud)
/* enable/disable rs485 direction control, first check if RS485 is supported */
if(ioctl(_fd, TIOCGRS485, &rs485) < 0) {
- if (_cl_rs485_after_delay >= 0) {
+ if (_cl_rs485) {
/* error could be because hardware is missing rs485 support so only print when actually trying to activate it */
perror("Error getting RS-485 mode");
}
} else {
- if (rs485.flags & SER_RS485_ENABLED) {
- printf("RS485 already enabled on port, ignoring delays if set\n");
- } else {
- if (_cl_rs485_after_delay >= 0) {
+ if (_cl_rs485) {
+ /* Skip reconfiguration if already enabled with default delays */
+ if ((_cl_rs485_after_delay < 0) && (rs485.flags & SER_RS485_ENABLED)) {
+ printf("RS485 already enabled on port with default settings\n");
+ } else {
+ /* Default to 0 if not specified */
+ if (_cl_rs485_after_delay < 0) {
+ _cl_rs485_after_delay = 0;
+ }
/* enable RS485 */
rs485.flags |= SER_RS485_ENABLED | SER_RS485_RX_DURING_TX |
(_cl_rs485_rts_after_send ? SER_RS485_RTS_AFTER_SEND : SER_RS485_RTS_ON_SEND);
@@ -725,14 +737,14 @@ static void setup_serial_port(int baud)
if(ioctl(_fd, TIOCSRS485, &rs485) < 0) {
perror("Error setting RS-485 mode");
}
- } else {
- /* disable RS485 */
- rs485.flags &= ~(SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND);
- rs485.delay_rts_after_send = 0;
- rs485.delay_rts_before_send = 0;
- if(ioctl(_fd, TIOCSRS485, &rs485) < 0) {
- perror("Error setting RS-232 mode");
- }
+ }
+ } else {
+ /* disable RS485 */
+ rs485.flags &= ~(SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND);
+ rs485.delay_rts_after_send = 0;
+ rs485.delay_rts_before_send = 0;
+ if(ioctl(_fd, TIOCSRS485, &rs485) < 0) {
+ perror("Error setting RS-232 mode");
}
}
}
|