Created
January 7, 2017 13:30
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
From: Clemens Gruber <[email protected]> | |
Date: Thu, 4 Aug 2016 14:51:44 +0200 | |
Subject: [PATCH] stty: RS-485 support | |
Signed-off-by: Clemens Gruber <[email protected]> | |
--- | |
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 <[email protected]> 2001 | |
+ RS485 options added by Janos Angeli <[email protected]> 2013 | |
+ Adapted by Clemens Gruber <[email protected]> 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