Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save clemensg/29bd68b3cfd719bd01002a2acde9662c to your computer and use it in GitHub Desktop.

Select an option

Save clemensg/29bd68b3cfd719bd01002a2acde9662c to your computer and use it in GitHub Desktop.

Revisions

  1. clemensg created this gist Jan 7, 2017.
    311 changes: 311 additions & 0 deletions BusyBox-stty-Add-RS485-config-options.patch
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,311 @@
    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