Compare commits

..

No commits in common. 'master' and '1.0.0' have entirely different histories.

1
.gitignore vendored

@ -6,5 +6,4 @@ config.h
*.oo
testmodbus-server
testmodbus-server.exe
default.modbus

@ -1,33 +1,3 @@
Version 1.0.4
2024-11-08:
- fixed single coil / word write. Response was not correct.
2024-08-07:
- fixed compile on windows. stdint.h was not included
2024-02-22:
- fixed: ignore incorrect requests
2023-09-19:
- performance issues fixed.
- gui issues if more than 200 values where added fixed.
- closing connection if an error occured.
2023-09-16:
- added message if a connection is closed.
2022-10-31:
- fixed use of uninitialized and wrong value.
2022-05-30:
- display issues with signed and unsigned int16 in the values tab.
- buildwindows will compile test-fc15 and test-fc16 command line tools.
- adding to the test-fc16 some byte and word swapping mechanism
Initial Application:

@ -1,182 +0,0 @@
# Cross Compile
This manual explains the steps to prepare a basic cross compiling environment on Debian. The build will be installed to `/opt/W64-cross-compile`. If the destination folder is set up right, you do not need any root rights.
The following packages are needed: (maybe wine is not anymore needed, haven't tested yet)
- wine
- wine64
- mingw-w64
- mingw-w64-tools
- binutils-mingw-w64
The following sources are needed:
- [glib](https://gitlab.gnome.org/GNOME/glib)
- [atk](https://gitlab.gnome.org/GNOME/atk)
- [pango](https://gitlab.gnome.org/GNOME/pango)
- [gdk-pixbuf](https://gitlab.gnome.org/GNOME/gdk-pixbuf)
- [libepoxy](https://github.com/anholt/libepoxy)
- [GTK+](https://www.gtk.org/)
## Prepare the `cross-file.ini`
This configuration file will be needed on all meson based builds.
[host_machine]
system = 'windows'
cpu_family = 'x86_64'
cpu = 'x86_64'
endian = 'little'
[built-in options]
c_args = []
c_link_args = []
[binaries]
c = '/usr/bin/x86_64-w64-mingw32-gcc'
cpp = '/usr/bin/x86_64-w64-mingw32-g++'
ar = '/usr/bin/x86_64-w64-mingw32-ar'
strip = '/usr/bin/x86_64-w64-mingw32-strip'
pkgconfig = '/usr/bin/x86_64-w64-mingw32-pkg-config'
windres = '/usr/bin/x86_64-w64-mingw32-windres'
ld = '/usr/bin/x86_64-w64-mingw32-ld'
exe_wrapper = 'wine'
## lib-glib
Compile the library using the following steps.
mkdir build
cd build
meson setup --buildtype=release --prefix=/opt/W64-cross-compile/ --cross-file ../../cross-file.ini
meson compile
if an error like `glib/glibconfig.h:65:51: error: missing binary operator before token "("` occures edit the line and delete the **G_GNUC_EXTENSION** expression.
meson install
Because not all compiled `*.dll` files are installed into the destination we need to copy them manualy.
cp `find -name "*.dll"` /opt/W64-cross-compile/lib/
## atk
The flags -Dintrospection=false will tell meson to disable some building options. See the file `meson_options.txt` for some information. Compile the library using the following steps.
mkdir build
cd build
PKG_CONFIG_PATH=/opt/W64-cross-compile/lib/pkgconfig meson setup --buildtype=release -Dintrospection=false -Ddocs=false --prefix=/opt/W64-cross-compile/ --cross-file ../../cross-file.ini
meson compile
meson install
Copy manualy all compiled `*.dll` files to the destination
cp `find -name "*.dll"` /opt/W64-cross-compile/lib/
## pango
Compile the library using the following steps. This will also download and compile some more librarys like `libpng` and `cairo` librarys.
mkdir build
cd build
PKG_CONFIG_PATH=/opt/W64-cross-compile/lib/pkgconfig meson setup --buildtype=release --prefix=/opt/W64-cross-compile/ --cross-file ../../cross-file.ini
For some reason the **harfbuzz** library wants to compile with the **HAVE_FT_GET_TRANSFORM** definition set. While this function is not defined in the sources at all. The workaround is to comment out the following line in `build/subprojects/harfbuzz/config.h` file.
// #define HAVE_FT_GET_TRANSFORM 1
Add `#include <cairo-dwrite.h> in file `../pango/pangocairo-dwrite-font.cpp` and start the compilation.
PKG_CONFIG_PATH=/opt/W64-cross-compile/lib/pkgconfig meson compile
In case of an error with unresolved symbols like undefined reference to '__strcat_chk'. You need to edit the `cross-file.ini` and add the linker flags/option `-lssp` to the `c_link_args` parameters. Remove the build directory and restart configuring and compiling this libraray again.
meson install
cp `find -name "*.dll"` /opt/W64-cross-compile/lib/
## gdk-pixbuf
mkdir build
cd build
PKG_CONFIG_PATH=/opt/W64-cross-compile/lib/pkgconfig meson setup --buildtype=release --prefix=/opt/W64-cross-compile/ --cross-file ../../cross-file.ini
meson compile
meson install
cp `find -name "*.dll"` /opt/W64-cross-compile/lib/
## libepoxy
mkdir build
cd build
PKG_CONFIG_PATH=/opt/W64-cross-compile/lib/pkgconfig meson --buildtype=release --prefix=/opt/W64-cross-compile/ --cross-file ../../cross-file.ini
meson compile
meson install
cp `find -name "*.dll"` /opt/W64-cross-compile/lib/
## GTK+-4
### Configuration and Compilation of GTK
mkdir build
cd build
PKG_CONFIG_PATH=/opt/W64-cross-compile/lib/pkgconfig meson --buildtype=release --prefix=/opt/W64-cross-compile/ -Dmedia-gstreamer=disabled -Ddemos=false -Dbuild-examples=false -Dbuild-tests=false --cross-file ../../cross-file.ini
meson compile
If the compile process stops with error `../gdk/loaders/gdkjpeg.c:302:67: error: free undeclared (first use in this function)` you need to add the line `#include <stdlib.h>`on top of the file, before the `#include <jpeglib.h>` line. Run the compile command again.
meson install
cp `find -name "*.dll"` /opt/W64-cross-compile/lib/
## GTK+-3
### preparation beacuse of `wine`
Copy all compiled executeble and library files into the wine windows/system folder.
cp /opt/W64-cross-compile/bin/*.exe ~/.wine/drive_c/windows/system32/
cp /opt/W64-cross-compile/lib/*.dll ~/.wine/drive_c/windows/system32/
cp /usr/x86_64-w64-mingw32/lib/zlib1.dll ~/.wine/drive_c/windows/system32/
### workaround for some issues
Edit the file `gdk/win32/gdkprivate-win32.h` and search around line 300 for the following declaration. In some releases the compiler is missing the **extern** statement here.
300 /* The singleton selection object pointer */
301 extern GdkWin32Selection *_win32_selection;
### compile first attempt
Configure and compile the library.
PKG_CONFIG_PATH=/opt/W64-cross-compile/lib/pkgconfig ./configure --prefix=/opt/W64-cross-compile/ --host=x86_64-w64-mingw32
touch gdk/win32/winpointer.h
PKG_CONFIG_PATH=/opt/W64-cross-compile/lib/pkgconfig make
#### Compile Error: glib-compile-resources: file not found
make[2]: Verzeichnis „/home/steffen/test/GTKCross/gtk+-3.24.1/gdk“ wird betreten
/bin/bash: Zeile 1: /opt/W64-cross-compile/bin/glib-compile-resources: Datei oder Verzeichnis nicht gefunden
GEN gdkresources.h
/bin/bash: Zeile 1: /opt/W64-cross-compile/bin/glib-compile-resources: Datei oder Verzeichnis nicht gefunden
make[2]: *** [Makefile:2243: gdkresources.h] Fehler 127
Edit the file `gdk/Makefile` append the windows `.exe` extension at the place where `GLIB_COMPILE_RESOURCES` is defined.
Find **all the other** `GLIB_COMPILE_RESOURCES` occurences and add the `wine` command prior to **all** `$(GLIB_COMPILE_RESOURCES)` calls.
Try to compile.
### fix and install the compilation
/bin/bash: Zeile 1: ../../gtk/gtk-update-icon-cache.exe: Kann die Binärdatei nicht ausführen: Fehler im Format der Programmdatei
make[3]: *** [Makefile:1673: install-update-icon-cache] Fehler 126
Edit the Makefile in demos/gtk-demos and add in line the wine prefix where the `. Try to run the `make install`command and do the same for the next errors.
/bin/bash: Zeile 1: ../../gtk/gtk-update-icon-cache.exe: Kann die Binärdatei nicht ausführen: Fehler im Format der Programmdatei
make[5]: *** [Makefile:1184: install-update-icon-cache] Fehler 126
make[5]: Verzeichnis „/home/steffen/gtkcrosscompile/gtk+-3.24.0/demos/widget-factory“ wird verlassen
If the compilation did well copy all *.dll files into the destination.
cp `find -name "*.dll"` /opt/W64-cross-compile/lib/

@ -0,0 +1,206 @@
Cross Compile
===============================================================================
needed:
wine
wine64
mingw-w64
mingw-w64-tools
=
= lib-glib
===============================================================================
cross-file.ini
[host_machine]
system = 'windows'
cpu_family = 'x86_64'
cpu = 'x86_64'
endian = 'little'
[properties]
c_args = []
c_link_args = []
[binaries]
c = '/usr/bin/x86_64-w64-mingw32-gcc'
cpp = '/usr/bin/x86_64-w64-mingw32-g++'
ar = '/usr/bin/x86_64-w64-mingw32-ar'
strip = '/usr/bin/x86_64-w64-mingw32-strip'
pkgconfig = '/usr/bin/x86_64-w64-mingw32-pkg-config'
windres = '/usr/bin/x86_64-w64-mingw32-windres'
ld = '/usr/bin/x86_64-w64-mingw32-ld'
exe_wrapper = 'wine64'
mkdir build
cd build
meson --buildtype=release --prefix=/opt/W64-cross-compile/ --cross-file ../cross-file.ini
mseon compile
meson install
cp `find -name "*.dll"` /opt/W64-cross-compile/lib/
=
= atk
===============================================================================
cross-file.ini
[host_machine]
system = 'windows'
cpu_family = 'x86_64'
cpu = 'x86_64'
endian = 'little'
[properties]
c_args = []
c_link_args = []
[binaries]
c = '/usr/bin/x86_64-w64-mingw32-gcc'
cpp = '/usr/bin/x86_64-w64-mingw32-g++'
ar = '/usr/bin/x86_64-w64-mingw32-ar'
strip = '/usr/bin/x86_64-w64-mingw32-strip'
pkgconfig = '/usr/bin/x86_64-w64-mingw32-pkg-config'
windres = '/usr/bin/x86_64-w64-mingw32-windres'
ld = '/usr/bin/x86_64-w64-mingw32-ld'
exe_wrapper = 'wine64'
mkdir build
cd build
PKG_CONFIG_PATH=/opt/W64-cross-compile/lib/pkgconfig meson --buildtype=release --prefix=/opt/W64-cross-compile/ --cross-file ../cross-file.ini
mseon compile
meson install
cp `find -name "*.dll"` /opt/W64-cross-compile/lib/
=
= pango
===============================================================================
cross-file.ini
[host_machine]
system = 'windows'
cpu_family = 'x86_64'
cpu = 'x86_64'
endian = 'little'
[properties]
c_args = []
c_link_args = []
[binaries]
c = '/usr/bin/x86_64-w64-mingw32-gcc'
cpp = '/usr/bin/x86_64-w64-mingw32-g++'
ar = '/usr/bin/x86_64-w64-mingw32-ar'
strip = '/usr/bin/x86_64-w64-mingw32-strip'
pkgconfig = '/usr/bin/x86_64-w64-mingw32-pkg-config'
windres = '/usr/bin/x86_64-w64-mingw32-windres'
ld = '/usr/bin/x86_64-w64-mingw32-ld'
exe_wrapper = 'wine64'
mkdir build
cd build
PKG_CONFIG_PATH=/opt/W64-cross-compile/lib/pkgconfig meson --buildtype=release --prefix=/opt/W64-cross-compile/ --cross-file ../cross-file.ini
mseon compile
meson install
cp `find -name "*.dll"` /opt/W64-cross-compile/lib/
=
= gdk-pixbuf
===============================================================================
cross-file.ini
[host_machine]
system = 'windows'
cpu_family = 'x86_64'
cpu = 'x86_64'
endian = 'little'
[properties]
c_args = []
c_link_args = []
[binaries]
c = '/usr/bin/x86_64-w64-mingw32-gcc'
cpp = '/usr/bin/x86_64-w64-mingw32-g++'
ar = '/usr/bin/x86_64-w64-mingw32-ar'
strip = '/usr/bin/x86_64-w64-mingw32-strip'
pkgconfig = '/usr/bin/x86_64-w64-mingw32-pkg-config'
windres = '/usr/bin/x86_64-w64-mingw32-windres'
ld = '/usr/bin/x86_64-w64-mingw32-ld'
exe_wrapper = 'wine64'
mkdir build
cd build
PKG_CONFIG_PATH=/opt/W64-cross-compile/lib/pkgconfig meson --buildtype=release --prefix=/opt/W64-cross-compile/ --cross-file ../cross-file.ini
mseon compile
meson install
cp `find -name "*.dll"` /opt/W64-cross-compile/lib/
=
= libepoxy
===============================================================================
cross-file.ini
[host_machine]
system = 'windows'
cpu_family = 'x86_64'
cpu = 'x86_64'
endian = 'little'
[properties]
c_args = []
c_link_args = []
[binaries]
c = '/usr/bin/x86_64-w64-mingw32-gcc'
cpp = '/usr/bin/x86_64-w64-mingw32-g++'
ar = '/usr/bin/x86_64-w64-mingw32-ar'
strip = '/usr/bin/x86_64-w64-mingw32-strip'
pkgconfig = '/usr/bin/x86_64-w64-mingw32-pkg-config'
windres = '/usr/bin/x86_64-w64-mingw32-windres'
ld = '/usr/bin/x86_64-w64-mingw32-ld'
exe_wrapper = 'wine64'
mkdir build
cd build
PKG_CONFIG_PATH=/opt/W64-cross-compile/lib/pkgconfig meson --buildtype=release --prefix=/opt/W64-cross-compile/ --cross-file ../cross-file.ini
mseon compile
meson install
cp `find -name "*.dll"` /opt/W64-cross-compile/lib/
=
= GTK
===============================================================================
cp /opt/W64-cross-compile/bin/*.exe ~/.wine/drive_c/windows/system32/
cp /opt/W64-cross-compile/lib/*.dll ~/.wine/drive_c/windows/system32/
vim gdk/win32/gdkprivate-win32.h ....
search around line 300.. and add the extern expression
300 /* The singleton selection object pointer */
301 extern GdkWin32Selection *_win32_selection;
PKG_CONFIG_PATH=/opt/W64-cross-compile/lib/pkgconfig ./configure --prefix=/opt/W64-cross-compile/ --host=x86_64-w64-mingw32
PKG_CONFIG_PATH=/opt/W64-cross-compile/lib/pkgconfig make
make install
will fail with
/bin/bash: Zeile 1: ../../gtk/gtk-update-icon-cache.exe: Kann die Binärdatei nicht ausführen: Fehler im Format der Programmdatei
make[3]: *** [Makefile:1673: install-update-icon-cache] Fehler 126
edit the Makefile in demos/gtk-demos and add in line the wine prefix.
the same we do for
/bin/bash: Zeile 1: ../../gtk/gtk-update-icon-cache.exe: Kann die Binärdatei nicht ausführen: Fehler im Format der Programmdatei
make[5]: *** [Makefile:1184: install-update-icon-cache] Fehler 126
make[5]: Verzeichnis „/home/steffen/gtkcrosscompile/gtk+-3.24.0/demos/widget-factory“ wird verlassen
make install
cp `find -name "*.dll"` /opt/W64-cross-compile/lib/

@ -1,22 +1,23 @@
.SILENT: help
VERSION = 1.0.5
VERSION = 1.0.0
APP = testmodbus-server
-include Makefile.rules
OBJECTSSRV = gui.oo server.oo mbsconfig.oo modbussrv.oo guimodbusdata.oo guivalues.oo json.oo tcp.oo
OBJECTS = gui.oo main.oo mbsconfig.oo modbus.oo guimodbusdata.oo guivalues.oo json.oo tcp.oo
DISTNAME=testmodbus-server-$(VERSION)
ifeq ($(CONFIGSET),)
ifeq ($(TARGET),)
noconfig: help
endif
all: Makefile.rules testmodbus-server$(TARGETEXT)
all: Makefile.rules $(TARGET)
help:
echo "set up configuration"
echo " make configwindows to generate the windows build"
echo " make configcross to generate the windows cross build"
echo " make configlinux to generate the linux build"
echo " make configlinux to generate the linix build"
echo " make buildwindows to generate the build for windows (uses cross compiler)"
configlinux: clean
@ -40,8 +41,8 @@ config: Makefile.rules
echo "#endif" >> config.h
testmodbus-server$(TARGETEXT): $(OBJECTSSRV)
$(CPP) -o testmodbus-server$(TARGETEXT) $(OBJECTSSRV) $(LDFLAGS) $(LIBS)
$(TARGET): $(OBJECTS)
$(CPP) -o $(TARGET) $(OBJECTS) $(LDFLAGS) $(LIBS)
.SUFFIXES:
.SUFFIXES: .c .cc .C .cpp .oo
@ -50,14 +51,12 @@ testmodbus-server$(TARGETEXT): $(OBJECTSSRV)
$(CPP) -o $@ -c $(CPPFLAGS) $<
clean:
rm -rf TestModbus-Server-$(VERSION)/
rm -f *.o *.oo *.c~ *.h~ *.cc~ *.ui~ testmodbus-server$(TARGETEXT) testmodbus-client$(TARGETEXT) Makefile~
rm -f *.o *.oo *.c~ *.h~ *.cc~ *.ui~ $(APP) Makefile~
rm -rf *.dll
rm -rf *.exe
rm -rf Makefile.rules
rm -rf test-fc16
rm -rf test-fc15
rm -rf config.h
dist: clean
rm -rf $(DISTNAME)
@ -76,33 +75,36 @@ dep:
$(CXX) -MM `ls *.cc` $(CXXFLAGS) > $(DEPENDFILE)
test-fc16: test-fc16.cc
$(CPP) -o test-fc16 test-fc16.cc tcp.cc $(LDFLAGS)
$(CPP) -o test-fc16 test-fc16.cc $(LDFLAGS) -I/usr/include -I/usr/local/include -L/usr/local/lib -L/usr/lib
test-fc15: test-fc15.cc
$(CPP) -o test-fc15 test-fc15.cc tcp.cc $(LDFLAGS)
$(CPP) -o test-fc15 test-fc15.cc $(LDFLAGS) -I/usr/include -I/usr/local/include -L/usr/local/lib -L/usr/lib
buildwindows: clean
make configcross
make $(TARGET) -j 9
make test-fc15
make test-fc16
copydll: $(TARGET)
echo "delete all librarys"
rm -rf *.dll
echo "copy linked dll first level"
cp -vf `ldd testmodbus-server.exe | grep .dll | grep /mingw64/bin | cut -d' ' -f3 ` ./
echo "copy network dll"
cp /usr/lib/*UDPTCPNetwork.dll ./
echo "copy linked dll second level"
cp -vf `ldd testmodbus-server.exe | grep .dll | grep /mingw64/bin | cut -d' ' -f3 ` ./
buildwindows:
rm -rf TestModbus-Server-$(VERSION)
mkdir TestModbus-Server-$(VERSION)
cp *.exe TestModbus-Server-$(VERSION)/
make clean
make configcross
make $(TARGET)
cp testmodbus-server.exe TestModbus-Server-$(VERSION)/
cp testmodbus-server.ui TestModbus-Server-$(VERSION)/
cp testmodbus-server.png TestModbus-Server-$(VERSION)/
cp README.md TestModbus-Server-$(VERSION)/
cp Changelog TestModbus-Server-$(VERSION)/
cp LICENSE TestModbus-Server-$(VERSION)/
./copydlls.sh
./copydlls.sh
./copydlls.sh
./copydlls.sh
./copyshare.sh
cp /usr/lib/gcc/x86_64-w64-mingw32/14-win32/*.dll TestModbus-Server-$(VERSION)/
for i in `ldd TestModbus-Server.exe |grep -vi "/c/windows" | cut -d" " -f3`; do cp $$i TestModbus-Server-$(VERSION)/; done
mv *.dll TestModbus-Server-$(VERSION)/
mv share TestModbus-Server-$(VERSION)/
zip -r TestModbus-Server-$(VERSION)-win.zip TestModbus-Server-$(VERSION)/
tar xvzf $(CROSSENV)/files/winbuild-dll.tgz -C TestModbus-Server-$(VERSION)/
tar xvzf $(CROSSENV)/files/winbuild-share.tgz -C TestModbus-Server-$(VERSION)/
-include $(DEPENDFILE)

@ -1,6 +1,5 @@
TARGETEXT = .exe
CONFIGSET = YES
TARGET = $(APP).exe
CROSSENV = /opt/W64-cross-compile/
CPP = /usr/bin/x86_64-w64-mingw32-g++
CPPFLAGS = -ggdb -Wall -O0 `PKG_CONFIG_PATH=$(CROSSENV)/lib/pkgconfig pkg-config --cflags gtk+-3.0 gmodule-export-2.0` -Wl,--export-dynamic -DBUILD_WINDOWS=1 -Wdeprecated

@ -1,6 +1,6 @@
TARGETEXT =
CONFIGSET = YES
TARGET = $(APP)
CPP = c++
CPPFLAGS = -ggdb -Wall -O0 `pkg-config --cflags gtk+-3.0 gmodule-export-2.0` -Wl,--export-dynamic -I/usr/include -DBUILD_LINUX=1
INCLUDES =

@ -1,6 +1,6 @@
TARGETEXT = .exe
CONFIGSET = YES
TARGET = $(APP).exe
CPP = g++
CPPFLAGS = -ggdb -Wall -O0 `pkg-config --cflags gtk+-3.0 gmodule-export-2.0` -Wl,--export-dynamic -I/usr/include -DBUILD_WINDOWS=1
INCLUDES =

@ -10,16 +10,13 @@ newer version of this software at https://steffen.gulpe.de/modbus-tcpip/
![Image_02](https://steffen.gulpe.de/modbus-tcpip/screenshot-winver1-0-0-values.PNG)
# Compilation on Linux
As requirement to compile this application you need to install the gnome3-devel packages. If this is done you can compile and run the application with the following commands:
# Compilation
make configlinux
make
./testmodbus-server
# Installation
not needed.
not supported.
# Cross Compilation for Windows (build on Debian, target Windows)

@ -1,44 +0,0 @@
#!/bin/bash
CROSS_DEST_DIR=/opt/W64-cross-compile/lib
CROSS_COMPILER_DIR=/usr/x86_64-w64-mingw32/lib
#
# in case of issues, check the path
# ls -la /usr/lib/gcc/x86_64-w64-mingw32/
#
CROSS_GCC_DIR=/usr/lib/gcc/x86_64-w64-mingw32/12-win32
cp -v $CROSS_COMPILER_DIR/zlib1.dll ./
# copy dll dependencys
copy_dependency() {
local I
for I in `strings $1 | grep -i '\.dll$' | grep -e "^lib"`
do
if [ -e ./$I ]
then
echo "File Exist"
elif [ -e $CROSS_COMPILER_DIR/$I ]
then
cp -v $CROSS_COMPILER_DIR/$I ./
copy_dependency $CROSS_COMPILER_DIR/$I
elif [ -e $CROSS_GCC_DIR/$I ]
then
cp -v $CROSS_GCC_DIR/$I ./
copy_dependency $CROSS_GCC_DIR/$I
elif [ -e $CROSS_DEST_DIR/$I ]
then
cp -v $CROSS_DEST_DIR/$I ./
copy_dependency $CROSS_DEST_DIR/$I
fi
done
}
copy_dependency testmodbus-server.exe

@ -1,10 +0,0 @@
#!/bin/bash
CROSS_PREFIX=/opt/W64-cross-compile
mkdir share
cp -rf $CROSS_PREFIX/share/glib-2.0 share/glib-2.0
cp -rf $CROSS_PREFIX/share/gtk-2.0 share/gtk-4.0
cp -rf $CROSS_PREFIX/share/gtk-3.0 share/gtk-3.0
cp -rf $CROSS_PREFIX/share/icons share/icons

@ -11,7 +11,7 @@
#include <stdio.h>
#include <list>
#include "gui.h"
#include "modbussrv.h"
#include "modbus.h"
#include "guivalues.h"
#include "json.h"
#include "mbsconfig.h"
@ -20,10 +20,6 @@
extern GtkBuilder *_builder_; // work around for threads
extern void addvar_displaywithvalues (gpointer data, GuiValue *v);
//////////////////////////////////////////////////////////////////////////////////////////////////
//
// call back functions
@ -48,9 +44,9 @@ void cb_window_show (GtkWidget *widget, gpointer data) {
void cb_menu_new (GtkWidget *widget, gpointer data) {
// GtkBuilder *builder = (GtkBuilder *) data;
modbussrv.EnableAll(0);
modbus.EnableAll(0);
MBData_EnableAll(0);
modbussrv.RequestsClear();
modbus.RequestsClear();
MBData_ReqReset ();
Value_DelAll();
};
@ -181,21 +177,21 @@ void cb_btn_start (GtkWidget *widget, gpointer data) {
int port = atoi(gtk_entry_get_text(GTK_ENTRY(portentry)));
if (modbussrv.isRunning()) {
if (modbus.isRunning()) {
printf ("Stop Server\n");
modbussrv.Stop();
modbus.Stop();
gtk_widget_set_sensitive(portentry, TRUE);
gtk_button_set_label(GTK_BUTTON(widget), _("Start"));
}
else {
printf ("Start Server (port: %d)\n", port);
if (modbussrv.Start(port)) {
if (modbus.Start(port)) {
gtk_button_set_label(GTK_BUTTON(widget),_("Stop"));
gtk_widget_set_sensitive(portentry, FALSE);
}
usleep (250000);
if (modbussrv.isRunning() == 0) {
modbussrv.Stop();
if (modbus.isRunning() == 0) {
modbus.Stop();
displayerror("modbus server could not been started.\nSee console output for errors.");
gtk_widget_set_sensitive(portentry, TRUE);
gtk_button_set_label(GTK_BUTTON(widget), _("Start"));
@ -260,7 +256,7 @@ void addvar_displaywithvalues (gpointer data, GuiValue *v) {
vn.value = gtk_entry_get_text(GTK_ENTRY(value)); // load the from the entry
if (Value_SetValue(vn.value, vn.type, vn.fc, &regstowrite, regvals)) {
modbussrv.SetRegValue(vn.fc, vn.reg, regstowrite, (uint16_t*)regvals);
modbus.SetRegValue(vn.fc, vn.reg, regstowrite, (uint16_t*)regvals);
}
}
@ -343,7 +339,6 @@ gboolean cb_thread_network_data_add (gpointer data) {
GtkTextTag *tag_data;
GtkTextTag *tag_info;
GtkTextTag *tag_modbus;
GtkTextTag *tag_error;
time_t _tm =time(NULL);
struct tm * curtime = localtime (&_tm);
static int _once = 0;
@ -356,8 +351,6 @@ gboolean cb_thread_network_data_add (gpointer data) {
"foreground", "black", "style", PANGO_WEIGHT_NORMAL, "family", "Monospace", NULL);
tag_info = gtk_text_buffer_create_tag (textbuffer, "Info",
"foreground", "green", "style", PANGO_WEIGHT_THIN, "family", "Sans", NULL);
tag_error = gtk_text_buffer_create_tag (textbuffer, "Error",
"foreground", "red", "style", PANGO_WEIGHT_BOLD, "family", "Sans", NULL);
tag_modbus = gtk_text_buffer_create_tag (textbuffer, "Modbus",
"foreground", "black", "style", PANGO_WEIGHT_NORMAL, "family", "Sans", NULL);
}
@ -375,12 +368,11 @@ gboolean cb_thread_network_data_add (gpointer data) {
else if (i % 32 == 0) text += "\n ";
else if (i % 4 == 0 && i > 0) text += " : ";
else if (i % 2 == 0 && i > 0) text += ":";
// else text += " ";
text += hexnum[c/16];
text += hexnum[c%16];
}
text += "\n";
gtk_text_buffer_get_start_iter(textbuffer, &start);
gtk_text_buffer_insert_with_tags_by_name(textbuffer, &start, text.c_str(), -1, "Data", NULL);
@ -408,33 +400,23 @@ gboolean cb_thread_network_data_add (gpointer data) {
}
else {
text = text + " Registers: " + std::to_string (mbdata->regstart);
text = text + " Cnt: " + std::to_string (mbdata->regcnt);
text = text + " Bytes: " + std::to_string (mbdata->regcnt);
}
}
text = text + " Bytecnt: "+ std::to_string (mbdata->bytecnt) +"\n";
text = text + "\n";
gtk_text_buffer_get_start_iter(textbuffer, &start);
gtk_text_buffer_insert_with_tags_by_name(textbuffer, &start, text.c_str(), -1, "Modbus", NULL);
//
// number of bytes
text = std::to_string(mbdata->bufferlen) + " Bytes";
gtk_text_buffer_get_start_iter(textbuffer, &start);
gtk_text_buffer_insert_with_tags_by_name(textbuffer, &start, text.c_str(), -1, "Info", NULL);
//
// Hostname
text = mbdata->hostname;
text ="";
text += mbdata->hostname;
if (mbdata->direction == 0) text = text + " RECV ";
else text = text + " SEND ";
text = text + std::to_string(mbdata->bufferlen) + " Bytes";
gtk_text_buffer_get_start_iter(textbuffer, &start);
gtk_text_buffer_insert_with_tags_by_name(textbuffer, &start, text.c_str(), -1, "Info", NULL);
//
// direction or error
if (mbdata->direction == 0)
gtk_text_buffer_insert_with_tags_by_name(textbuffer, &start, (const char*)" RECV ", -1, "Info", NULL);
else if (mbdata->direction == 1)
gtk_text_buffer_insert_with_tags_by_name(textbuffer, &start, (const char*)" SEND ", -1, "Info", NULL);
else
gtk_text_buffer_insert_with_tags_by_name(textbuffer, &start, (const char*)" ** ERROR **", -1, "Error", NULL);
//
// add date
@ -484,6 +466,9 @@ gboolean cb_thread_network_text_add (gpointer data) {
strftime (timetext, 255, "%H:%M:%S", curtime);
//
// build hex dump
//
//
//
text ="";
@ -590,19 +575,19 @@ void cb_about_btnclose(GtkWidget *widget, gpointer data) {
}
void cb_btn_enableall (GtkWidget *widget, gpointer data) {
modbussrv.EnableAll(1);
modbus.EnableAll(1);
MBData_EnableAll(1);
};
void cb_btn_disableall (GtkWidget *widget, gpointer data) {
modbussrv.EnableAll(0);
modbus.EnableAll(0);
MBData_EnableAll(0);
};
void cb_btn_clearreq (GtkWidget *widget, gpointer data) {
modbussrv.RequestsClear();
modbus.RequestsClear();
MBData_ReqReset ();
};
@ -635,7 +620,7 @@ void cb_btn_enablevalues (GtkWidget *widget, gpointer data) {
break;
}
modbussrv.Enable(atoi(v_fc), atoi(v_reg), Value_GetSize(v_type), 1);
modbus.Enable(atoi(v_fc), atoi(v_reg), Value_GetSize(v_type), 1);
MBData_Enable(atoi(v_fc), atoi(v_reg), Value_GetSize(v_type), 1);
if (v_name != NULL) free (v_name);
@ -736,9 +721,9 @@ void load_file(std::string fn) {
int autoadd = 0;
modbussrv.EnableAll(0);
modbus.EnableAll(0);
MBData_EnableAll(0);
modbussrv.RequestsClear();
modbus.RequestsClear();
MBData_ReqReset ();
Value_DelAll();
std::string confdata;

@ -15,6 +15,8 @@
#include <iostream>
#include <list>
#define BUILDER_FILE "testmodbus-server.ui"
#include "guivalues.h"
#include "guimodbusdata.h"
std::string to_hex16 (int v);

@ -12,9 +12,9 @@
#include "gui.h"
#include "guimodbusdata.h"
#include "modbussrv.h"
#include "modbus.h"
extern ModbusSrv modbussrv;
extern Modbus modbus;
extern GtkBuilder *_builder_; // work around for threads
void mbdata_enabletoggled_cb(GtkCellRendererToggle *cellrenderer, char *path, gpointer data);
@ -45,7 +45,7 @@ GtkTreeModel *MBData_create_with_data() {
gtk_tree_store_set (store, &secondlevel, MBDATA_COL_FCREG, regname1.c_str(),-1);
}
modbussrv.GetRegister(fc, regnum, &r);
modbus.GetRegister(fc, regnum, &r);
regname2 = "FC" + std::to_string(fc) + " " + std::to_string(regnum);
if (fc < 3) {
if (r.value == 0) txt = "false";
@ -152,7 +152,7 @@ void mbdata_enabletoggled_cb(GtkCellRendererToggle *cellrenderer, char *path, gp
gtk_tree_store_set(GTK_TREE_STORE(model), &iter,
MBDATA_COL_ENABLED, enabled,
-1);
modbussrv.Enable(fc, reg, 1, enabled);
modbus.Enable(fc, reg, 1, enabled);
g_free (fcreg);
fcreg = NULL;
}
@ -175,7 +175,7 @@ void MBData_ChangeRegs (int fc, int regstart, int count, ModbusRegister *r) {
model = gtk_tree_view_get_model(GTK_TREE_VIEW(mbdata));
for (i = 0; regstart < MAXREG && i < count; i++, regstart++) {
strncpy(value, to_hex16(r[i].value).c_str(), 16);
for (j = 0; j < 4; j++) value[3-j] = hex[(r[i].value >> j)%16];
path = std::to_string(fc-1) + ":" + std::to_string(regstart / STEPREG) + ":" + std::to_string(regstart % STEPREG);
// printf ("fc:%d reg:%d val:%d enabled:%d requested:%d path:%s\n", fc, regstart, r[i].value, r[i].enabled, r[i].requested, path.c_str());

@ -8,7 +8,7 @@
#define _GUIMODBUSDATA_H_
#include "gui.h"
#include "modbussrv.h"
#include "modbus.h"
#include "guivalues.h"
enum {

@ -16,10 +16,10 @@
#include "gui.h"
#include "config.h"
#include "mbsconfig.h"
#include "modbussrv.h"
#include "modbus.h"
#include "guivalues.h"
void Value_ModStore(GtkTreeModel *model, GtkTreeIter *iter, GuiValue *g);
extern GtkBuilder *_builder_; // work around for threads
GuiValue::GuiValue() {
@ -226,21 +226,15 @@ gboolean Value_Loop(gpointer data) {
v.reg = atoi(v_reg);
v.type = v_type;
v.sim = v_sim;
Value_Set (&v);
changed = Value_Simulation(&v);
if (changed) {
uint16_t regvals[4];
int regstowrite = 1;
if (Value_SetValue(v.value, v.type, v.fc, &regstowrite, regvals)) {
modbussrv.SetRegValue(v.fc, v.reg, regstowrite, (uint16_t*)regvals);
modbus.SetRegValue(v.fc, v.reg, regstowrite, (uint16_t*)regvals);
}
gtk_list_store_set(GTK_LIST_STORE(model), &iter,
VALDATA_COL_NAME, v.name.c_str(),
VALDATA_COL_FC, std::to_string(v.fc).c_str(),
VALDATA_COL_REGSTART, std::to_string(v.reg).c_str(),
VALDATA_COL_TYPE, v.type.c_str(),
VALDATA_COL_VALUE, Value_GetValue(v.fc, v.reg, v.type).c_str(),
VALDATA_COL_SIM, v.sim.c_str(),
-1);
}
g_free(v_name);
@ -272,7 +266,6 @@ void Value_Set(GuiValue *g) {
if (strcmp(v_name, g->name.c_str()) == 0) {
Value_ModStore(model, &iter, g);
changed = 1;
break;
}
g_free(v_name);
}
@ -304,7 +297,7 @@ void Value_Add(GuiValue *g) {
Value_ModStore(model, &iter, g);
count = Value_GetSize(g->type);
modbussrv.Enable(g->fc, g->reg, count, 1);
modbus.Enable(g->fc, g->reg, count, 1);
MBData_Enable(g->fc, g->reg, count, 1);
}
@ -319,6 +312,12 @@ void Value_ModStore(GtkTreeModel *model, GtkTreeIter *iter, GuiValue *g) {
VALDATA_COL_VALUE, Value_GetValue(g->fc, g->reg, g->type).c_str(),
VALDATA_COL_SIM, g->sim.c_str(),
-1);
// for (int i = 0; i < 10; i++) {
// float *f = (float *)&modbusdata[2][i];
// printf ("%f ", *f);
// }
// printf ("\n");
};

@ -8,7 +8,7 @@
#define _GUIVALUE_H_
#include "gui.h"
#include "modbussrv.h"
#include "modbus.h"
#include <string>
enum {

@ -10,7 +10,6 @@
#include <list>
#include <string>
#include <string.h>
#include <stdint.h>
using namespace std;

@ -4,20 +4,20 @@
//
/////////////////////////////////////////////////////////////////////////////////
#include <sys/time.h>
#include "config.h"
#include "mbsconfig.h"
#include "gui.h"
#include "modbussrv.h"
#include "modbus.h"
//////////////////////////////////////////////////////////////////////////////////////////////////
//
// global variables
//
#define BUILDER_FILE "testmodbus-server.ui"
Config config;
ModbusSrv modbussrv;
Modbus modbus;
GtkBuilder *_builder_ = NULL; // work around for the thread situation
uint16_t modbusdata[4][0x10000]; // needed for work with the gui will by synced by the modbus call back functions
@ -47,7 +47,7 @@ int main (int argc, char **argv) {
// #endif
//
modbussrv.SetCallback(&modbus_callback);
modbus.SetCallback(&modbus_callback);
window = gtk_builder_get_object (builder, "testmodbus-server");
gtk_widget_show_all (GTK_WIDGET(window));
@ -67,6 +67,20 @@ int main (int argc, char **argv) {
return 0;
}
string to_hex16 (int v) {
char HEX[] = "0123456789ABCDEF";
int i = v;
int n;
string txt = "";
for (n = 0; n < 4; n++) {
txt = HEX[i%16]+ txt;
i = i / 16;
}
return txt;
}
gboolean modbus_callback(gpointer data) {
struct modbus_callback_data *mdata = (struct modbus_callback_data *) data;
@ -79,3 +93,15 @@ gboolean modbus_callback(gpointer data) {
return FALSE;
};
float get_cycletime(struct timeval *t) {
struct timeval t1;
float f = 0.0;
t1 = *t;
gettimeofday(t, NULL);
f = (float)(t->tv_sec - t1.tv_sec) + ((t->tv_usec - t1.tv_usec) / 1000000.0);
return f;
}

@ -12,7 +12,7 @@
#define _MBDCONFIG_H_
#include "config.h"
#include "modbussrv.h"
#include "modbus.h"
#include <string>
// maybe soon internationalisation
@ -42,6 +42,6 @@ class Config {
// declared in main.cc
//
extern Config config;
extern ModbusSrv modbussrv;
extern Modbus modbus;
#endif

@ -6,58 +6,27 @@
#include <errno.h>
#include <glib.h>
#include <sys/time.h>
#if defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
#else
#include <unistd.h> /* close() */
#endif
#include "gui.h"
#include "modbussrv.h"
#include "modbus.h"
#include "mbsconfig.h"
#include "config.h"
std::string to_hex16 (int v) {
char HEX[] = "0123456789ABCDEF";
int i = v;
int n;
std::string txt = "";
for (n = 0; n < 4; n++) {
txt = HEX[i%16]+ txt;
i = i / 16;
}
return txt;
}
float get_cycletime(struct timeval *t) {
struct timeval t1;
float f = 0.0;
t1 = *t;
gettimeofday(t, NULL);
f = (float)(t->tv_sec - t1.tv_sec) + ((t->tv_usec - t1.tv_usec) / 1000000.0);
return f;
}
//
// C / C++ Wrapper
gpointer _ServerThread (gpointer data) {
modbussrv.ServerThread ();
modbus.ServerThread ();
return NULL;
};
//
//
ModbusSrv::ModbusSrv () {
Modbus::Modbus () {
onchangecallback = NULL;
ModbusRegister r = {0, false, 0, false};
port = 502;
@ -75,7 +44,7 @@ ModbusSrv::ModbusSrv () {
}
};
ModbusSrv::~ModbusSrv () {
Modbus::~Modbus () {
for (int i = 0; i < MODBUS_MAXCLIENTS; i++) {
if (clients[i] != NULL) {
delete clients[i];
@ -85,12 +54,12 @@ ModbusSrv::~ModbusSrv () {
};
int ModbusSrv::isRunning() {
int Modbus::isRunning() {
return tcpserver.IsListen();
};
int ModbusSrv::Start(int serverport) {
int Modbus::Start(int serverport) {
port = serverport;
serverthread = g_thread_new("network thread", _ServerThread, NULL);
@ -98,7 +67,7 @@ int ModbusSrv::Start(int serverport) {
return 1;
};
void ModbusSrv::Stop() {
void Modbus::Stop() {
g_mutex_lock(&servermutex);
for (int i = 0; i < MODBUS_MAXCLIENTS; i++) {
if (clients[i] != NULL) {
@ -111,7 +80,7 @@ void ModbusSrv::Stop() {
};
void ModbusSrv::CloseConnection(int slot) {
void Modbus::CloseConnection(int slot) {
if (slot < 0 || slot >= MODBUS_MAXCLIENTS) return; // slot out of bound
if (clients[slot] != NULL)
delete clients[slot];
@ -119,12 +88,30 @@ void ModbusSrv::CloseConnection(int slot) {
};
void ModbusSrv::SetCallback (gboolean (*callback_func)(gpointer data)) {
void Modbus::SetCallback (gboolean (*callback_func)(gpointer data)) {
onchangecallback = callback_func;
}
/***************************************************************************************************
* this should only be called from within the ServerThread function
*/
void Modbus::ReadData(gpointer pdata) {
int slot;
long int len;
for (slot = 0; slot < MODBUS_MAXCLIENTS; slot++) if (&clients[slot] == pdata) break;
if (slot < 0 || slot >= MODBUS_MAXCLIENTS) return; // slot out of bound
if (clients[slot] == NULL) return; // slot not connected?
len = clients[slot]->Read(inbuffer, MODBUS_IOBUFFER);
if (len < 0) {
CloseConnection(slot);
}
};
void ModbusSrv::ServerThread() {
void Modbus::ServerThread() {
int keep_running = 1;
int ret;
struct timeval cycletimestamp = { 0 };
@ -161,18 +148,12 @@ void ModbusSrv::ServerThread() {
char *msg;
clients[slot] = tcp;
msg = (char*) malloc (255);
snprintf (msg, 255, "new connection from %s, use slot:%d\n", clients[slot]->GetRemoteAddr().c_str(), slot);
snprintf (msg, 255, "new connection from %s\n", clients[slot]->GetRemoteAddr().c_str());
gdk_threads_add_idle(cb_thread_network_text_add, msg);
}
else {
// no free slot, accept and close right away.
if (tcp) {
char *msg;
msg = (char*) malloc (255);
snprintf (msg, 255, "no free slot, close connection.\n");
gdk_threads_add_idle(cb_thread_network_text_add, msg);
delete tcp;
}
if (tcp) delete tcp;
}
}
@ -183,10 +164,6 @@ void ModbusSrv::ServerThread() {
if (clients[slot] != NULL) {
len = clients[slot]->ReadTimeout(inbuffer, MODBUS_IOBUFFER, 0);
if (len < 0) {
char *msg;
msg = (char*) malloc (255);
snprintf (msg, 255, "connection on slot %d closed.\n", slot);
gdk_threads_add_idle(cb_thread_network_text_add, msg);
delete clients[slot];
clients[slot] = NULL;
}
@ -214,12 +191,9 @@ void ModbusSrv::ServerThread() {
mbindata->transactionid = 0;
mbindata->protoolid = 0;
if (Decode(mbindata) == 0) {
mbindata->direction = 2; // mark as error
gdk_threads_add_idle(cb_thread_network_data_add, mbindata);
continue;
}
Decode(mbindata);
gdk_threads_add_idle(cb_thread_network_data_add, mbindata);
//
// fill in outdata
//
@ -244,11 +218,8 @@ void ModbusSrv::ServerThread() {
}
else {
char *txt = (char*)malloc(255);
snprintf (txt, 255, "error on processing message, close connection\n");
snprintf (txt, 255, "error on processing message\n");
gdk_threads_add_idle(cb_thread_network_text_add, txt);
delete clients[slot];
clients[slot] = NULL;
}
}
else if (mbindata->fc == 5 || mbindata->fc == 6) {
@ -257,10 +228,8 @@ void ModbusSrv::ServerThread() {
}
else {
char *txt = (char*)malloc(255);
snprintf (txt, 255, "error on processing message, close connection\n");
snprintf (txt, 255, "error on processing message\n");
gdk_threads_add_idle(cb_thread_network_text_add, txt);
delete clients[slot];
clients[slot] = NULL;
}
}
else if (mbindata->fc == 15 || mbindata->fc == 16) {
@ -269,10 +238,8 @@ void ModbusSrv::ServerThread() {
}
else {
char *txt = (char*)malloc(255);
snprintf (txt, 255, "error on processing message, close connection\n");
snprintf (txt, 255, "error on processing message\n");
gdk_threads_add_idle(cb_thread_network_text_add, txt);
delete clients[slot];
clients[slot] = NULL;
}
}
gdk_threads_add_idle(cb_thread_network_data_add, mboutdata);
@ -300,7 +267,7 @@ void ModbusSrv::ServerThread() {
// return 0 on error
int ModbusSrv::WorkerAndEncodeRead(struct modbus_data *mbin, struct modbus_data *mbout) {
int Modbus::WorkerAndEncodeRead(struct modbus_data *mbin, struct modbus_data *mbout) {
//
// to prevent race condition and invalid data: servermutex must be already locked
// buffer on outdata must be of size 0x10000
@ -447,17 +414,40 @@ int ModbusSrv::WorkerAndEncodeRead(struct modbus_data *mbin, struct modbus_data
}
int ModbusSrv::WorkerAndEncodeWriteSingle(struct modbus_data *mbin, struct modbus_data *mbout) {
int Modbus::WorkerAndEncodeWriteSingle(struct modbus_data *mbin, struct modbus_data *mbout) {
uint16_t i16;
int pos = 0;
int error = 0;
// transaction
mbout->transactionid = mbin->transactionid;
i16 = htons((uint16_t)mbin->transactionid);
memcpy (mbout->buffer+pos, &i16, sizeof(i16));
pos += sizeof (i16);
// protocolid
mbout->protoolid = mbin->protoolid;
mbout->length = 0;
i16 = htons((uint16_t)mbin->protoolid);
memcpy (mbout->buffer+pos, &i16, sizeof(i16));
pos += sizeof (i16);
// length 3 + number of registers
mbout->length = 3;
mbout->length += mbin->regcnt * 2; // 16bit = 2Bytes
i16 = htons((uint16_t)mbout->length);
memcpy (mbout->buffer+pos, &i16, sizeof(i16));
pos += sizeof (i16);
// device id
mbout->unitid = mbin->unitid;
memcpy (mbout->buffer+pos, &mbout->unitid, sizeof(uint8_t));
pos += sizeof (uint8_t);
// fc
mbout->fc = mbin->fc;
memcpy (mbout->buffer+pos, &mbout->fc, sizeof(uint8_t));
pos += sizeof (uint8_t);
mbout->direction = 1;
if (mbin->fc == 5) {
@ -467,17 +457,33 @@ int ModbusSrv::WorkerAndEncodeWriteSingle(struct modbus_data *mbin, struct modbu
else mbarray[FC1][mbin->regstart].value = 0;
}
else error = 1;
// return register and value
i16 = htons((uint16_t)mbin->regstart);
memcpy (mbout->buffer+pos, &i16, sizeof(i16));
pos += sizeof (i16);
i16 = htons((uint16_t)mbin->regcnt);
memcpy (mbout->buffer+pos, &i16, sizeof(i16));
pos += sizeof (i16);
}
if (mbin->fc == 6) {
mbarray[FC3][mbin->regstart].requested |= 2;
if (mbarray[FC3][mbin->regstart].enabled)
mbarray[FC3][mbin->regstart].value = mbin->regcnt;
else error = 1;
// return register and value
i16 = htons((uint16_t)mbin->regstart);
memcpy (mbout->buffer+pos, &i16, sizeof(i16));
pos += sizeof (i16);
i16 = htons((uint16_t)mbin->regcnt);
memcpy (mbout->buffer+pos, &i16, sizeof(i16));
pos += sizeof (i16);
}
// mirror the output
memcpy (mbout->buffer, mbin->buffer, mbin->bufferlen);
mbout->bufferlen = mbin->bufferlen;
mbout->bufferlen = pos;
//
// inform the application about the modbus values change
@ -504,7 +510,7 @@ int ModbusSrv::WorkerAndEncodeWriteSingle(struct modbus_data *mbin, struct modbu
}
int ModbusSrv::WorkerAndEncodeWriteMulti(struct modbus_data *mbin, struct modbus_data *mbout) {
int Modbus::WorkerAndEncodeWriteMulti(struct modbus_data *mbin, struct modbus_data *mbout) {
uint16_t i16;
int pos = 0;
int i;
@ -621,18 +627,16 @@ int ModbusSrv::WorkerAndEncodeWriteMulti(struct modbus_data *mbin, struct modbus
}
//
// return 1 on success, 0 on error
int ModbusSrv::Decode(struct modbus_data *mbdata) {
void Modbus::Decode(struct modbus_data *mbdata) {
//
uint16_t i16;
uint8_t i8;
int pos = 0;
int ret = 1;
mbdata->fc = 0;
mbdata->regcnt = 0;
mbdata->regstart =-1;
mbdata->regcnt = -1;
mbdata->regstart = -1;
mbdata->unitid = 0;
mbdata->length = 0;
mbdata->direction = 0;
@ -640,7 +644,7 @@ int ModbusSrv::Decode(struct modbus_data *mbdata) {
mbdata->protoolid = 0;
mbdata->bytecnt = 0;
if (mbdata->bufferlen < 8) return 0;
if (mbdata->bufferlen < 8) return;
// Transaction
memcpy (&i16, mbdata->buffer+pos, sizeof(i16));
@ -658,45 +662,32 @@ int ModbusSrv::Decode(struct modbus_data *mbdata) {
mbdata->length = ntohs(i16);
// unitid
if (mbdata->length < pos-6) ret = 0;
memcpy (&i8, mbdata->buffer+pos, sizeof(i8));
pos += sizeof(i8);
mbdata->unitid = i8;
// function code
if (mbdata->length < pos-6) ret = 0;
memcpy (&i8, mbdata->buffer+pos, sizeof(i8));
pos += sizeof(i8);
mbdata->fc = i8;
// register
if (mbdata->length < pos-6) ret = 0;
memcpy (&i16, mbdata->buffer+pos, sizeof(i16));
pos += sizeof(i16);
mbdata->regstart = ntohs(i16);
// not needed for single write
if (mbdata->fc == 5 || mbdata->fc == 6) {
mbdata->regcnt = 0;
mbdata->bytecnt = 0;
}
// number of registers
if (mbdata->length < pos-6) ret = 0;
memcpy (&i16, mbdata->buffer+pos, sizeof(i16));
pos += sizeof(i16);
mbdata->regcnt = ntohs(i16);
// bytecnt
// if (mbdata->length < pos-6) ret = 0;
// unitid
memcpy (&i8, mbdata->buffer+pos, sizeof(i8));
pos += sizeof(i8);
mbdata->bytecnt = i8;
return ret;
};
int ModbusSrv::GetRegister(int fc, int regnum, ModbusRegister *r) {
int Modbus::GetRegister(int fc, int regnum, ModbusRegister *r) {
r->enabled = false;
r->requested = 0;
r->updated = false;
@ -717,7 +708,7 @@ int ModbusSrv::GetRegister(int fc, int regnum, ModbusRegister *r) {
};
int ModbusSrv::GetRegisters(int fc, int regnum, int count, ModbusRegister *r) {
int Modbus::GetRegisters(int fc, int regnum, int count, ModbusRegister *r) {
r->enabled = false;
r->requested = 0;
r->updated = false;
@ -738,7 +729,7 @@ int ModbusSrv::GetRegisters(int fc, int regnum, int count, ModbusRegister *r) {
};
int ModbusSrv::SetRegister(int fc, int regnum, ModbusRegister *r) {
int Modbus::SetRegister(int fc, int regnum, ModbusRegister *r) {
if (regnum < 0 || regnum >= 0x10000) return -1;
g_mutex_lock(&servermutex);
@ -754,7 +745,7 @@ int ModbusSrv::SetRegister(int fc, int regnum, ModbusRegister *r) {
}
int ModbusSrv::SetRegisters(int fc, int regnum, int count, ModbusRegister *r) {
int Modbus::SetRegisters(int fc, int regnum, int count, ModbusRegister *r) {
int reg = regnum;
int regend = regnum+count;
@ -777,7 +768,7 @@ int ModbusSrv::SetRegisters(int fc, int regnum, int count, ModbusRegister *r) {
}
void ModbusSrv::Enable(int fc, int regstart, int count, int onoff) {
void Modbus::Enable(int fc, int regstart, int count, int onoff) {
int i;
if (fc < 1 || fc > 4) return;
if (regstart < 0) return;
@ -791,7 +782,7 @@ void ModbusSrv::Enable(int fc, int regstart, int count, int onoff) {
};
void ModbusSrv::RequestsClear() {
void Modbus::RequestsClear() {
int fc, reg;
g_mutex_lock(&servermutex);
@ -802,7 +793,7 @@ void ModbusSrv::RequestsClear() {
};
void ModbusSrv::EnableAll(int onoff) {
void Modbus::EnableAll(int onoff) {
int fc, reg;
g_mutex_lock(&servermutex);
@ -813,7 +804,7 @@ void ModbusSrv::EnableAll(int onoff) {
};
void ModbusSrv::SetRegValue(int fc, int regstart, int count, uint16_t *values) {
void Modbus::SetRegValue(int fc, int regstart, int count, uint16_t *values) {
int reg;
if (fc <= 0 || fc > 4) {
@ -869,6 +860,31 @@ void ModbusSrv::SetRegValue(int fc, int regstart, int count, uint16_t *values) {
g_mutex_lock(&servermutex);
}
/* // debug del me
printf ("%s:%d %s regs (", __FILE__, __LINE__, __FUNCTION__);
std::string text;
text = "";
if (fc == 5) fc = 1;
if (fc == 6) fc = 3;
if (fc == 15) fc = 1;
if (fc == 16) fc = 3;
for (int r = 0; r < count; r++) {
unsigned char c;
char hexnum[] = "0123456789ABCDEF";
c = *(((unsigned char *)&mbarray[fc-1][regstart+r])+0);
text += hexnum[c/16];
text += hexnum[c%16];
c = *(((unsigned char *)&mbarray[fc-1][regstart+r])+1);
text += hexnum[c/16];
text += hexnum[c%16];
text += ":";
}
printf ("%s)\n", text.c_str());
*/
g_mutex_unlock(&servermutex);
};

@ -36,7 +36,7 @@ struct modbus_data {
int protoolid;
int length;
int unitid;
int direction; // 0 - RECV, 1 - SEND, 2 - ERROR
int direction;
int fc;
int regstart;
int regcnt;
@ -45,7 +45,6 @@ struct modbus_data {
// return the cycletime in us
std::string to_hex16 (int v);
float get_cycletime(struct timeval *t);
struct {
@ -64,7 +63,7 @@ struct modbus_callback_data {
};
class ModbusSrv {
class Modbus {
private:
TCP tcpserver;
int port;
@ -77,14 +76,14 @@ private:
char inbuffer[MODBUS_IOBUFFER];
char outbuffer[MODBUS_IOBUFFER];
int Decode(struct modbus_data *mbdata);
// return 0 on error, 1 on success
void Decode(struct modbus_data *mbdata);
// return 0 on error, 1 on no error
int WorkerAndEncodeRead(struct modbus_data *mbin, struct modbus_data *mbout);
int WorkerAndEncodeWriteSingle(struct modbus_data *mbin, struct modbus_data *mbout);
int WorkerAndEncodeWriteMulti(struct modbus_data *mbin, struct modbus_data *mbout);
public:
ModbusSrv();
~ModbusSrv();
Modbus();
~Modbus();
void ServerThread();
void SetCallback (gboolean (*callback_func)(gpointer data));
@ -97,7 +96,7 @@ public:
int SetRegister(int fc, int regnum, ModbusRegister *r);
int SetRegisters(int fc, int regnum, int count, ModbusRegister *r);
void CloseConnection(int slot);
// void ReadData(gpointer pdata);
void ReadData(gpointer pdata);
void Enable(int fc, int regstart, int count, int onoff);
void EnableAll(int onoff);
@ -107,15 +106,6 @@ public:
int isRunning();
};
class ModbusCli {
private:
public:
ModbusCli() {};
~ModbusCli() {};
};
#if defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
#define usleep(_us_) Sleep(_us_/1000)
#endif

@ -55,7 +55,7 @@ TCP::~TCP() {
TCP::TCP() {
if (tcpinit == 0) {
#if defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__) || defined(BUILD_WINDOWS)
#ifdef BUILD_WINDOWS
WORD wVersionRequested;
WSADATA wsaData;
@ -96,15 +96,13 @@ TCP::TCP(string h, string p) {
};
/*
* puts the tcp server to listen mode. This code works on linux with IPV4 and IPV6
*/
int TCP::Listen(int port) {
char buffer[NET_BUFFERSIZE];
int err, i;
struct addrinfo hints, *res, *rp;
if (sock > 0) Close();
// FIXME: solution to get both (IPV4 and IPV6) to work at the same time?
bzero (&hints, sizeof (struct addrinfo));
hints.ai_flags = AI_PASSIVE;
#if defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
@ -158,10 +156,12 @@ int TCP::Listen(int port) {
TCP* TCP::Accept() {
fd_set rfds;
struct timeval tv;
int retval;
int retval, err, i;
SOCKET newsock;
struct sockaddr_storage cliaddr;
socklen_t cliaddr_len = sizeof(struct sockaddr_storage);
char host[NET_BUFFERSIZE];
char port[NET_BUFFERSIZE];
TCP *tcp = NULL;
if (sock <= 0) return NULL;
@ -195,6 +195,8 @@ TCP* TCP::Accept() {
int TCP::Connect(string h, string p) {
int i = 0;
remote_host = h;
remote_port = p;
@ -231,7 +233,7 @@ int TCP::Connect() {
err = getaddrinfo(remote_host.c_str(), remote_port.c_str(), &hints, &res);
if (err != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(err));
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
return 0;
}

@ -4,10 +4,9 @@
//
/////////////////////////////////////////////////////////////////////////////////
#include "tcp.h"
#include <UDPTCPNetwork.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#define SIZE_BUFFER 4096
int main (int argc, char **argv) {

@ -4,29 +4,11 @@
//
/////////////////////////////////////////////////////////////////////////////////
#include "tcp.h"
#include <UDPTCPNetwork.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#define SIZE_BUFFER 4096
void swapbytes (unsigned char *p1, unsigned char *p2) {
unsigned char tmp;
tmp = *p2;
*p2 = *p1;
*p1 = tmp;
}
void swapwords (unsigned char *p1, unsigned char *p2) {
uint16_t tmp;
memcpy (&tmp, p2, 2);
memcpy (p2, p1, 2);
memcpy (p1, &tmp, 2);
}
int main (int argc, char **argv) {
unsigned char data[] = { 0x00,0x70,0x00,0x00 , 0x00,0x0B,0x01,0x10 ,
0x00,0x04,0x00,0x02 , 0x04,0xC0,0x02,0x7B ,
@ -45,14 +27,9 @@ int main (int argc, char **argv) {
memset (buffer, 0x00, SIZE_BUFFER);
if (argc < 6) {
printf ("%d\n", argc);
printf("test-fc16 server port register NOSWAP|WSWAP|BSWAP|BWSWAP values...\n");
printf("test-fc16 localhost 502 16 NOSWAP 25.0 0.54 1000.5\n");
printf (" NOSWAP no swapping words\n");
printf (" WordSWAP swap the 16bit words\n");
printf (" ByteSWAP swap the Bytes\n");
printf (" WordByteSWAP swap the bytes and the words\n");
if (argc < 3) {
printf("test-fc16 server port register values...\n");
printf("test-fc16 localhost 502 16 25.0 0.54 1000.5\n");
return 0;
}
@ -66,9 +43,9 @@ int main (int argc, char **argv) {
if (argc == 3) {
tcp.Write((char*)data, sizeof(data));
}
else if (argc > 5) {
else if (argc > 4) {
regstart = atoi (argv[3]);
regcnt = argc-5;
regcnt = argc-4;
printf ("writing %d floats, offset %d\n", regcnt, regstart);
@ -116,8 +93,8 @@ int main (int argc, char **argv) {
pos += sizeof(ui8);
for (i = 0; i < regcnt; i++) {
f = (float) atof(argv[i+5]);
printf ("i: %d string:%s f:%f\n", i, argv[i+5], f);
f = (float) atof(argv[i+4]);
printf ("i: %d string:%s f:%f\n", i, argv[i+4], f);
memcpy (&ui16, &f, sizeof(ui16));
ui16 = htons(ui16);
@ -128,20 +105,10 @@ int main (int argc, char **argv) {
ui16 = htons(ui16);
memcpy (buffer+pos, &ui16, sizeof(ui16));
pos += sizeof(ui16);
if (strstr (argv[4], "Word") != NULL) swapwords((unsigned char*)buffer+pos-4, (unsigned char*)buffer+pos-2);
if (strstr (argv[4], "Byte") != NULL) {
swapbytes((unsigned char*)buffer+pos-4, (unsigned char*)buffer+pos-3);
swapbytes((unsigned char*)buffer+pos-2, (unsigned char*)buffer+pos-1);
}
}
printf ("Wrote %d (out of %d) bytes\n", tcp.Write((char*)buffer, pos), pos);
tcp.Write((char*)buffer, pos);
}
pos = tcp.ReadTimeout(buffer, SIZE_BUFFER, 1000);
printf ("Got %d bytes.\n", pos);
tcp.Close();
return 0;

Loading…
Cancel
Save