Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save clemensg/29bd68b3cfd719bd01002a2acde9662c to your computer and use it in GitHub Desktop.
Save clemensg/29bd68b3cfd719bd01002a2acde9662c to your computer and use it in GitHub Desktop.
Patch for Busybox 1.25.1 to add RS-485 configuration to stty
From: Clemens Gruber <clemens.gruber@pqgruber.com>
Date: Thu, 4 Aug 2016 14:51:44 +0200
Subject: [PATCH] stty: RS-485 support
Signed-off-by: Clemens Gruber <clemens.gruber@pqgruber.com>
---
coreutils/stty.c | 159 +++++++++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 150 insertions(+), 9 deletions(-)
diff --git a/coreutils/stty.c b/coreutils/stty.c
index 52967ea8f351..5a2d44c7e790 100644
--- a/coreutils/stty.c
+++ b/coreutils/stty.c
@@ -19,6 +19,9 @@
Special for busybox ported by Vladimir Oleynik <dzo@simtreas.ru> 2001
+ RS485 options added by Janos Angeli <angelo@angelo.hu> 2013
+ Adapted by Clemens Gruber <clemens.gruber@pqgruber.com> 2014-2016
+
*/
//usage:#define stty_trivial_usage
@@ -32,8 +35,13 @@
//usage: "\n [SETTING] See manpage"
#include "libbb.h"
+
#include "common_bufsiz.h"
+#include <asm-generic/ioctls.h>
+#include <linux/ioctl.h>
+#include <linux/serial.h>
+
#ifndef _POSIX_VDISABLE
# define _POSIX_VDISABLE ((unsigned char) 0)
#endif
@@ -933,11 +941,27 @@ static int find_param(const char *name)
return i;
}
-static int recover_mode(const char *arg, struct termios *mode)
+static int find_rs485config(const char *name)
+{
+ static const char params[] ALIGN1 =
+ "rs485\0" /* 1 */
+ "rs485rtsonsend\0" /* 2 */
+ "rs485rtsaftersend\0" /* 3 */
+ "rs485rxduringtx\0" /* 4 */
+ "rs485delaybefore\0" /* 5 */
+ "rs485delayafter\0"; /* 6 */
+ int i = index_in_strings(params, name) + 1;
+ if ((i == 5) || (i == 6))
+ i |= 0x80;
+ return i;
+}
+
+static int recover_mode(const char *arg, struct termios *mode, struct serial_rs485 *rs485conf, int paramcheck, int rs485)
{
int i, n;
unsigned chr;
unsigned long iflag, oflag, cflag, lflag;
+ unsigned long rsflags, rsdelaybefore, rsdelayafter;
/* Scan into temporaries since it is too much trouble to figure out
the right format for 'tcflag_t' */
@@ -956,15 +980,30 @@ static int recover_mode(const char *arg, struct termios *mode)
arg += n;
}
+ if (rs485 >= 0) {
+ if (sscanf(arg, ":%lx:%lx:%lx%n", &rsflags, &rsdelaybefore, &rsdelayafter, &n) != 3)
+ return 0;
+ rs485conf->flags = rsflags;
+ rs485conf->delay_rts_before_send = rsdelaybefore;
+ rs485conf->delay_rts_after_send = rsdelayafter;
+ arg += n;
+ }
+
/* Fail if there are too many fields */
- if (*arg != '\0')
+ if (*arg != '\0') {
+ /* In the first pass of params verify we don't know the port device
+ have RS485 support or not, so give a try for the extra RS485 params */
+ if ((paramcheck) && (sscanf(arg, ":%lx:%lx:%lx%n", &rsflags, &rsdelaybefore, &rsdelayafter, &n) == 3))
+ return 1;
+
return 0;
+ }
return 1;
}
static void display_recoverable(const struct termios *mode,
- int UNUSED_PARAM dummy)
+ const struct serial_rs485 *rs485conf, int UNUSED_PARAM dummy, int rs485)
{
int i;
printf("%lx:%lx:%lx:%lx",
@@ -972,6 +1011,14 @@ static void display_recoverable(const struct termios *mode,
(unsigned long) mode->c_cflag, (unsigned long) mode->c_lflag);
for (i = 0; i < NCCS; ++i)
printf(":%x", (unsigned int) mode->c_cc[i]);
+
+ if (rs485 >= 0) {
+ printf(":%lx:%lx:%lx",
+ (unsigned long) rs485conf->flags,
+ (unsigned long) rs485conf->delay_rts_before_send,
+ (unsigned long) rs485conf->delay_rts_after_send);
+ }
+
bb_putchar('\n');
}
@@ -992,7 +1039,7 @@ static void display_speed(const struct termios *mode, int fancy)
wrapf(fmt_str, tty_baud_to_value(ispeed), tty_baud_to_value(ospeed));
}
-static void do_display(const struct termios *mode, int all)
+static void do_display(const struct termios *mode, const struct serial_rs485 *rs485conf, int all, int rs485)
{
int i;
tcflag_t *bitsp;
@@ -1058,6 +1105,24 @@ static void do_display(const struct termios *mode, int all)
}
}
newline();
+
+ if (rs485 < 0) {
+ if (all) {
+ wrapf("RS485 not supported");
+ newline();
+ }
+ } else {
+ wrapf("%srs485 %srs485rtsonsend %srs485rtsaftersend %srs485rxduringtx",
+ (rs485conf->flags & SER_RS485_ENABLED) ? "" : "-",
+ (rs485conf->flags & SER_RS485_RTS_ON_SEND) ? "" : "-",
+ (rs485conf->flags & SER_RS485_RTS_AFTER_SEND) ? "" : "-",
+ (rs485conf->flags & SER_RS485_RX_DURING_TX) ? "" : "-");
+ newline();
+ wrapf("rs485delaybefore = %d; rs485delayafter = %d;\n",
+ rs485conf->delay_rts_before_send,
+ rs485conf->delay_rts_after_send);
+ newline();
+ }
}
static void sane_mode(struct termios *mode)
@@ -1252,11 +1317,14 @@ int stty_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int stty_main(int argc UNUSED_PARAM, char **argv)
{
struct termios mode;
- void (*output_func)(const struct termios *, int);
+ struct serial_rs485 rs485conf;
+ void (*output_func)(const struct termios *, const struct serial_rs485 *, int, int);
const char *file_name = NULL;
int display_all = 0;
int stty_state;
int k;
+ int rs485_supported;
+ int rs485_setconfig;
INIT_G();
@@ -1281,6 +1349,13 @@ int stty_main(int argc UNUSED_PARAM, char **argv)
stty_state &= ~STTY_noargs;
continue;
}
+
+ param = find_rs485config(arg+1);
+ if ((param) && ((param & param_need_arg) == 0)) {
+ stty_state &= ~STTY_noargs;
+ continue;
+ }
+
/* It is an option - parse it */
i = 0;
while (arg[++i]) {
@@ -1335,6 +1410,17 @@ int stty_main(int argc UNUSED_PARAM, char **argv)
continue;
}
+ param = find_rs485config(arg);
+ if (param & param_need_arg) {
+ if (!argnext)
+ bb_error_msg_and_die(bb_msg_requires_arg, arg);
+ ++k;
+ }
+ if (param) {
+ stty_state &= ~STTY_noargs;
+ continue;
+ }
+
param = find_param(arg);
if (param & param_need_arg) {
if (!argnext)
@@ -1369,7 +1455,7 @@ int stty_main(int argc UNUSED_PARAM, char **argv)
set_speed_or_die(output_speed, argnext, &mode);
break;
default:
- if (recover_mode(arg, &mode) == 1) break;
+ if (recover_mode(arg, &mode, &rs485conf, 1, -1) == 1) break;
if (tty_value_to_baud(xatou(arg)) != (speed_t) -1) break;
invalid_argument:
bb_error_msg_and_die("invalid argument '%s'", arg);
@@ -1402,15 +1488,17 @@ int stty_main(int argc UNUSED_PARAM, char **argv)
memset(&mode, 0, sizeof(mode));
if (tcgetattr(STDIN_FILENO, &mode))
perror_on_device_and_die("%s");
+ rs485_supported = ioctl(STDIN_FILENO, TIOCGRS485, &rs485conf);
if (stty_state & (STTY_verbose_output | STTY_recoverable_output | STTY_noargs)) {
G.max_col = get_terminal_width(STDOUT_FILENO);
- output_func(&mode, display_all);
+ output_func(&mode, &rs485conf, display_all, rs485_supported);
return EXIT_SUCCESS;
}
/* Second pass: perform actions */
k = 0;
+ rs485_setconfig = 0;
while (argv[++k]) {
const struct mode_info *mp;
const struct control_info *cp;
@@ -1424,6 +1512,25 @@ int stty_main(int argc UNUSED_PARAM, char **argv)
set_mode(mp, 1 /* reversed */, &mode);
stty_state |= STTY_require_set_attr;
}
+
+ param = find_rs485config(arg+1);
+ if ((param) && ((param & param_need_arg) == 0)) {
+ rs485_setconfig = 1;
+ switch (param) {
+ case 1:
+ rs485conf.flags &= ~SER_RS485_ENABLED;
+ break;
+ case 2:
+ rs485conf.flags &= ~SER_RS485_RTS_ON_SEND;
+ break;
+ case 3:
+ rs485conf.flags &= ~SER_RS485_RTS_AFTER_SEND;
+ break;
+ case 4:
+ rs485conf.flags &= ~SER_RS485_RX_DURING_TX;
+ }
+ }
+
/* It is an option - already parsed. Skip it */
continue;
}
@@ -1443,6 +1550,33 @@ int stty_main(int argc UNUSED_PARAM, char **argv)
continue;
}
+ param = find_rs485config(arg);
+ if (param) {
+ rs485_setconfig = 1;
+ if (param & param_need_arg)
+ ++k;
+ switch (param & 0x7F) {
+ case 1:
+ rs485conf.flags |= SER_RS485_ENABLED;
+ break;
+ case 2:
+ rs485conf.flags |= SER_RS485_RTS_ON_SEND;
+ break;
+ case 3:
+ rs485conf.flags |= SER_RS485_RTS_AFTER_SEND;
+ break;
+ case 4:
+ rs485conf.flags |= SER_RS485_RX_DURING_TX;
+ break;
+ case 5:
+ rs485conf.delay_rts_before_send = xatoul_sfx(argnext, stty_suffixes);
+ break;
+ case 6:
+ rs485conf.delay_rts_after_send = xatoul_sfx(argnext, stty_suffixes);
+ }
+ continue;
+ }
+
param = find_param(arg);
if (param & param_need_arg) {
++k;
@@ -1479,9 +1613,11 @@ int stty_main(int argc UNUSED_PARAM, char **argv)
stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
break;
default:
- if (recover_mode(arg, &mode) == 1)
+ if (recover_mode(arg, &mode, &rs485conf, 0, rs485_supported) == 1) {
stty_state |= STTY_require_set_attr;
- else /* true: if (tty_value_to_baud(xatou(arg)) != (speed_t) -1) */{
+ if (rs485_supported >= 0)
+ rs485_setconfig = 1;
+ } else /* true: if (tty_value_to_baud(xatou(arg)) != (speed_t) -1) */{
set_speed_or_die(both_speeds, arg, &mode);
stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
} /* else - impossible (caught in the first pass):
@@ -1532,5 +1668,10 @@ int stty_main(int argc UNUSED_PARAM, char **argv)
}
}
+ if (rs485_setconfig) {
+ if (ioctl (STDIN_FILENO, TIOCSRS485, &rs485conf) < 0)
+ perror_on_device_and_die("%s: cannot set RS485 options");
+ }
+
return EXIT_SUCCESS;
}
--
2.11.0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment