mirror of https://github.com/3cky/mbusd.git
Compare commits
13 Commits
021ab29710
...
52bd932ac9
Author | SHA1 | Date |
---|---|---|
kpr0th | 52bd932ac9 | |
kpr0th | 164accb10a | |
kpr0th | 5308e4ee93 | |
kpr0th | b76ac4bec4 | |
Victor Antonovich | 68f988051c | |
Victor Antonovich | b03d50b58c | |
Victor Antonovich | 20c87df994 | |
Cían Hughes | 4ee7e8a834 | |
Victor Antonovich | b07681842f | |
Victor Antonovich | b464ec9676 | |
Victor Antonovich | 6517dea57f | |
Victor Antonovich | 0f7a8c50fb | |
Victor Antonovich | 18fb6d086e |
|
@ -32,7 +32,7 @@ jobs:
|
|||
- name: Install test dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install setuptools wheel twisted pymodbus
|
||||
pip install setuptools wheel twisted pyserial pymodbus
|
||||
sudo apt-get install -y socat
|
||||
|
||||
- name: Run tests
|
||||
|
|
|
@ -1,25 +1,11 @@
|
|||
/autom4te.cache
|
||||
/config.cache
|
||||
/config.h
|
||||
/config.status
|
||||
/.settings/
|
||||
/src/.deps/
|
||||
/src/*.o
|
||||
/src/mbusd
|
||||
/doc/mbusd.8
|
||||
Makefile
|
||||
/.settings
|
||||
*.log
|
||||
*.in~
|
||||
systemd-units/mbusd@.service
|
||||
*.conf
|
||||
*.pyc
|
||||
CMakeCache.txt
|
||||
CMakeFiles
|
||||
CPackConfig.cmake
|
||||
CPackSourceConfig.cmake
|
||||
cmake_install.cmake
|
||||
.idea
|
||||
*~
|
||||
/.idea
|
||||
/.vscode
|
||||
.project
|
||||
.cproject
|
||||
build
|
||||
.pydevproject
|
||||
/build
|
||||
build.sh
|
|
@ -1,10 +1,11 @@
|
|||
cmake_minimum_required(VERSION 3.2)
|
||||
|
||||
project(mbusd VERSION 0.5.1)
|
||||
project(mbusd VERSION 0.5.2)
|
||||
|
||||
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)
|
||||
|
|
2
LICENSE
2
LICENSE
|
@ -1,4 +1,4 @@
|
|||
Copyright (c) 2002-2003, 2013-2022 Victor Antonovich (v.antonovich@gmail.com)
|
||||
Copyright (c) 2002-2003, 2013-2023 Victor Antonovich (v.antonovich@gmail.com)
|
||||
Copyright (c) 2011 Andrew Denysenko <nitr0@seti.kr.ua>
|
||||
All rights reserved.
|
||||
|
||||
|
|
50
README.md
50
README.md
|
@ -52,19 +52,21 @@ 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]
|
||||
[-R pause] [-W wait] [-T timeout]
|
||||
mbusd [-h] [-d] [-L logfile] [-v level] [-c cfgfile]
|
||||
[-p device] [-s speed] [-m mode] [-S]
|
||||
[-t] [-r] [-y sysfsfile] [-Y sysfsfile]
|
||||
[-A address] [-P port] [-C maxconn] [-N retries]
|
||||
[-R pause] [-W wait] [-T timeout] [-b]
|
||||
|
||||
-h Usage help.
|
||||
-d Instruct mbusd not to fork itself (non-daemonize).
|
||||
-L logfile
|
||||
Specifies log file name ('-' for logging to STDOUT only, default is /var/log/mbusd.log).
|
||||
Specifies log file name ('-' for logging to STDOUT only, relative path or bare filename
|
||||
will be stored at /var/log, default is /var/log/mbus.log).
|
||||
-v level
|
||||
Specifies log verbosity level (0 for errors only, 1 for warnings
|
||||
and 2 for also information messages.) If mbusd was compiled in debug mode,
|
||||
valid log levels are up to 9, where log levels above 2 forces
|
||||
logging of information about additional internal events.
|
||||
Specifies log verbosity level (0 for errors only, 1 for warnings and 2 for informational
|
||||
messages also). If mbusd was compiled in debug mode, valid log levels are up to 9,
|
||||
where log levels above 2 adds logging of information about additional internal events.
|
||||
-c cfgfile
|
||||
Read configuration from cfgfile.
|
||||
-p device
|
||||
|
@ -73,29 +75,31 @@ Usage:
|
|||
Specifies serial port speed.
|
||||
-m mode
|
||||
Specifies serial port mode (like 8N1).
|
||||
-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
|
||||
for transmitter enable and '0' to file for transmitter disable
|
||||
-Y file
|
||||
Enable RS-485 direction data direction control by writing '0' to file
|
||||
for transmitter enable and '1' to file for transmitter disable
|
||||
-S Enable RS-485 support for given serial port device (Linux only)
|
||||
-t Enable RTS RS-485 data direction control using RTS, active transmit.
|
||||
-r Enable RTS RS-485 data direction control using RTS, active receive.
|
||||
-y sysfsfile
|
||||
Enable RS-485 direction data direction control by writing '1' to sysfs file
|
||||
for transmitter enable and '0' to file for transmitter disable.
|
||||
-Y sysfsfile
|
||||
Enable RS-485 direction data direction control by writing '0' to sysfs file
|
||||
for transmitter enable and '1' to file for transmitter disable.
|
||||
-A address
|
||||
Specifies TCP address to bind (default 0.0.0.0).
|
||||
Specifies TCP server address to bind (default is 0.0.0.0).
|
||||
-P port
|
||||
Specifies TCP port number (default 502).
|
||||
Specifies TCP server port number (default is 502).
|
||||
-C maxconn
|
||||
Specifies maximum number of simultaneous TCP connections.
|
||||
Specifies maximum number of simultaneous TCP connections (default is 32).
|
||||
-N retries
|
||||
Specifies maximum number of request retries (0 disables retries).
|
||||
Specifies maximum number of request retries (0 disables retries, default is 3).
|
||||
-R pause
|
||||
Specifies pause between requests in milliseconds.
|
||||
Specifies pause between requests in milliseconds (default is 100ms).
|
||||
-W wait
|
||||
Specifies response wait time in milliseconds.
|
||||
Specifies response wait time in milliseconds (default is 500ms).
|
||||
-T timeout
|
||||
Specifies connection timeout value in seconds (0 disables timeout).
|
||||
Specifies connection timeout value in seconds (0 disables timeout, default is 60).
|
||||
-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!
|
||||
|
||||
|
|
|
@ -4,6 +4,14 @@
|
|||
# #
|
||||
#############################################
|
||||
|
||||
########## Logging settings #############
|
||||
|
||||
# Logging verbosity level
|
||||
loglevel = 2
|
||||
|
||||
# Logfile (fully-qualified path, or filename [stored at /var/log/] or - for STDOUT only)
|
||||
logfile = /var/log/mbus.log
|
||||
|
||||
########## Serial port settings #############
|
||||
|
||||
# Serial port device name
|
||||
|
@ -15,7 +23,10 @@ speed = 9600
|
|||
# Serial port mode
|
||||
mode = 8n1
|
||||
|
||||
# RS-485 data direction control type (addc, rts, sysfs_0, sysfs_1)
|
||||
# Enable RS-485 support for given serial port device (Linux only)
|
||||
# enable_rs485 = no
|
||||
|
||||
# RS-485 data direction control type (addc, rts_0, rts/rts_1, sysfs_0, sysfs_1)
|
||||
trx_control = addc
|
||||
|
||||
# Sysfs file to use to control data direction
|
||||
|
|
|
@ -18,10 +18,11 @@ mbusd \- MODBUS/TCP to MODBUS/RTU gateway.
|
|||
.RB [ -m
|
||||
.IR mode ]
|
||||
.RB [ -t ]
|
||||
.RB [ -r ]
|
||||
.RB [ -y
|
||||
.IR file ]
|
||||
.IR sysfsfile ]
|
||||
.RB [ -Y
|
||||
.IR file ]
|
||||
.IR sysfsfile ]
|
||||
.RB [ -A
|
||||
.IR address ]
|
||||
.RB [ -P
|
||||
|
@ -60,18 +61,22 @@ 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"
|
||||
Specifies TCP port number.
|
||||
.IP \fB-t\fR
|
||||
Enable RTS RS-485 data direction control (if not disabled while compile).
|
||||
Enable RTS RS-485 data direction control using RTS, active transmit.
|
||||
.IP \fB-r\fR
|
||||
Enable RTS RS-485 data direction control using RTS, active receive.
|
||||
.IP "\fB-y \fIfile\fR"
|
||||
Enable RS-485 direction data direction control by writing '1' to file
|
||||
for transmitter enable and '0' to file for transmitter disable
|
||||
for transmitter enable and '0' to file for transmitter disable.
|
||||
.IP "\fB-Y \fIfile\fR"
|
||||
Enable RS-485 direction data direction control by writing '0' to file
|
||||
for transmitter enable and '1' to file for transmitter disable
|
||||
for transmitter enable and '1' to file for transmitter disable.
|
||||
.IP "\fB-C \fImaxconn\fR"
|
||||
Specifies maximum number of simultaneous TCP connections.
|
||||
.IP "\fB-N \fIretries\fR"
|
||||
|
|
69
src/cfg.c
69
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';
|
||||
|
@ -95,6 +98,20 @@ cfg_ltrim(const char *s)
|
|||
return (char *) s;
|
||||
}
|
||||
|
||||
static int
|
||||
cfg_is_empty(char *s)
|
||||
{
|
||||
char *p = s + strlen(s);
|
||||
if (strlen(s) == 0)
|
||||
return 1;
|
||||
while (p > s && isspace((unsigned char )(*--p)))
|
||||
{ //no-op
|
||||
}
|
||||
if (p == s && isspace((unsigned char )(*p)))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
cfg_handle_param(char *name, char *value)
|
||||
{
|
||||
|
@ -183,6 +200,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"))
|
||||
|
@ -191,9 +214,13 @@ cfg_handle_param(char *name, char *value)
|
|||
{
|
||||
cfg.trxcntl = TRX_ADDC;
|
||||
}
|
||||
else if (CFG_VALUE_MATCH("rts"))
|
||||
else if (CFG_VALUE_MATCH("rts") || CFG_VALUE_MATCH("rts_1"))
|
||||
{
|
||||
cfg.trxcntl = TRX_RTS;
|
||||
cfg.trxcntl = TRX_RTS_1;
|
||||
}
|
||||
else if (CFG_VALUE_MATCH("rts_0"))
|
||||
{
|
||||
cfg.trxcntl = TRX_RTS_0;
|
||||
}
|
||||
else if (CFG_VALUE_MATCH("sysfs_0"))
|
||||
{
|
||||
|
@ -218,7 +245,43 @@ cfg_handle_param(char *name, char *value)
|
|||
}
|
||||
else if (CFG_NAME_MATCH("loglevel"))
|
||||
{
|
||||
cfg.dbglvl = (char)strtol(optarg, NULL, 0);
|
||||
cfg.dbglvl = (char)strtol(value, NULL, 0);
|
||||
# ifdef DEBUG
|
||||
if (!(isdigit(*value)) || cfg.dbglvl < 0 || cfg.dbglvl > 9)
|
||||
{ /* report about invalid log level */
|
||||
CFG_ERR("invalid loglevel value: %s (must be 0-9)", value);
|
||||
# else
|
||||
if (!(isdigit(*value)) || cfg.dbglvl < 0 || cfg.dbglvl > 2)
|
||||
{ /* report about invalid log level */
|
||||
CFG_ERR("invalid loglevel value: %s (must be 0-2)", value);
|
||||
# endif
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
else if (CFG_NAME_MATCH("logfile"))
|
||||
{
|
||||
if (cfg_is_empty(value))
|
||||
{
|
||||
CFG_ERR("missing logfile value", value);
|
||||
return(0);
|
||||
}
|
||||
else if (*value != '/')
|
||||
{
|
||||
if (*value == '-')
|
||||
{
|
||||
/* logging to file disabled */
|
||||
*cfg.logname = '\0';
|
||||
}
|
||||
else
|
||||
{ /* concatenate given log file name with default path */
|
||||
strncpy(cfg.logname, LOGPATH, INTBUFSIZE);
|
||||
strncat(cfg.logname, value, INTBUFSIZE - strlen(cfg.logname));
|
||||
}
|
||||
}
|
||||
else strncpy(cfg.logname, value, INTBUFSIZE);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -251,7 +251,7 @@ conn_write(int d, void *buf, size_t nbytes, int istty)
|
|||
#ifdef TRXCTL
|
||||
if (istty && cfg.trxcntl != TRX_ADDC)
|
||||
{
|
||||
tty_set_rts(d);
|
||||
tty_set_tx(d);
|
||||
tty_delay(35000000l/cfg.ttyspeed);
|
||||
}
|
||||
#endif
|
||||
|
@ -267,7 +267,7 @@ conn_write(int d, void *buf, size_t nbytes, int istty)
|
|||
if (istty && cfg.trxcntl != TRX_ADDC )
|
||||
{
|
||||
tty_delay(DV(nbytes, tty.bpc, cfg.ttyspeed));
|
||||
tty_clr_rts(d);
|
||||
tty_set_rx(d);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -59,6 +59,7 @@
|
|||
#include <netdb.h>
|
||||
#include <fcntl.h>
|
||||
#include <ctype.h>
|
||||
#include <stdbool.h>
|
||||
#ifdef HAVE_LIBUTIL
|
||||
# include <libutil.h>
|
||||
#endif
|
||||
|
|
91
src/main.c
91
src/main.c
|
@ -56,6 +56,20 @@ ttydata_t tty;
|
|||
/* Connections queue descriptor */
|
||||
queue_t queue;
|
||||
|
||||
static int
|
||||
main_is_empty(char *s)
|
||||
{
|
||||
char *p = s + strlen(s);
|
||||
if (strlen(s) == 0)
|
||||
return 1;
|
||||
while (p > s && isspace((unsigned char )(*--p)))
|
||||
{ //no-op
|
||||
}
|
||||
if (p == s && isspace((unsigned char )(*p)))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef HAVE_DAEMON
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
@ -100,52 +114,62 @@ void
|
|||
usage(char *exename)
|
||||
{
|
||||
cfg_init();
|
||||
printf("%s-%s Copyright (C) 2002-2003, 2011, 2013-2022 Victor Antonovich <v.antonovich@gmail.com>, "
|
||||
printf("%s-%s Copyright (C) 2002-2003, 2011, 2013-2023 Victor Antonovich <v.antonovich@gmail.com>, "
|
||||
"Andrew Denysenko <nitr0@seti.kr.ua>\n\n"
|
||||
"Usage: %s [-h] [-d] "
|
||||
#ifdef LOG
|
||||
"[-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"
|
||||
" [-t] [-r] [-y sysfsfile] [-Y sysfsfile]\n"
|
||||
#endif
|
||||
" [-A address] [-P port] [-C maxconn] [-N retries]\n"
|
||||
" [-R pause] [-W wait] [-T timeout] [-b]\n\n"
|
||||
"Options:\n"
|
||||
" -h : this help\n"
|
||||
" -d : don't daemonize\n"
|
||||
" -d : don't fork (non-daemonize)\n"
|
||||
#ifdef LOG
|
||||
" -L logfile : set log file name (default %s%s, \n"
|
||||
" -L logfile : set log file name (default is %s%s, \n"
|
||||
" '-' for logging to STDOUT only)\n"
|
||||
#ifdef DEBUG
|
||||
" -v level : set log level (0-9, default %d, 0 - errors only)\n"
|
||||
" -v level : set log level (0-9, default is %d, 0 - errors only)\n"
|
||||
#else
|
||||
" -v level : set log level (0-2, default %d, 0 - errors only)\n"
|
||||
#endif
|
||||
#endif
|
||||
" -c cfgfile : read configuration from cfgfile\n"
|
||||
" -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"
|
||||
" -A address : set TCP server address to bind (default %s)\n"
|
||||
" -P port : set TCP server port number (default %d)\n"
|
||||
" -p device : set serial port device name (default is %s)\n"
|
||||
" -s speed : set serial port speed (default is %d)\n"
|
||||
" -m mode : set serial port mode (default is %s)\n"
|
||||
#ifdef HAVE_TIOCRS485
|
||||
" -S : enable Linux RS-485 support for given serial port device\n"
|
||||
#endif
|
||||
#ifdef TRXCTL
|
||||
" -t : enable RTS RS-485 data direction control using RTS\n"
|
||||
" -t : enable RTS RS-485 data direction control using RTS, active transmit\n"
|
||||
" -r : enable RTS RS-485 data direction control using RTS, active receive\n"
|
||||
" -y : enable RTS RS-485 data direction control using sysfs file, active transmit\n"
|
||||
" (writes '1' to sysfs file for transmit enable, '0' for transmit disable)\n"
|
||||
" -Y : enable RTS RS-485 data direction control using sysfs file, active receive\n"
|
||||
" (writes '0' to sysfs file for transmit enable, '1' for transmit disable)\n"
|
||||
#endif
|
||||
" -A address : set TCP server address to bind (default is %s)\n"
|
||||
" -P port : set TCP server port number (default is %d)\n"
|
||||
" -C maxconn : set maximum number of simultaneous TCP connections\n"
|
||||
" (1-%d, default %d)\n"
|
||||
" (1-%d, default is %d)\n"
|
||||
" -N retries : set maximum number of request retries\n"
|
||||
" (0-%d, default %d, 0 - without retries)\n"
|
||||
" (0-%d, default is %d, 0 disables retrying)\n"
|
||||
" -R pause : set pause between requests in milliseconds\n"
|
||||
" (1-%d, default %lu)\n"
|
||||
" (1-%d, default is %lu)\n"
|
||||
" -W wait : set response wait time in milliseconds\n"
|
||||
" (1-%d, default %lu)\n"
|
||||
" (1-%d, default is %lu)\n"
|
||||
" -T timeout : set connection timeout value in seconds\n"
|
||||
" (0-%d, default %d, 0 - no timeout)\n"
|
||||
" (0-%d, default is %d, 0 disables timeout)\n"
|
||||
" -b : enable reply on broadcast"
|
||||
"\n", PACKAGE, VERSION, exename,
|
||||
#ifdef LOG
|
||||
|
@ -159,6 +183,7 @@ usage(char *exename)
|
|||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
|
@ -182,6 +207,9 @@ main(int argc, char *argv[])
|
|||
#ifdef TRXCTL
|
||||
"ty:Y:"
|
||||
#endif
|
||||
#ifdef HAVE_TIOCRS485
|
||||
"S"
|
||||
#endif
|
||||
#ifdef LOG
|
||||
"v:L:"
|
||||
#endif
|
||||
|
@ -208,36 +236,49 @@ main(int argc, char *argv[])
|
|||
break;
|
||||
#ifdef TRXCTL
|
||||
case 't':
|
||||
cfg.trxcntl = TRX_RTS;
|
||||
cfg.trxcntl = TRX_RTS_1;
|
||||
break;
|
||||
case 'r':
|
||||
cfg.trxcntl = TRX_RTS_0;
|
||||
break;
|
||||
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':
|
||||
cfg.dbglvl = (char)strtol(optarg, NULL, 0);
|
||||
# ifdef DEBUG
|
||||
if (cfg.dbglvl > 9)
|
||||
if (!(isdigit(*optarg)) || cfg.dbglvl < 0 || cfg.dbglvl > 9)
|
||||
{ /* report about invalid log level */
|
||||
printf("%s: -v: invalid loglevel value"
|
||||
" (%d, must be 0-9)\n", exename, cfg.dbglvl);
|
||||
" (%s, must be 0-9)\n", exename, optarg);
|
||||
# else
|
||||
if (cfg.dbglvl < 0 || cfg.dbglvl > 9)
|
||||
if (!(isdigit(*optarg)) || cfg.dbglvl < 0 || cfg.dbglvl > 2)
|
||||
{ /* report about invalid log level */
|
||||
printf("%s: -v: invalid loglevel value"
|
||||
" (%d, must be 0-2)\n", exename, cfg.dbglvl);
|
||||
" (%s, must be 0-2)\n", exename, optarg);
|
||||
# endif
|
||||
exit(-1);
|
||||
}
|
||||
break;
|
||||
case 'L':
|
||||
if (*optarg != '/')
|
||||
if (main_is_empty(optarg))
|
||||
{ /* report about invalid log file */
|
||||
printf("%s: -L: missing logfile value\n", exename, optarg);
|
||||
exit(-1);
|
||||
}
|
||||
else if (*optarg != '/')
|
||||
{
|
||||
if (*optarg == '-')
|
||||
{
|
||||
|
|
44
src/tty.c
44
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
|
||||
|
@ -186,7 +189,26 @@ tty_set_attr(ttydata_t *mod)
|
|||
return RC_ERR;
|
||||
tcflush(mod->fd, TCIOFLUSH);
|
||||
#ifdef TRXCTL
|
||||
tty_clr_rts(mod->fd);
|
||||
tty_set_rx(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)
|
||||
|
@ -443,27 +465,33 @@ void sysfs_gpio_set(char *filename, char *value) {
|
|||
|
||||
}
|
||||
|
||||
/* Set RTS line to active state */
|
||||
/* Set tty device into transmit mode */
|
||||
void
|
||||
tty_set_rts(int fd)
|
||||
tty_set_tx(int fd)
|
||||
{
|
||||
if ( TRX_RTS == cfg.trxcntl ) {
|
||||
if ( TRX_RTS_1 == cfg.trxcntl ) {
|
||||
int mstat = TIOCM_RTS;
|
||||
ioctl(fd, TIOCMBIS, &mstat);
|
||||
} else if ( TRX_SYSFS_1 == cfg.trxcntl) {
|
||||
} else if ( TRX_RTS_0 == cfg.trxcntl ) {
|
||||
int mstat = TIOCM_RTS;
|
||||
ioctl(fd, TIOCMBIC, &mstat);
|
||||
} else if ( TRX_SYSFS_1 == cfg.trxcntl) {
|
||||
sysfs_gpio_set(cfg.trxcntl_file,"1");
|
||||
} else if ( TRX_SYSFS_0 == cfg.trxcntl) {
|
||||
sysfs_gpio_set(cfg.trxcntl_file,"0");
|
||||
}
|
||||
}
|
||||
|
||||
/* Set RTS line to passive state */
|
||||
/* Set tty device into receive mode */
|
||||
void
|
||||
tty_clr_rts(int fd)
|
||||
tty_set_rx(int fd)
|
||||
{
|
||||
if ( TRX_RTS == cfg.trxcntl ) {
|
||||
if ( TRX_RTS_1 == cfg.trxcntl ) {
|
||||
int mstat = TIOCM_RTS;
|
||||
ioctl(fd, TIOCMBIC, &mstat);
|
||||
} else if ( TRX_RTS_0 == cfg.trxcntl ) {
|
||||
int mstat = TIOCM_RTS;
|
||||
ioctl(fd, TIOCMBIS, &mstat);
|
||||
} else if ( TRX_SYSFS_1 == cfg.trxcntl) {
|
||||
sysfs_gpio_set(cfg.trxcntl_file,"0");
|
||||
} else if ( TRX_SYSFS_0 == cfg.trxcntl) {
|
||||
|
|
18
src/tty.h
18
src/tty.h
|
@ -34,6 +34,10 @@
|
|||
#ifndef _TTY_H
|
||||
#define _TTY_H
|
||||
|
||||
#ifdef HAVE_TIOCRS485
|
||||
#include <linux/serial.h>
|
||||
#endif
|
||||
|
||||
#include "globals.h"
|
||||
#include "cfg.h"
|
||||
|
||||
|
@ -73,9 +77,10 @@
|
|||
*/
|
||||
#ifdef TRXCTL
|
||||
#define TRX_ADDC 0
|
||||
#define TRX_RTS 1
|
||||
#define TRX_SYSFS_1 2
|
||||
#define TRX_SYSFS_0 3
|
||||
#define TRX_RTS_1 1
|
||||
#define TRX_RTS_0 2
|
||||
#define TRX_SYSFS_1 3
|
||||
#define TRX_SYSFS_0 4
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -96,6 +101,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
|
||||
|
@ -120,8 +128,8 @@ int tty_set_attr(ttydata_t *mod);
|
|||
speed_t tty_transpeed(int speed);
|
||||
int tty_cooked(ttydata_t *mod);
|
||||
int tty_close(ttydata_t *mod);
|
||||
void tty_set_rts(int fd);
|
||||
void tty_clr_rts(int fd);
|
||||
void tty_set_tx(int fd);
|
||||
void tty_set_rx(int fd);
|
||||
void tty_delay(int usec);
|
||||
|
||||
#endif /* _TTY_H */
|
||||
|
|
|
@ -14,7 +14,7 @@ import logging
|
|||
#---------------------------------------------------------------------------#
|
||||
#from pymodbus.server.async import StartTcpServer
|
||||
#from pymodbus.server.async import StartUdpServer
|
||||
from pymodbus.server.asynchronous import StartSerialServer
|
||||
from pymodbus.server import StartSerialServer
|
||||
|
||||
from pymodbus.device import ModbusDeviceIdentification
|
||||
from pymodbus.datastore import ModbusSequentialDataBlock
|
||||
|
@ -92,7 +92,7 @@ class ModbusSerialServer:
|
|||
hr = ModbusSequentialDataBlock(0, [0]*8), # holding regs
|
||||
ir = ModbusSequentialDataBlock(0, list(range(8))), # input regs
|
||||
zero_mode=True) # request(0-7) will map to the address (0-7)
|
||||
context = ModbusServerContext(slaves=store, single=True)
|
||||
context = ModbusServerContext(slaves={1: store}, single=False)
|
||||
|
||||
#---------------------------------------------------------------------------#
|
||||
# initialize the server information
|
||||
|
@ -112,7 +112,7 @@ class ModbusSerialServer:
|
|||
#---------------------------------------------------------------------------#
|
||||
#StartTcpServer(context, identity=identity, address=("localhost", 5020))
|
||||
#StartUdpServer(context, identity=identity, address=("localhost", 502))
|
||||
StartSerialServer(context, identity=identity, port=self.serialPort, baudrate=19200, framer=framer, broadcast_enable=True)
|
||||
StartSerialServer(context=context, identity=identity, port=self.serialPort, baudrate=19200, framer=framer, broadcast_enable=True)
|
||||
#StartSerialServer(context, identity=identity, port='/dev/pts/3', framer=ModbusAsciiFramer)
|
||||
|
||||
p = None
|
||||
|
|
|
@ -8,7 +8,7 @@ from subprocess import Popen, PIPE, STDOUT
|
|||
from os.path import isfile
|
||||
from time import sleep
|
||||
|
||||
from pymodbus.client.sync import ModbusTcpClient
|
||||
from pymodbus.client import ModbusTcpClient
|
||||
from pymodbus.pdu import ExceptionResponse
|
||||
from pymodbus.bit_read_message import ReadDiscreteInputsResponse, ReadCoilsResponse
|
||||
from pymodbus.bit_write_message import WriteMultipleCoilsResponse, WriteSingleCoilResponse
|
||||
|
@ -62,35 +62,35 @@ class TestModbusRequests(unittest.TestCase):
|
|||
bits = [random.randrange(2)>0 for i in range(8)]
|
||||
|
||||
# 15 Write Multiple Coils
|
||||
result = self.client.write_coils(0, bits, unit=1)
|
||||
result = self.client.write_coils(0, bits, slave=1)
|
||||
self.assertIsInstance(result, WriteMultipleCoilsResponse, result)
|
||||
self.assertEqual(result.address, 0, result)
|
||||
self.assertEqual(result.count, 8, result)
|
||||
|
||||
# 01 Read Coils
|
||||
result = self.client.read_coils(0, 8, unit=1)
|
||||
result = self.client.read_coils(0, 8, slave=1)
|
||||
self.assertIsInstance(result, ReadCoilsResponse, result)
|
||||
self.assertEqual(result.bits, bits, result)
|
||||
|
||||
# 05 Write Single Coil
|
||||
bit1 = not bits[0]
|
||||
result = self.client.write_coil(0, bit1, unit=1)
|
||||
result = self.client.write_coil(0, bit1, slave=1)
|
||||
self.assertIsInstance(result, WriteSingleCoilResponse, result)
|
||||
self.assertEqual(result.address, 0, result)
|
||||
self.assertEqual(result.value, bit1, result)
|
||||
result = self.client.read_coils(0, 1, unit=1)
|
||||
result = self.client.read_coils(0, 1, slave=1)
|
||||
self.assertIsInstance(result, ReadCoilsResponse, result)
|
||||
self.assertEqual(result.bits[0], bit1, result)
|
||||
|
||||
def test_discreteInputs(self):
|
||||
# 02 Read Discrete Inputs
|
||||
result = self.client.read_discrete_inputs(0, 8, unit=1)
|
||||
result = self.client.read_discrete_inputs(0, 8, slave=1)
|
||||
self.assertIsInstance(result, ReadDiscreteInputsResponse, result)
|
||||
self.assertEqual(result.bits, [True]*8, result)
|
||||
|
||||
def test_inputRegisters(self):
|
||||
# 04 Read Input Registers
|
||||
result = self.client.read_input_registers(0, 8, unit=1)
|
||||
result = self.client.read_input_registers(0, 8, slave=1)
|
||||
self.assertIsInstance(result, ReadInputRegistersResponse, result)
|
||||
self.assertEqual(result.registers, list(range(8)), result)
|
||||
|
||||
|
@ -98,28 +98,28 @@ class TestModbusRequests(unittest.TestCase):
|
|||
registers = [random.randrange(8) for i in range(8)]
|
||||
|
||||
# 16 Write Multiple Holding Registers
|
||||
result = self.client.write_registers(0, registers, unit=1)
|
||||
result = self.client.write_registers(0, registers, slave=1)
|
||||
self.assertIsInstance(result, WriteMultipleRegistersResponse, result)
|
||||
self.assertEqual(result.address, 0, result)
|
||||
self.assertEqual(result.count, 8, result)
|
||||
|
||||
# 03 Read Multiple Holding Registers
|
||||
result = self.client.read_holding_registers(0, 8, unit=1)
|
||||
result = self.client.read_holding_registers(0, 8, slave=1)
|
||||
self.assertIsInstance(result, ReadHoldingRegistersResponse, result)
|
||||
self.assertEqual(result.registers, registers, result)
|
||||
|
||||
# 06 Write Single Holding Register
|
||||
register1 = (registers[0] + 1) % 65535
|
||||
result = self.client.write_register(0, register1, unit=1)
|
||||
result = self.client.write_register(0, register1, slave=1)
|
||||
self.assertIsInstance(result, WriteSingleRegisterResponse, result)
|
||||
self.assertEqual(result.address, 0, result)
|
||||
self.assertEqual(result.value, register1, result)
|
||||
result = self.client.read_holding_registers(0, 1, unit=1)
|
||||
result = self.client.read_holding_registers(0, 1, slave=1)
|
||||
self.assertIsInstance(result, ReadHoldingRegistersResponse, result)
|
||||
self.assertEqual(result.registers[0], register1, result)
|
||||
|
||||
def test_exception(self):
|
||||
result = self.client.write_coil(1000, False, unit=1) # invalid address 1000
|
||||
result = self.client.write_coil(1000, False, slave=1) # invalid address 1000
|
||||
self.assertIsInstance(result, ExceptionResponse, result)
|
||||
self.assertEqual(result.original_code, 5, result) # fc05 Write Single Coil
|
||||
self.assertEqual(result.exception_code, 2, result) # Illegal Data Address
|
||||
|
@ -127,10 +127,10 @@ class TestModbusRequests(unittest.TestCase):
|
|||
def test_broadcast(self):
|
||||
registers = [random.randrange(8) for i in range(8)]
|
||||
# 16 Write Multiple Holding Registers
|
||||
result = self.client.write_registers(0, registers, unit=0)
|
||||
result = self.client.write_registers(0, registers, slave=0)
|
||||
|
||||
# 03 Read Multiple Holding Registers
|
||||
result = self.client.read_holding_registers(0, 8, unit=1)
|
||||
result = self.client.read_holding_registers(0, 8, slave=1)
|
||||
self.assertIsInstance(result, ReadHoldingRegistersResponse, result)
|
||||
self.assertEqual(result.registers, registers, result)
|
||||
|
||||
|
|
Loading…
Reference in New Issue