mirror of
https://github.com/3cky/mbusd.git
synced 2024-09-26 03:43:04 +02:00
Add support for read configuration from file
This commit is contained in:
parent
7fb5309551
commit
3ea208491a
36
.cproject
36
.cproject
@ -1,7 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<?fileVersion 4.0.0?>
|
||||
|
||||
<cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
|
||||
<?fileVersion 4.0.0?><cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
|
||||
<storageModule moduleId="org.eclipse.cdt.core.settings">
|
||||
<cconfiguration id="cdt.managedbuild.toolchain.gnu.base.1826992774">
|
||||
<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.toolchain.gnu.base.1826992774" moduleId="org.eclipse.cdt.core.settings" name="Default">
|
||||
@ -16,17 +14,28 @@
|
||||
</extensions>
|
||||
</storageModule>
|
||||
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
|
||||
<configuration buildProperties="" id="cdt.managedbuild.toolchain.gnu.base.1826992774" name="Default" parent="org.eclipse.cdt.build.core.emptycfg">
|
||||
<configuration buildProperties="" description="" id="cdt.managedbuild.toolchain.gnu.base.1826992774" name="Default" parent="org.eclipse.cdt.build.core.emptycfg">
|
||||
<folderInfo id="cdt.managedbuild.toolchain.gnu.base.1826992774.1618506567" name="/" resourcePath="">
|
||||
<toolChain id="cdt.managedbuild.toolchain.gnu.base.1143041813" name="cdt.managedbuild.toolchain.gnu.base" superClass="cdt.managedbuild.toolchain.gnu.base">
|
||||
<targetPlatform archList="all" binaryParser="org.eclipse.cdt.core.ELF" id="cdt.managedbuild.target.gnu.platform.base.781693864" name="Debug Platform" osList="linux,hpux,aix,qnx" superClass="cdt.managedbuild.target.gnu.platform.base"/>
|
||||
<builder id="cdt.managedbuild.target.gnu.builder.base.751022712" managedBuildOn="false" name="Gnu Make Builder.Default" superClass="cdt.managedbuild.target.gnu.builder.base"/>
|
||||
<builder id="cdt.managedbuild.target.gnu.builder.base.751022712" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="Gnu Make Builder" superClass="cdt.managedbuild.target.gnu.builder.base"/>
|
||||
<tool id="cdt.managedbuild.tool.gnu.archiver.base.1388164087" name="GCC Archiver" superClass="cdt.managedbuild.tool.gnu.archiver.base"/>
|
||||
<tool id="cdt.managedbuild.tool.gnu.cpp.compiler.base.1875165406" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.base"/>
|
||||
<tool id="cdt.managedbuild.tool.gnu.c.compiler.base.1454341581" name="GCC C Compiler" superClass="cdt.managedbuild.tool.gnu.c.compiler.base"/>
|
||||
<tool id="cdt.managedbuild.tool.gnu.cpp.compiler.base.1875165406" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.base">
|
||||
<inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.437218346" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/>
|
||||
</tool>
|
||||
<tool id="cdt.managedbuild.tool.gnu.c.compiler.base.1454341581" name="GCC C Compiler" superClass="cdt.managedbuild.tool.gnu.c.compiler.base">
|
||||
<inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.722267304" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/>
|
||||
</tool>
|
||||
<tool id="cdt.managedbuild.tool.gnu.c.linker.base.2010478517" name="GCC C Linker" superClass="cdt.managedbuild.tool.gnu.c.linker.base"/>
|
||||
<tool id="cdt.managedbuild.tool.gnu.cpp.linker.base.970100266" name="GCC C++ Linker" superClass="cdt.managedbuild.tool.gnu.cpp.linker.base"/>
|
||||
<tool id="cdt.managedbuild.tool.gnu.assembler.base.27610334" name="GCC Assembler" superClass="cdt.managedbuild.tool.gnu.assembler.base"/>
|
||||
<tool id="cdt.managedbuild.tool.gnu.cpp.linker.base.970100266" name="GCC C++ Linker" superClass="cdt.managedbuild.tool.gnu.cpp.linker.base">
|
||||
<inputType id="cdt.managedbuild.tool.gnu.cpp.linker.input.177254843" superClass="cdt.managedbuild.tool.gnu.cpp.linker.input">
|
||||
<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
|
||||
<additionalInput kind="additionalinput" paths="$(LIBS)"/>
|
||||
</inputType>
|
||||
</tool>
|
||||
<tool id="cdt.managedbuild.tool.gnu.assembler.base.27610334" name="GCC Assembler" superClass="cdt.managedbuild.tool.gnu.assembler.base">
|
||||
<inputType id="cdt.managedbuild.tool.gnu.assembler.input.285918871" superClass="cdt.managedbuild.tool.gnu.assembler.input"/>
|
||||
</tool>
|
||||
</toolChain>
|
||||
</folderInfo>
|
||||
</configuration>
|
||||
@ -37,8 +46,15 @@
|
||||
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
|
||||
<project id="mbus.null.914501471" name="mbus"/>
|
||||
</storageModule>
|
||||
<storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/>
|
||||
<storageModule moduleId="refreshScope"/>
|
||||
<storageModule moduleId="scannerConfiguration">
|
||||
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
|
||||
<scannerConfigBuildInfo instanceId="cdt.managedbuild.toolchain.gnu.base.1826992774;cdt.managedbuild.toolchain.gnu.base.1826992774.1618506567;cdt.managedbuild.tool.gnu.cpp.compiler.base.1875165406;cdt.managedbuild.tool.gnu.cpp.compiler.input.437218346">
|
||||
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
|
||||
</scannerConfigBuildInfo>
|
||||
<scannerConfigBuildInfo instanceId="cdt.managedbuild.toolchain.gnu.base.1826992774;cdt.managedbuild.toolchain.gnu.base.1826992774.1618506567;cdt.managedbuild.tool.gnu.c.compiler.base.1454341581;cdt.managedbuild.tool.gnu.c.compiler.input.722267304">
|
||||
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
|
||||
</scannerConfigBuildInfo>
|
||||
</storageModule>
|
||||
<storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/>
|
||||
</cproject>
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -11,3 +11,4 @@ Makefile
|
||||
*.log
|
||||
*.in~
|
||||
systemd-units/mbusd@.service
|
||||
*.conf
|
||||
|
@ -4,13 +4,17 @@ ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
SUBDIRS = src doc
|
||||
|
||||
mbusddocdir = ${prefix}/doc/mbusd
|
||||
mbusddocdir = ${docdir}
|
||||
mbusddoc_DATA = \
|
||||
README.md\
|
||||
CHANGELOG.md\
|
||||
LICENSE
|
||||
|
||||
EXTRA_DIST = $(mbusddoc_DATA)
|
||||
mbusdconfdir = ${mbusddocdir}
|
||||
mbusdconf_DATA = \
|
||||
conf/mbusd.conf.example
|
||||
|
||||
EXTRA_DIST = $(mbusddoc_DATA) $(mbusdconf_DATA)
|
||||
|
||||
# Copy all the spec files. Of cource, only one is actually used.
|
||||
dist-hook:
|
||||
@ -34,4 +38,3 @@ $(systemdsystemunit_DATA):
|
||||
distclean-local::
|
||||
-$(RM) $(systemdsystemunit_DATA)
|
||||
endif
|
||||
|
||||
|
56
Makefile.in
56
Makefile.in
@ -158,9 +158,9 @@ am__uninstall_files_from_dir = { \
|
||||
|| { echo " ( cd '$$dir' && rm -f" $$files ")"; \
|
||||
$(am__cd) "$$dir" && rm -f $$files; }; \
|
||||
}
|
||||
am__installdirs = "$(DESTDIR)$(mbusddocdir)" \
|
||||
"$(DESTDIR)$(systemdsystemunitdir)"
|
||||
DATA = $(mbusddoc_DATA) $(systemdsystemunit_DATA)
|
||||
am__installdirs = "$(DESTDIR)$(mbusdconfdir)" \
|
||||
"$(DESTDIR)$(mbusddocdir)" "$(DESTDIR)$(systemdsystemunitdir)"
|
||||
DATA = $(mbusdconf_DATA) $(mbusddoc_DATA) $(systemdsystemunit_DATA)
|
||||
RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
|
||||
distclean-recursive maintainer-clean-recursive
|
||||
am__recursive_targets = \
|
||||
@ -367,13 +367,17 @@ top_builddir = @top_builddir@
|
||||
top_srcdir = @top_srcdir@
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
SUBDIRS = src doc
|
||||
mbusddocdir = ${prefix}/doc/mbusd
|
||||
mbusddocdir = ${docdir}
|
||||
mbusddoc_DATA = \
|
||||
README.md\
|
||||
CHANGELOG.md\
|
||||
LICENSE
|
||||
|
||||
EXTRA_DIST = $(mbusddoc_DATA)
|
||||
mbusdconfdir = ${mbusddocdir}
|
||||
mbusdconf_DATA = \
|
||||
conf/mbusd.conf.example
|
||||
|
||||
EXTRA_DIST = $(mbusddoc_DATA) $(mbusdconf_DATA)
|
||||
|
||||
# systemd
|
||||
AM_DISTCHECK_CONFIGURE_FLAGS = \
|
||||
@ -443,6 +447,27 @@ clean-libtool:
|
||||
|
||||
distclean-libtool:
|
||||
-rm -f libtool config.lt
|
||||
install-mbusdconfDATA: $(mbusdconf_DATA)
|
||||
@$(NORMAL_INSTALL)
|
||||
@list='$(mbusdconf_DATA)'; test -n "$(mbusdconfdir)" || list=; \
|
||||
if test -n "$$list"; then \
|
||||
echo " $(MKDIR_P) '$(DESTDIR)$(mbusdconfdir)'"; \
|
||||
$(MKDIR_P) "$(DESTDIR)$(mbusdconfdir)" || exit 1; \
|
||||
fi; \
|
||||
for p in $$list; do \
|
||||
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
|
||||
echo "$$d$$p"; \
|
||||
done | $(am__base_list) | \
|
||||
while read files; do \
|
||||
echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(mbusdconfdir)'"; \
|
||||
$(INSTALL_DATA) $$files "$(DESTDIR)$(mbusdconfdir)" || exit $$?; \
|
||||
done
|
||||
|
||||
uninstall-mbusdconfDATA:
|
||||
@$(NORMAL_UNINSTALL)
|
||||
@list='$(mbusdconf_DATA)'; test -n "$(mbusdconfdir)" || list=; \
|
||||
files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
|
||||
dir='$(DESTDIR)$(mbusdconfdir)'; $(am__uninstall_files_from_dir)
|
||||
install-mbusddocDATA: $(mbusddoc_DATA)
|
||||
@$(NORMAL_INSTALL)
|
||||
@list='$(mbusddoc_DATA)'; test -n "$(mbusddocdir)" || list=; \
|
||||
@ -788,7 +813,7 @@ check: check-recursive
|
||||
all-am: Makefile $(DATA) config.h
|
||||
installdirs: installdirs-recursive
|
||||
installdirs-am:
|
||||
for dir in "$(DESTDIR)$(mbusddocdir)" "$(DESTDIR)$(systemdsystemunitdir)"; do \
|
||||
for dir in "$(DESTDIR)$(mbusdconfdir)" "$(DESTDIR)$(mbusddocdir)" "$(DESTDIR)$(systemdsystemunitdir)"; do \
|
||||
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
|
||||
done
|
||||
install: install-recursive
|
||||
@ -844,7 +869,8 @@ info: info-recursive
|
||||
|
||||
info-am:
|
||||
|
||||
install-data-am: install-mbusddocDATA install-systemdsystemunitDATA
|
||||
install-data-am: install-mbusdconfDATA install-mbusddocDATA \
|
||||
install-systemdsystemunitDATA
|
||||
|
||||
install-dvi: install-dvi-recursive
|
||||
|
||||
@ -890,7 +916,8 @@ ps: ps-recursive
|
||||
|
||||
ps-am:
|
||||
|
||||
uninstall-am: uninstall-mbusddocDATA uninstall-systemdsystemunitDATA
|
||||
uninstall-am: uninstall-mbusdconfDATA uninstall-mbusddocDATA \
|
||||
uninstall-systemdsystemunitDATA
|
||||
|
||||
.MAKE: $(am__recursive_targets) all install-am install-strip
|
||||
|
||||
@ -905,12 +932,13 @@ uninstall-am: uninstall-mbusddocDATA uninstall-systemdsystemunitDATA
|
||||
install install-am install-data install-data-am install-dvi \
|
||||
install-dvi-am install-exec install-exec-am install-html \
|
||||
install-html-am install-info install-info-am install-man \
|
||||
install-mbusddocDATA install-pdf install-pdf-am install-ps \
|
||||
install-ps-am install-strip install-systemdsystemunitDATA \
|
||||
installcheck installcheck-am installdirs installdirs-am \
|
||||
maintainer-clean maintainer-clean-generic mostlyclean \
|
||||
mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
|
||||
tags tags-am uninstall uninstall-am uninstall-mbusddocDATA \
|
||||
install-mbusdconfDATA install-mbusddocDATA install-pdf \
|
||||
install-pdf-am install-ps install-ps-am install-strip \
|
||||
install-systemdsystemunitDATA installcheck installcheck-am \
|
||||
installdirs installdirs-am maintainer-clean \
|
||||
maintainer-clean-generic mostlyclean mostlyclean-generic \
|
||||
mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
|
||||
uninstall-am uninstall-mbusdconfDATA uninstall-mbusddocDATA \
|
||||
uninstall-systemdsystemunitDATA
|
||||
|
||||
.PRECIOUS: Makefile
|
||||
|
46
README.md
46
README.md
@ -47,20 +47,15 @@ Usage:
|
||||
|
||||
-h Usage help.
|
||||
-d Instruct mbusd not to fork itself (non-daemonize).
|
||||
-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
|
||||
-L logfile
|
||||
Specifies log file name ('-' for logging to STDOUT only, default is /var/log/mbusd.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.
|
||||
-L logfile
|
||||
Specifies log file name ('-' for logging to STDOUT only, default is /var/log/mbusd.log).
|
||||
-c cfgfile
|
||||
Read configuration from cfgfile.
|
||||
-p device
|
||||
Specifies serial port device name.
|
||||
-s speed
|
||||
@ -69,6 +64,13 @@ Usage:
|
||||
Specifies serial port mode (like 8N1).
|
||||
-P port
|
||||
Specifies TCP port number (default 502).
|
||||
-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
|
||||
-C maxconn
|
||||
Specifies maximum number of simultaneous TCP connections.
|
||||
-N retries
|
||||
@ -82,16 +84,28 @@ Usage:
|
||||
|
||||
Please note running **mbusd** on default Modbus TCP port (502) requires root privileges!
|
||||
|
||||
Configuration file:
|
||||
-------------------
|
||||
**mbusd** can read the configuration from a file specified by `-c` command line flag.
|
||||
Please see [example configuration file](conf/mbusd.conf.example)
|
||||
for complete list of available configuration options.
|
||||
|
||||
systemd:
|
||||
---------------
|
||||
|
||||
**mbusd** has [systemd](https://wiki.archlinux.org/index.php/systemd) support. The build system detects whether the system has systemd after which `sudo make install` installs the `mbusd@.service` file on systems with systemd active.
|
||||
**mbusd** has [systemd](https://wiki.archlinux.org/index.php/systemd) support.
|
||||
The build system detects whether the system has systemd after which `sudo make install`
|
||||
installs the `mbusd@.service` file on systems with systemd active.
|
||||
|
||||
The **mbusd** service can be started via:
|
||||
|
||||
# systemctl start mbusd@<serial port>.service
|
||||
|
||||
where `<serial port>` is serial port device name (like `ttyUSB0`).
|
||||
|
||||
**mbusd** started by systemd will read its configuration from file named `/etc/mbusd/mbusd-<serial port>.conf`.
|
||||
This way it's possible to run multiple **mbusd** instances with different configurations.
|
||||
|
||||
To see the **mbusd** service status:
|
||||
|
||||
# systemctl status mbusd@<serial port>.service
|
||||
@ -106,12 +120,6 @@ To start the **mbusd** service on system boot:
|
||||
|
||||
Please check systemd documentation for other usefull systemd [commands](https://wiki.archlinux.org/index.php/systemd)
|
||||
|
||||
The checked in `mbusd@.service` starts **mbusd** equivalent to the following command:
|
||||
|
||||
# $PREFIX/bin/mbusd -p /dev/<serial port> -s 9600 -m 8N1 -P 502 -d -v2
|
||||
|
||||
Feel free to modify the service file locally with your own desired configuration.
|
||||
|
||||
Reporting bugs:
|
||||
---------------
|
||||
|
||||
@ -119,7 +127,8 @@ Please file [issue](https://github.com/3cky/mbusd/issues) with attached debug lo
|
||||
|
||||
# mbusd -L/tmp/mbusd.log -p /dev/ttyUSB0 -s 9600 -P 502 -d -v9
|
||||
|
||||
Unless you were prompted so or there is another pertinent reason (e.g. GitHub fails to accept the bug report), please do not send bug reports via personal email.
|
||||
Unless you were prompted so or there is another pertinent reason (e.g. GitHub fails to accept the bug report),
|
||||
please do not send bug reports via personal email.
|
||||
|
||||
Contributing:
|
||||
-------------
|
||||
@ -146,6 +155,9 @@ Andrew Denysenko (<nitr0@seti.kr.ua>):
|
||||
James Jarvis (<jj@aprsworld.com>):
|
||||
- file based RS-485 data direction control
|
||||
|
||||
Luuk Loeffen (<luukloeffen@hotmail.com>):
|
||||
- systemd support
|
||||
|
||||
License:
|
||||
--------
|
||||
|
||||
|
44
conf/mbusd.conf.example
Normal file
44
conf/mbusd.conf.example
Normal file
@ -0,0 +1,44 @@
|
||||
#############################################
|
||||
# #
|
||||
# Sample configuration file for mbusd #
|
||||
# #
|
||||
#############################################
|
||||
|
||||
########## Serial port settings #############
|
||||
|
||||
# Serial port device name
|
||||
device = /dev/ttyS0
|
||||
|
||||
# Serial port speed
|
||||
speed = 9600
|
||||
|
||||
# Serial port mode
|
||||
mode = 8n1
|
||||
|
||||
# RS-485 data direction control type (addc, rts, sysfs_0, sysfs_1)
|
||||
trx_control = addc
|
||||
|
||||
# Sysfs file to use to control data direction
|
||||
# trx_sysfile =
|
||||
|
||||
############# TCP port settings #############
|
||||
|
||||
# TCP server port number
|
||||
port = 502
|
||||
|
||||
# Maximum number of simultaneous TCP connections
|
||||
maxconn = 32
|
||||
|
||||
# Connection timeout value in seconds
|
||||
timeout = 60
|
||||
|
||||
######### Request/response settings #########
|
||||
|
||||
# Maximum number of request retries
|
||||
retries = 3
|
||||
|
||||
# Pause between requests in milliseconds
|
||||
pause = 100
|
||||
|
||||
# Response wait time in milliseconds
|
||||
wait = 500
|
@ -5,21 +5,23 @@ mbusd \- MODBUS/TCP to MODBUS/RTU gateway.
|
||||
.B mbusd
|
||||
.RB [ -h ]
|
||||
.RB [ -d ]
|
||||
.RB [ -t ]
|
||||
.RB [ -y
|
||||
.IR file ]
|
||||
.RB [ -Y
|
||||
.IR file ]
|
||||
.RB [ -v
|
||||
.IR level ]
|
||||
.RB [ -L
|
||||
.IR logfile ]
|
||||
.RB [ -v
|
||||
.IR level ]
|
||||
.RB [ -c
|
||||
.IR cfgfile ]
|
||||
.RB [ -p
|
||||
.IR device ]
|
||||
.RB [ -s
|
||||
.IR speed ]
|
||||
.RB [ -m
|
||||
.IR mode ]
|
||||
.RB [ -t ]
|
||||
.RB [ -y
|
||||
.IR file ]
|
||||
.RB [ -Y
|
||||
.IR file ]
|
||||
.RB [ -P
|
||||
.IR port ]
|
||||
.RB [ -C
|
||||
@ -39,22 +41,16 @@ mbusd \- MODBUS/TCP to MODBUS/RTU gateway.
|
||||
Usage help.
|
||||
.IP \fB-d\fR
|
||||
Instruct \fImbusd\fR not to fork itself (non-daemonize).
|
||||
.IP \fB-t\fR
|
||||
Enable RTS RS-485 data direction control (if not disabled while compile).
|
||||
.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
|
||||
.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
|
||||
.IP "\fB-L \fIlogfile\fR"
|
||||
Specifies log file name ('-' for logging to STDOUT only, default is /var/log/mbusd.log).
|
||||
.IP "\fB-v \fIlevel\fR"
|
||||
Specifies log verbosity level. 0 enables logging of errors only,
|
||||
1 also enables warnings and 2 enables information messages.
|
||||
If \fImbusd\fR 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.
|
||||
.IP "\fB-L \fIlogfile\fR"
|
||||
Specifies log file name ('-' for logging to STDOUT only, default is /var/log/mbusd.log).
|
||||
.IP "\fB-c \fIcfgfile\fR"
|
||||
Read configuration from cfgfile.
|
||||
.IP "\fB-p \fIdevice\fR"
|
||||
Specifies serial port device name.
|
||||
.IP "\fB-s \fIspeed\fR"
|
||||
@ -63,6 +59,14 @@ Specifies serial port speed.
|
||||
Specifies serial port mode (like 8N1).
|
||||
.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).
|
||||
.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
|
||||
.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
|
||||
.IP "\fB-C \fImaxconn\fR"
|
||||
Specifies maximum number of simultaneous TCP connections.
|
||||
.IP "\fB-N \fIretries\fR"
|
||||
|
231
src/cfg.c
231
src/cfg.c
@ -33,9 +33,23 @@
|
||||
|
||||
#include "cfg.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
#define CFG_MAX_LINE_LENGTH 200
|
||||
|
||||
#define CFG_NAME_MATCH(n) strcmp(n, name) == 0
|
||||
#define CFG_VALUE_MATCH(n) strcasecmp(n, value) == 0
|
||||
|
||||
/* Global configuration storage variable */
|
||||
cfg_t cfg;
|
||||
|
||||
/* Configuration error message */
|
||||
char cfg_err[INTBUFSIZE + 1];
|
||||
|
||||
#define CFG_ERR(s, v) snprintf(cfg_err, INTBUFSIZE, s, v)
|
||||
|
||||
/*
|
||||
* Setting up config defaults
|
||||
*/
|
||||
@ -48,9 +62,10 @@ cfg_init(void)
|
||||
#endif
|
||||
strncpy(cfg.ttyport, DEFAULT_PORT, INTBUFSIZE);
|
||||
cfg.ttyspeed = DEFAULT_SPEED;
|
||||
cfg.ttymode = DEFAULT_MODE;
|
||||
strncpy(cfg.ttymode, DEFAULT_MODE, INTBUFSIZE);
|
||||
#ifdef TRXCTL
|
||||
cfg.trxcntl = TRX_ADDC;
|
||||
*cfg.trxcntl_file = '\0';
|
||||
#endif
|
||||
cfg.serverport = DEFAULT_SERVERPORT;
|
||||
cfg.maxconn = DEFAULT_MAXCONN;
|
||||
@ -60,3 +75,217 @@ cfg_init(void)
|
||||
cfg.resppause = DV(3, cfg.ttyspeed);
|
||||
cfg.conntimeout = DEFAULT_CONNTIMEOUT;
|
||||
}
|
||||
|
||||
static char *
|
||||
cfg_rtrim(char *s)
|
||||
{
|
||||
char *p = s + strlen(s);
|
||||
while (p > s && isspace((unsigned char )(*--p)))
|
||||
*p = '\0';
|
||||
return s;
|
||||
}
|
||||
|
||||
static char *
|
||||
cfg_ltrim(const char *s)
|
||||
{
|
||||
while (*s && isspace((unsigned char )(*s)))
|
||||
s++;
|
||||
return (char *) s;
|
||||
}
|
||||
|
||||
int
|
||||
cfg_handle_param(char *name, char *value)
|
||||
{
|
||||
if (CFG_NAME_MATCH("device"))
|
||||
{
|
||||
strncpy(cfg.ttyport, value, INTBUFSIZE);
|
||||
}
|
||||
else if (CFG_NAME_MATCH("speed"))
|
||||
{
|
||||
cfg.ttyspeed = strtoul(value, NULL, 0);
|
||||
}
|
||||
else if (CFG_NAME_MATCH("mode"))
|
||||
{
|
||||
int mode_invalid;
|
||||
if (strlen(value) != 3)
|
||||
mode_invalid = 1;
|
||||
else
|
||||
{
|
||||
char parity = toupper(value[1]);
|
||||
mode_invalid = value[0] != '8' || (value[2] != '1' && value[2] != '2') ||
|
||||
(parity != 'N' && parity != 'E' && parity != 'O');
|
||||
}
|
||||
if (mode_invalid)
|
||||
{
|
||||
CFG_ERR("invalid device mode: %s", value);
|
||||
return 0;
|
||||
}
|
||||
strncpy(cfg.ttymode, value, INTBUFSIZE);
|
||||
}
|
||||
else if (CFG_NAME_MATCH("port"))
|
||||
{
|
||||
cfg.serverport = strtoul(value, NULL, 0);
|
||||
}
|
||||
else if (CFG_NAME_MATCH("maxconn"))
|
||||
{
|
||||
cfg.maxconn = strtoul(value, NULL, 0);
|
||||
if (cfg.maxconn < 1 || cfg.maxconn > MAX_MAXCONN)
|
||||
{
|
||||
CFG_ERR("invalid maxconn value: %s", value);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else if (CFG_NAME_MATCH("retries"))
|
||||
{
|
||||
cfg.maxtry = strtoul(value, NULL, 0);
|
||||
if (cfg.maxtry > MAX_MAXTRY)
|
||||
{
|
||||
CFG_ERR("invalid retries value: %s", value);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else if (CFG_NAME_MATCH("pause"))
|
||||
{
|
||||
cfg.rqstpause = strtoul(value, NULL, 0);
|
||||
if (cfg.rqstpause < 1 || cfg.rqstpause > MAX_RQSTPAUSE)
|
||||
{
|
||||
CFG_ERR("invalid pause value: %s", value);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else if (CFG_NAME_MATCH("wait"))
|
||||
{
|
||||
cfg.respwait = strtoul(value, NULL, 0);
|
||||
if (cfg.respwait < 1 || cfg.respwait > MAX_RESPWAIT)
|
||||
{
|
||||
CFG_ERR("invalid wait value: %s", value);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else if (CFG_NAME_MATCH("timeout"))
|
||||
{
|
||||
cfg.conntimeout = strtoul(value, NULL, 0);
|
||||
if (cfg.conntimeout > MAX_CONNTIMEOUT)
|
||||
return 0;
|
||||
#ifdef TRXCTL
|
||||
}
|
||||
else if (CFG_NAME_MATCH("trx_control"))
|
||||
{
|
||||
if (CFG_VALUE_MATCH("addc"))
|
||||
{
|
||||
cfg.trxcntl = TRX_ADDC;
|
||||
}
|
||||
else if (CFG_VALUE_MATCH("rts"))
|
||||
{
|
||||
cfg.trxcntl = TRX_RTS;
|
||||
}
|
||||
else if (CFG_VALUE_MATCH("sysfs_0"))
|
||||
{
|
||||
cfg.trxcntl = TRX_SYSFS_0;
|
||||
}
|
||||
else if (CFG_VALUE_MATCH("sysfs_1"))
|
||||
{
|
||||
cfg.trxcntl = TRX_SYSFS_1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Unknown TRX control mode */
|
||||
CFG_ERR("unknown trx control mode: %s", value);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else if (CFG_NAME_MATCH("trx_sysfile"))
|
||||
{
|
||||
strncpy(cfg.trxcntl_file, value, INTBUFSIZE);
|
||||
#endif
|
||||
#ifdef LOG
|
||||
}
|
||||
else if (CFG_NAME_MATCH("loglevel"))
|
||||
{
|
||||
cfg.dbglvl = (char)strtol(optarg, NULL, 0);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
/* Unknown parameter name */
|
||||
CFG_ERR("unknown parameter: %s", name);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
cfg_parse_file(void *file)
|
||||
{
|
||||
char *line;
|
||||
char *start;
|
||||
char *end;
|
||||
char *name;
|
||||
char *value;
|
||||
int lineno = 0;
|
||||
int error = 0;
|
||||
|
||||
*cfg_err = '\0';
|
||||
|
||||
line = (char *) malloc(CFG_MAX_LINE_LENGTH);
|
||||
if (!line)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (fgets(line, CFG_MAX_LINE_LENGTH, file) != NULL)
|
||||
{
|
||||
lineno++;
|
||||
|
||||
start = cfg_ltrim(cfg_rtrim(line));
|
||||
|
||||
if (*start == '#')
|
||||
{
|
||||
/* skip comment */
|
||||
continue;
|
||||
}
|
||||
else if (*start)
|
||||
{
|
||||
/* parse `name=value` pair */
|
||||
for (end = start; *end && *end != '='; end++);
|
||||
if (*end == '=')
|
||||
{
|
||||
*end = '\0';
|
||||
|
||||
name = cfg_rtrim(start);
|
||||
value = cfg_ltrim(cfg_rtrim(end + 1));
|
||||
|
||||
/* handle name/value pair */
|
||||
if (!cfg_handle_param(name, value))
|
||||
{
|
||||
error = lineno;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no '=' found on config line */
|
||||
error = lineno;
|
||||
CFG_ERR("can't parse line: %s", start);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free(line);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
int
|
||||
cfg_read_file(const char *filename)
|
||||
{
|
||||
FILE* file;
|
||||
int error;
|
||||
|
||||
file = fopen(filename, "r");
|
||||
if (!file)
|
||||
return -1;
|
||||
error = cfg_parse_file(file);
|
||||
fclose(file);
|
||||
return error;
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ typedef struct
|
||||
/* tty speed */
|
||||
int ttyspeed;
|
||||
/* tty mode */
|
||||
char *ttymode;
|
||||
char ttymode[INTBUFSIZE + 1];
|
||||
/* 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 */
|
||||
@ -76,6 +76,8 @@ typedef struct
|
||||
|
||||
/* Prototypes */
|
||||
extern cfg_t cfg;
|
||||
extern char cfg_err[];
|
||||
void cfg_init(void);
|
||||
int cfg_read_file(const char *filename);
|
||||
|
||||
#endif /* _CFG_H */
|
||||
|
25
src/conn.h
25
src/conn.h
@ -53,6 +53,31 @@
|
||||
#define DEFAULT_RESPWAIT 500
|
||||
#define DEFAULT_CONNTIMEOUT 60
|
||||
|
||||
/* Max simultaneous TCP connections to server */
|
||||
#ifndef MAX_MAXCONN
|
||||
# define MAX_MAXCONN 128
|
||||
#endif
|
||||
|
||||
/* Max RTU device request retries */
|
||||
#ifndef MAX_MAXTRY
|
||||
# define MAX_MAXTRY 15
|
||||
#endif
|
||||
|
||||
/* Max RTU device pause between requests, in msecs */
|
||||
#ifndef MAX_RQSTPAUSE
|
||||
# define MAX_RQSTPAUSE 10000
|
||||
#endif
|
||||
|
||||
/* Max RTU device response wait, in msecs */
|
||||
#ifndef MAX_RESPWAIT
|
||||
# define MAX_RESPWAIT 10000
|
||||
#endif
|
||||
|
||||
/* Max connection timeout, in secs */
|
||||
#ifndef MAX_CONNTIMEOUT
|
||||
# define MAX_CONNTIMEOUT 1000
|
||||
#endif
|
||||
|
||||
#define CRCSIZE 2 /* size (in bytes) of CRC */
|
||||
#define HDRSIZE 6 /* size (in bytes) of header */
|
||||
#define BUFSIZE 256 /* size (in bytes) of MODBUS data */
|
||||
|
95
src/main.c
95
src/main.c
@ -100,62 +100,70 @@ void
|
||||
usage(char *exename)
|
||||
{
|
||||
cfg_init();
|
||||
printf("%s-%s Copyright (C) 2002-2003, 2011, 2013-2016 Victor Antonovich <v.antonovich@gmail.com>, "
|
||||
printf("%s-%s Copyright (C) 2002-2003, 2011, 2013-2017 Victor Antonovich <v.antonovich@gmail.com>, "
|
||||
"Andrew Denysenko <nitr0@seti.kr.ua>\n\n"
|
||||
"Usage: %s [-h] [-d] "
|
||||
#ifdef TRXCTL
|
||||
"[-t] [-y sysfsfile] [-Y sysfsfile]\n"
|
||||
#ifdef LOG
|
||||
"[-L logfile] [-v level] "
|
||||
#endif
|
||||
"[-v level] [-L logfile] [-p device] [-s speed] [-m mode] [-P port]\n"
|
||||
" [-C maxconn] [-N retries] [-R pause] [-W wait] [-T timeout]\n\n"
|
||||
"[-c cfgfile] \n"
|
||||
" [-p device] [-s speed] [-m mode]\n"
|
||||
#ifdef TRXCTL
|
||||
" [-t] [-y sysfsfile] [-Y sysfsfile]\n"
|
||||
#endif
|
||||
" [-P port] [-C maxconn] [-N retries] [-R pause] [-W wait] [-T timeout]\n\n"
|
||||
"Options:\n"
|
||||
" -h : this help\n"
|
||||
" -d : don't daemonize\n"
|
||||
#ifdef TRXCTL
|
||||
" -t : enable RTS RS-485 data direction control using RTS\n"
|
||||
" -y : enable RTS RS-485 data direction control using sysfs file, active transmit\n"
|
||||
" -Y : enable RTS RS-485 data direction control using sysfs file, active receive\n"
|
||||
#endif
|
||||
#ifdef LOG
|
||||
" -L logfile : set log file name (default %s%s, \n"
|
||||
" '-' for logging to STDOUT only)\n"
|
||||
#ifdef DEBUG
|
||||
" -v level : set log level (0-9, default %d, 0 - errors only)\n"
|
||||
#else
|
||||
" -v level : set log level (0-2, default %d, 0 - errors only)\n"
|
||||
#endif
|
||||
" -L logfile : set log file name (default %s%s, \n"
|
||||
" '-' for logging to STDOUT only)\n"
|
||||
#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"
|
||||
" -P port : set TCP server port number (default %d)\n"
|
||||
#ifdef TRXCTL
|
||||
" -t : enable RTS RS-485 data direction control using RTS\n"
|
||||
" -y : enable RTS RS-485 data direction control using sysfs file, active transmit\n"
|
||||
" -Y : enable RTS RS-485 data direction control using sysfs file, active receive\n"
|
||||
#endif
|
||||
" -C maxconn : set maximum number of simultaneous TCP connections\n"
|
||||
" (1-128, default %d)\n"
|
||||
" (1-%d, default %d)\n"
|
||||
" -N retries : set maximum number of request retries\n"
|
||||
" (0-15, default %d, 0 - without retries)\n"
|
||||
" (0-%d, default %d, 0 - without retries)\n"
|
||||
" -R pause : set pause between requests in milliseconds\n"
|
||||
" (1-10000, default %lu)\n"
|
||||
" (1-%d, default %lu)\n"
|
||||
" -W wait : set response wait time in milliseconds\n"
|
||||
" (1-10000, default %lu)\n"
|
||||
" (1-%d, default %lu)\n"
|
||||
" -T timeout : set connection timeout value in seconds\n"
|
||||
" (0-1000, default %d, 0 - no timeout)"
|
||||
" (0-%d, default %d, 0 - no timeout)"
|
||||
"\n", PACKAGE, VERSION, exename,
|
||||
#ifdef LOG
|
||||
cfg.dbglvl, LOGPATH, LOGNAME,
|
||||
LOGPATH, LOGNAME, cfg.dbglvl,
|
||||
#endif
|
||||
cfg.ttyport, cfg.ttyspeed, cfg.ttymode, cfg.serverport, cfg.maxconn,
|
||||
cfg.maxtry, cfg.rqstpause, cfg.respwait, cfg.conntimeout);
|
||||
cfg.ttyport, cfg.ttyspeed, cfg.ttymode, cfg.serverport,
|
||||
MAX_MAXCONN, cfg.maxconn, MAX_MAXTRY, cfg.maxtry,
|
||||
MAX_RQSTPAUSE, cfg.rqstpause, MAX_RESPWAIT, cfg.respwait,
|
||||
MAX_CONNTIMEOUT, cfg.conntimeout);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int err = 0, rc;
|
||||
int err = 0, rc, err_line;
|
||||
char *exename;
|
||||
char ttyparity;
|
||||
|
||||
sig_init();
|
||||
|
||||
cfg_init();
|
||||
|
||||
if ((exename = strrchr(argv[0], '/')) == NULL)
|
||||
@ -172,7 +180,7 @@ main(int argc, char *argv[])
|
||||
#ifdef LOG
|
||||
"v:L:"
|
||||
#endif
|
||||
"p:s:m:P:C:N:R:W:T:")) != RC_ERR)
|
||||
"p:s:m:P:C:N:R:W:T:c:")) != RC_ERR)
|
||||
{
|
||||
switch (rc)
|
||||
{
|
||||
@ -181,6 +189,18 @@ main(int argc, char *argv[])
|
||||
case 'd':
|
||||
isdaemon = FALSE;
|
||||
break;
|
||||
case 'c':
|
||||
if ((err_line = cfg_read_file(optarg)) != 0)
|
||||
{
|
||||
if (err_line > 0)
|
||||
printf("%s: can't read config file %s: error at line %d: %s\n",
|
||||
exename, optarg, err_line, cfg_err);
|
||||
else
|
||||
printf("%s: can't read config file %s: %s\n",
|
||||
exename, optarg, strerror(errno));
|
||||
exit(-1);
|
||||
}
|
||||
break;
|
||||
#ifdef TRXCTL
|
||||
case 't':
|
||||
cfg.trxcntl = TRX_RTS;
|
||||
@ -222,8 +242,7 @@ main(int argc, char *argv[])
|
||||
else
|
||||
{ /* concatenate given log file name with default path */
|
||||
strncpy(cfg.logname, LOGPATH, INTBUFSIZE);
|
||||
strncat(cfg.logname, optarg,
|
||||
INTBUFSIZE - strlen(cfg.logname));
|
||||
strncat(cfg.logname, optarg, INTBUFSIZE - strlen(cfg.logname));
|
||||
}
|
||||
}
|
||||
else strncpy(cfg.logname, optarg, INTBUFSIZE);
|
||||
@ -234,8 +253,7 @@ main(int argc, char *argv[])
|
||||
{ /* concatenate given port name with default
|
||||
path to devices mountpoint */
|
||||
strncpy(cfg.ttyport, "/dev/", INTBUFSIZE);
|
||||
strncat(cfg.ttyport, optarg,
|
||||
INTBUFSIZE - strlen(cfg.ttyport));
|
||||
strncat(cfg.ttyport, optarg, INTBUFSIZE - strlen(cfg.ttyport));
|
||||
}
|
||||
else strncpy(cfg.ttyport, optarg, INTBUFSIZE);
|
||||
break;
|
||||
@ -243,11 +261,12 @@ main(int argc, char *argv[])
|
||||
cfg.ttyspeed = strtoul(optarg, NULL, 0);
|
||||
break;
|
||||
case 'm':
|
||||
cfg.ttymode = optarg;
|
||||
strncpy(cfg.ttymode, optarg, INTBUFSIZE);
|
||||
/* tty mode sanity checks */
|
||||
if (strlen(cfg.ttymode) != 3)
|
||||
{
|
||||
printf("%s: -m: invalid serial port mode ('%s')\n", exename, cfg.ttymode);
|
||||
printf("%s: -m: invalid serial port mode ('%s')\n",
|
||||
exename, cfg.ttymode);
|
||||
exit(-1);
|
||||
}
|
||||
if (cfg.ttymode[0] != '8')
|
||||
@ -276,46 +295,46 @@ main(int argc, char *argv[])
|
||||
break;
|
||||
case 'C':
|
||||
cfg.maxconn = strtoul(optarg, NULL, 0);
|
||||
if (cfg.maxconn < 1 || cfg.maxconn > 128)
|
||||
if (cfg.maxconn < 1 || cfg.maxconn > MAX_MAXCONN)
|
||||
{ /* report about invalid max conn number */
|
||||
printf("%s: -C: invalid maxconn value"
|
||||
" (%d, must be 1-128)\n", exename, cfg.maxconn);
|
||||
" (%d, must be 1-%d)\n", exename, cfg.maxconn, MAX_MAXCONN);
|
||||
exit(-1);
|
||||
}
|
||||
break;
|
||||
case 'N':
|
||||
cfg.maxtry = strtoul(optarg, NULL, 0);
|
||||
if (cfg.maxtry > 15)
|
||||
if (cfg.maxtry > MAX_MAXTRY)
|
||||
{ /* report about invalid max try number */
|
||||
printf("%s: -N: invalid maxtry value"
|
||||
" (%d, must be 0-15)\n", exename, cfg.maxtry);
|
||||
" (%d, must be 0-%d)\n", exename, cfg.maxtry, MAX_MAXTRY);
|
||||
exit(-1);
|
||||
}
|
||||
break;
|
||||
case 'R':
|
||||
cfg.rqstpause = strtoul(optarg, NULL, 0);
|
||||
if (cfg.rqstpause < 1 || cfg.rqstpause > 10000)
|
||||
if (cfg.rqstpause < 1 || cfg.rqstpause > MAX_RQSTPAUSE)
|
||||
{ /* report about invalid rqst pause value */
|
||||
printf("%s: -R: invalid inter-request pause value"
|
||||
" (%lu, must be 1-10000)\n", exename, cfg.rqstpause);
|
||||
" (%lu, must be 1-%d)\n", exename, cfg.rqstpause, MAX_RQSTPAUSE);
|
||||
exit(-1);
|
||||
}
|
||||
break;
|
||||
case 'W':
|
||||
cfg.respwait = strtoul(optarg, NULL, 0);
|
||||
if (cfg.respwait < 1 || cfg.respwait > 10000)
|
||||
if (cfg.respwait < 1 || cfg.respwait > MAX_RESPWAIT)
|
||||
{ /* report about invalid resp wait value */
|
||||
printf("%s: -W: invalid response wait time value"
|
||||
" (%lu, must be 1-10000)\n", exename, cfg.respwait);
|
||||
" (%lu, must be 1-%d)\n", exename, cfg.respwait, MAX_RESPWAIT);
|
||||
exit(-1);
|
||||
}
|
||||
break;
|
||||
case 'T':
|
||||
cfg.conntimeout = strtoul(optarg, NULL, 0);
|
||||
if (cfg.conntimeout > 1000)
|
||||
if (cfg.conntimeout > MAX_CONNTIMEOUT)
|
||||
{ /* report about invalid conn timeout value */
|
||||
printf("%s: -T: invalid conn timeout value"
|
||||
" (%d, must be 1-1000)\n", exename, cfg.conntimeout);
|
||||
" (%d, must be 1-%d)\n", exename, cfg.conntimeout, MAX_CONNTIMEOUT);
|
||||
exit(-1);
|
||||
}
|
||||
break;
|
||||
|
@ -3,7 +3,7 @@ Description=Modbus TCP to Modbus RTU (RS-232/485) gateway.
|
||||
Requires=network.target
|
||||
|
||||
[Service]
|
||||
ExecStart=@bindir@/mbusd -p /dev/%i -s 9600 -m 8N1 -P 502 -d -v2
|
||||
ExecStart=@bindir@/mbusd -d -v2 -L - -c /etc/mbusd/mbusd-%i.conf -p /dev/%i
|
||||
Restart=on-failure
|
||||
RestartSec=1
|
||||
StandardOutput=journal
|
||||
|
Loading…
Reference in New Issue
Block a user