From 6517dea57f6a5fbcbf77e0117947b9a2c31d014c Mon Sep 17 00:00:00 2001 From: Victor Antonovich Date: Fri, 29 Sep 2023 18:04:09 +0300 Subject: [PATCH] Make use of Linux RS-485 support #97 --- CMakeLists.txt | 5 +++++ README.md | 9 ++++++--- conf/mbusd.conf.example | 3 +++ doc/mbusd.8.in | 6 ++++-- src/cfg.c | 9 +++++++++ src/cfg.h | 6 ++++++ src/globals.h | 1 + src/main.c | 21 ++++++++++++++++++--- src/tty.c | 22 ++++++++++++++++++++++ src/tty.h | 7 +++++++ 10 files changed, 81 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7102ec9..b72f3ac 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,6 +5,7 @@ project(mbusd VERSION 0.5.1) list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/extern_GPL) include(CheckFunctionExists) include(CheckLibraryExists) +include(CheckSymbolExists) include(GNUInstallDirs) include(FindUnixCommands) include(FindSystemd) @@ -41,6 +42,10 @@ check_function_exists(cfsetispeed HAVE_CFSETISPEED) if(HAVE_CFSETSPEED AND HAVE_CFSETISPEED) add_definitions(-DHAVE_CFSETSPEED) endif() +check_symbol_exists(TIOCSRS485 sys/ioctl.h HAVE_TIOCRS485) +if(HAVE_TIOCRS485) + add_definitions(-DHAVE_TIOCRS485) +endif() check_function_exists(time HAVE_TIME) check_function_exists(localtime HAVE_LOCALTIME) if(HAVE_TIME AND HAVE_LOCALTIME) diff --git a/README.md b/README.md index 2943682..3c82d75 100644 --- a/README.md +++ b/README.md @@ -52,8 +52,10 @@ can be altered in many ways, e.g. by using the following tools in the `build` di Usage: ------ - mbusd [-h] [-d] [-L logfile] [-v level] [-c cfgfile] [-p device] [-s speed] [-m mode] - [-t] [-y file] [-Y file] [-A address] [-P port] [-C maxconn] [-N retries] + mbusd [-h] [-d] [-L logfile] [-v level] [-c cfgfile] + [-p device] [-s speed] [-m mode] [-S] + [-t] [-y sysfsfile] [-Y sysfsfile] + [-A address] [-P port] [-C maxconn] [-N retries] [-R pause] [-W wait] [-T timeout] -h Usage help. @@ -73,6 +75,7 @@ Usage: Specifies serial port speed. -m mode Specifies serial port mode (like 8N1). + -S Enable RS-485 support for given serial port device (Linux only) -t Enable RTS RS-485 data direction control (if not disabled while compile). -y file Enable RS-485 direction data direction control by writing '1' to file @@ -95,7 +98,7 @@ Usage: -T timeout Specifies connection timeout value in seconds (0 disables timeout). -b - Instructs **mbusd** to reply on a broadcast. + Instructs mbusd to reply on a broadcast. Please note running **mbusd** on default Modbus TCP port (502) requires root privileges! diff --git a/conf/mbusd.conf.example b/conf/mbusd.conf.example index 67ae365..2cde560 100644 --- a/conf/mbusd.conf.example +++ b/conf/mbusd.conf.example @@ -15,6 +15,9 @@ speed = 9600 # Serial port mode mode = 8n1 +# Enable RS-485 support for given serial port device (Linux only) +# enable_rs485 = no + # RS-485 data direction control type (addc, rts, sysfs_0, sysfs_1) trx_control = addc diff --git a/doc/mbusd.8.in b/doc/mbusd.8.in index b1f9cc5..6aee070 100644 --- a/doc/mbusd.8.in +++ b/doc/mbusd.8.in @@ -19,9 +19,9 @@ mbusd \- MODBUS/TCP to MODBUS/RTU gateway. .IR mode ] .RB [ -t ] .RB [ -y -.IR file ] +.IR sysfsfile ] .RB [ -Y -.IR file ] +.IR sysfsfile ] .RB [ -A .IR address ] .RB [ -P @@ -60,6 +60,8 @@ Specifies serial port device name. Specifies serial port speed. .IP "\fB-m \fImode\fR" Specifies serial port mode (like 8N1). +.IP \fB-S\fR +Enable RS-485 support for given serial port device (Linux only). .IP "\fB-A \fIaddress\fR" Specifies TCP address to bind. .IP "\fB-P \fIport\fR" diff --git a/src/cfg.c b/src/cfg.c index a6c5abf..deb522c 100644 --- a/src/cfg.c +++ b/src/cfg.c @@ -64,6 +64,9 @@ cfg_init(void) strncpy(cfg.ttyport, DEFAULT_PORT, INTBUFSIZE); cfg.ttyspeed = DEFAULT_SPEED; strncpy(cfg.ttymode, DEFAULT_MODE, INTBUFSIZE); +#ifdef HAVE_TIOCRS485 + cfg.rs485 = FALSE; +#endif #ifdef TRXCTL cfg.trxcntl = TRX_ADDC; *cfg.trxcntl_file = '\0'; @@ -183,6 +186,12 @@ cfg_handle_param(char *name, char *value) cfg.conntimeout = strtoul(value, NULL, 0); if (cfg.conntimeout > MAX_CONNTIMEOUT) return 0; +#ifdef HAVE_TIOCRS485 + } + else if (CFG_NAME_MATCH("enable_rs485")) + { + cfg.rs485 = CFG_VALUE_BOOL(); +#endif #ifdef TRXCTL } else if (CFG_NAME_MATCH("trx_control")) diff --git a/src/cfg.h b/src/cfg.h index 0f0033f..f4b7fbd 100644 --- a/src/cfg.h +++ b/src/cfg.h @@ -54,10 +54,16 @@ typedef struct int ttyspeed; /* tty mode */ char ttymode[INTBUFSIZE + 1]; +#ifdef HAVE_TIOCRS485 + /* Linux RS-485 support use flag */ + bool rs485; +#endif +#ifdef TRXCTL /* trx control type (0 - ADDC, 1 - by RTS, 2 - by sysfs GPIO with 1 activating transmit, 3 - by sysfs GPIO with 0 activating transmit) */ int trxcntl; /* trx control sysfs file */ char trxcntl_file[INTBUFSIZE + 1]; +#endif /* TCP server address */ char serveraddr[INTBUFSIZE + 1]; /* TCP server port number */ diff --git a/src/globals.h b/src/globals.h index 77b7167..cb145a8 100644 --- a/src/globals.h +++ b/src/globals.h @@ -59,6 +59,7 @@ #include #include #include +#include #ifdef HAVE_LIBUTIL # include #endif diff --git a/src/main.c b/src/main.c index c04f3b4..79c91bc 100644 --- a/src/main.c +++ b/src/main.c @@ -107,7 +107,11 @@ usage(char *exename) "[-L logfile] [-v level] " #endif "[-c cfgfile] \n" - " [-p device] [-s speed] [-m mode]\n" + " [-p device] [-s speed] [-m mode]" +#ifdef HAVE_TIOCRS485 + " [-S]" +#endif + "\n" #ifdef TRXCTL " [-t] [-y sysfsfile] [-Y sysfsfile]\n" #endif @@ -129,6 +133,9 @@ usage(char *exename) " -p device : set serial port device name (default %s)\n" " -s speed : set serial port speed (default %d)\n" " -m mode : set serial port mode (default %s)\n" +#ifdef HAVE_TIOCRS485 + " -S : enable Linux RS-485 support for given serial port device\n" +#endif " -A address : set TCP server address to bind (default %s)\n" " -P port : set TCP server port number (default %d)\n" #ifdef TRXCTL @@ -182,6 +189,9 @@ main(int argc, char *argv[]) #ifdef TRXCTL "ty:Y:" #endif +#ifdef HAVE_TIOCRS485 + "S" +#endif #ifdef LOG "v:L:" #endif @@ -213,11 +223,16 @@ main(int argc, char *argv[]) case 'y': cfg.trxcntl = TRX_SYSFS_1; strncpy(cfg.trxcntl_file, optarg, INTBUFSIZE); - break; + break; case 'Y': cfg.trxcntl = TRX_SYSFS_0; strncpy(cfg.trxcntl_file, optarg, INTBUFSIZE); - break; + break; +#endif +#ifdef HAVE_TIOCRS485 + case 'S': + cfg.rs485 = TRUE; + break; #endif #ifdef LOG case 'v': diff --git a/src/tty.c b/src/tty.c index 0b377b5..92462c7 100644 --- a/src/tty.c +++ b/src/tty.c @@ -65,6 +65,9 @@ tty_init(ttydata_t *mod) { mod->bpc++; } +#ifdef HAVE_TIOCRS485 + mod->rs485 = cfg.rs485; +#endif #ifdef TRXCTL mod->trxcntl = cfg.trxcntl; #endif @@ -187,6 +190,25 @@ tty_set_attr(ttydata_t *mod) tcflush(mod->fd, TCIOFLUSH); #ifdef TRXCTL tty_clr_rts(mod->fd); +#endif +#ifdef HAVE_TIOCRS485 + if (mod->rs485) + { + struct serial_rs485 rs485conf; +#ifdef LOG + logw(2, "tty: trying to enable RS-485 support for %s", mod->port); +#endif + if (ioctl(mod->fd, TIOCGRS485, &rs485conf) < 0) { + return RC_ERR; + } + rs485conf.flags |= SER_RS485_ENABLED; + if (ioctl(mod->fd, TIOCSRS485, &rs485conf) < 0) { + return RC_ERR; + } +#ifdef LOG + logw(2, "tty: enabled RS-485 support for %s", mod->port); +#endif + } #endif flag = fcntl(mod->fd, F_GETFL, 0); if (flag < 0) diff --git a/src/tty.h b/src/tty.h index e49965f..fe7d82f 100644 --- a/src/tty.h +++ b/src/tty.h @@ -34,6 +34,10 @@ #ifndef _TTY_H #define _TTY_H +#ifdef HAVE_TIOCRS485 +#include +#endif + #include "globals.h" #include "cfg.h" @@ -96,6 +100,9 @@ typedef struct int speed; /* serial port speed */ char *port; /* serial port device name */ int bpc; /* bits per character */ +#ifdef HAVE_TIOCRS485 + bool rs485; /* use Linux RS-485 support flag */ +#endif #ifdef TRXCTL int trxcntl; /* trx control type (enum - see values in config.h) */ #endif