Compare commits

...

42 Commits

Author SHA1 Message Date
Steffen Pohle c6f263e3d2 some code cleanup and fixing all the warnings
10 months ago
Steffen Pohle 1c6fb1c3b9 some code cleanup and fixing all the warnings
10 months ago
Steffen Pohle d7faa21676 Update 'README.md'
10 months ago
Steffen Pohle b021f134c1 windows alwas windows.
10 months ago
Steffen Pohle 5cc7e6832c adding bulk load, some little gui improvements.
10 months ago
Steffen Pohle d1d48749df cross build manual fixed.
1 year ago
Steffen Pohle c15d89180d changed build version
1 year ago
Steffen Pohle cd08819ea3 fixed single word/coil write fc5/fc6
2 years ago
Steffen Pohle f0c160a9d6 fixed windows build, somehow not all DLLs are being copied
2 years ago
Steffen Pohle bcbb0514bc fixed windows build part two. missing include of stdint.h
2 years ago
Steffen Pohle 34e4995764 fixed windows build. missing include of stdint.h
2 years ago
Steffen Pohle de29f19930 Makefile target buildwindows will create the zip file
3 years ago
Steffen Pohle e416a16bc8 fixed: ignore faulty requests
3 years ago
Steffen Pohle 49a1b404ee fixed: ignore faulty requests
3 years ago
Steffen Pohle 1d3f575df5 gui issues fixed.
3 years ago
Steffen Pohle 59614436a2 crosscompiling works again
3 years ago
Steffen Pohle c122133021 better debug message
3 years ago
Steffen Pohle 32fec3f9a5 fixing little bugs. closing connection on error.
3 years ago
Steffen Pohle 32f2c40c06 added information message
3 years ago
Steffen Pohle e4574423f4 change readme file
3 years ago
Steffen Pohle 4c8d70d1b0 code cleanup
3 years ago
Steffen Pohle 8cb56a1fed removed testmodbus-client files to new repository.
3 years ago
Steffen Pohle 018d96efb6 preparation for testmodbus-client
3 years ago
Steffen Pohle b1577fbdab prepare server code for an maybe client
3 years ago
Steffen Pohle f6d0ece8a6 prepare server code for an maybe client
3 years ago
Steffen Pohle 010eb60b21 ipv6 is working already
4 years ago
Steffen Pohle de19cc1566 used wrong value, causing a use of uninitialited value
4 years ago
Steffen Pohle 1f4dccc2d8 used wrong value, causing a use of uninitialited value
4 years ago
Steffen Pohle 06c891c283 ignore default config file
4 years ago
Steffen Pohle 493fa1c508 fixing test-fc16.cc windows test function.
4 years ago
Steffen Pohle e734a7b905 adding some new features, like test-fc15, test-fc16 for windows and some byswapping. Also fixing some display issues
4 years ago
Steffen Pohle d0184f7cc2 crosscompiling works.
5 years ago
Steffen Pohle b4fae05f74 crosscompiling works.
5 years ago
Steffen Pohle f530871e99 „HowTo-Cross-Compile.md“ ändern
5 years ago
Steffen Pohle 27b961d98b the HowTo it is back working
5 years ago
Steffen Pohle 4a7eb317b8 Got GTK crosscompiled again. Adding GTK4 because it was so easy to compile.
5 years ago
Steffen Pohle 7ce986644e pango/vairo and atk is back compiling again...
5 years ago
Steffen Pohle 473b3e0d26 lib-glib is compiling
5 years ago
Steffen Pohle 46666fe160 Update 'HowTo-Cross-Compile.md'
5 years ago
Steffen Pohle d9259b1a57 Update 'HowTo-Cross-Compile.md'
5 years ago
Steffen Pohle 69d9592611 converting from pain text to md file
5 years ago
Steffen Pohle bc8849fa22 converting from pain text to md file
5 years ago

1
.gitignore vendored

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

@ -1,3 +1,39 @@
Version 1.0.5
2025-11-29:
- double click on the variable list works.
- added bulk load of CSV files.
- set values within the saved file and thier content
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: Initial Application:

@ -0,0 +1,182 @@
# 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/

@ -1,206 +0,0 @@
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,23 +1,22 @@
.SILENT: help .SILENT: help
VERSION = 1.0.0 VERSION = 1.0.5
APP = testmodbus-server
-include Makefile.rules -include Makefile.rules
OBJECTS = gui.oo main.oo mbsconfig.oo modbus.oo guimodbusdata.oo guivalues.oo json.oo tcp.oo OBJECTSSRV = gui.oo server.oo mbsconfig.oo modbussrv.oo guimodbusdata.oo guivalues.oo json.oo tcp.oo
DISTNAME=testmodbus-server-$(VERSION) DISTNAME=testmodbus-server-$(VERSION)
ifeq ($(TARGET),) ifeq ($(CONFIGSET),)
noconfig: help noconfig: help
endif endif
all: Makefile.rules $(TARGET) all: Makefile.rules testmodbus-server$(TARGETEXT)
help: help:
echo "set up configuration" echo "set up configuration"
echo " make configwindows to generate the windows build" echo " make configwindows to generate the windows build"
echo " make configcross to generate the windows cross build" echo " make configcross to generate the windows cross build"
echo " make configlinux to generate the linix build" echo " make configlinux to generate the linux build"
echo " make buildwindows to generate the build for windows (uses cross compiler)" echo " make buildwindows to generate the build for windows (uses cross compiler)"
configlinux: clean configlinux: clean
@ -41,8 +40,8 @@ config: Makefile.rules
echo "#endif" >> config.h echo "#endif" >> config.h
$(TARGET): $(OBJECTS) testmodbus-server$(TARGETEXT): $(OBJECTSSRV)
$(CPP) -o $(TARGET) $(OBJECTS) $(LDFLAGS) $(LIBS) $(CPP) -o testmodbus-server$(TARGETEXT) $(OBJECTSSRV) $(LDFLAGS) $(LIBS)
.SUFFIXES: .SUFFIXES:
.SUFFIXES: .c .cc .C .cpp .oo .SUFFIXES: .c .cc .C .cpp .oo
@ -51,12 +50,14 @@ $(TARGET): $(OBJECTS)
$(CPP) -o $@ -c $(CPPFLAGS) $< $(CPP) -o $@ -c $(CPPFLAGS) $<
clean: clean:
rm -f *.o *.oo *.c~ *.h~ *.cc~ *.ui~ $(APP) Makefile~ rm -rf TestModbus-Server-$(VERSION)/
rm -f *.o *.oo *.c~ *.h~ *.cc~ *.ui~ testmodbus-server$(TARGETEXT) testmodbus-client$(TARGETEXT) Makefile~
rm -rf *.dll rm -rf *.dll
rm -rf *.exe rm -rf *.exe
rm -rf Makefile.rules rm -rf Makefile.rules
rm -rf test-fc16 rm -rf test-fc16
rm -rf test-fc15 rm -rf test-fc15
rm -rf config.h
dist: clean dist: clean
rm -rf $(DISTNAME) rm -rf $(DISTNAME)
@ -75,36 +76,33 @@ dep:
$(CXX) -MM `ls *.cc` $(CXXFLAGS) > $(DEPENDFILE) $(CXX) -MM `ls *.cc` $(CXXFLAGS) > $(DEPENDFILE)
test-fc16: test-fc16.cc test-fc16: test-fc16.cc
$(CPP) -o test-fc16 test-fc16.cc $(LDFLAGS) -I/usr/include -I/usr/local/include -L/usr/local/lib -L/usr/lib $(CPP) -o test-fc16 test-fc16.cc tcp.cc $(LDFLAGS)
test-fc15: test-fc15.cc test-fc15: test-fc15.cc
$(CPP) -o test-fc15 test-fc15.cc $(LDFLAGS) -I/usr/include -I/usr/local/include -L/usr/local/lib -L/usr/lib $(CPP) -o test-fc15 test-fc15.cc tcp.cc $(LDFLAGS)
copydll: $(TARGET) buildwindows: clean
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)
make clean
make configcross make configcross
make $(TARGET) make $(TARGET) -j 9
cp testmodbus-server.exe TestModbus-Server-$(VERSION)/ make test-fc15
make test-fc16
mkdir TestModbus-Server-$(VERSION)
cp *.exe TestModbus-Server-$(VERSION)/
cp testmodbus-server.ui TestModbus-Server-$(VERSION)/ cp testmodbus-server.ui TestModbus-Server-$(VERSION)/
cp testmodbus-server.png TestModbus-Server-$(VERSION)/ cp testmodbus-server.png TestModbus-Server-$(VERSION)/
cp README.md TestModbus-Server-$(VERSION)/ cp README.md TestModbus-Server-$(VERSION)/
cp Changelog TestModbus-Server-$(VERSION)/ cp Changelog TestModbus-Server-$(VERSION)/
cp LICENSE TestModbus-Server-$(VERSION)/ cp LICENSE TestModbus-Server-$(VERSION)/
tar xvzf $(CROSSENV)/files/winbuild-dll.tgz -C TestModbus-Server-$(VERSION)/ ./copydlls.sh
tar xvzf $(CROSSENV)/files/winbuild-share.tgz -C TestModbus-Server-$(VERSION)/ ./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)/
-include $(DEPENDFILE) -include $(DEPENDFILE)

@ -1,5 +1,6 @@
TARGET = $(APP).exe TARGETEXT = .exe
CONFIGSET = YES
CROSSENV = /opt/W64-cross-compile/ CROSSENV = /opt/W64-cross-compile/
CPP = /usr/bin/x86_64-w64-mingw32-g++ 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 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 @@
TARGET = $(APP) TARGETEXT =
CONFIGSET = YES
CPP = c++ 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 CPPFLAGS = -ggdb -Wall -O0 `pkg-config --cflags gtk+-3.0 gmodule-export-2.0` -Wl,--export-dynamic -I/usr/include -DBUILD_LINUX=1
INCLUDES = INCLUDES =

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

@ -9,14 +9,16 @@ newer version of this software at https://steffen.gulpe.de/modbus-tcpip/
![Image_01](https://steffen.gulpe.de/modbus-tcpip/screenshot-winver1-0-0-regs.PNG) ![Image_01](https://steffen.gulpe.de/modbus-tcpip/screenshot-winver1-0-0-regs.PNG)
![Image_02](https://steffen.gulpe.de/modbus-tcpip/screenshot-winver1-0-0-values.PNG) ![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 configlinux
make make
./testmodbus-server
# Installation # Installation
not supported. not needed.
# Cross Compilation for Windows (build on Debian, target Windows) # Cross Compilation for Windows (build on Debian, target Windows)
@ -32,3 +34,16 @@ needed librarys (needs to prepared, see Makefile for some hints).
For precompiled windows binarys look at this [link](https://steffen.gulpe.de/modbus-tcpip/). For precompiled windows binarys look at this [link](https://steffen.gulpe.de/modbus-tcpip/).
# some usefull functions
Bulk load of csv files works.
NAME,TYPE,FC,REGISTER,VALUE
TEST_FC3_0,FLOAT,3,0,1.5
TEST_FC3_2,FLOAT,3,2,1.6
TEST_FC4_4,FLOAT,4,4,2.6
TEST_FC4_6,FLOAT,4,6,15.6

@ -0,0 +1,44 @@
#!/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

@ -0,0 +1,10 @@
#!/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

275
gui.cc

@ -10,8 +10,9 @@
#endif #endif
#include <stdio.h> #include <stdio.h>
#include <list> #include <list>
#include <sys/time.h>
#include "gui.h" #include "gui.h"
#include "modbus.h" #include "modbussrv.h"
#include "guivalues.h" #include "guivalues.h"
#include "json.h" #include "json.h"
#include "mbsconfig.h" #include "mbsconfig.h"
@ -19,17 +20,28 @@
extern GtkBuilder *_builder_; // work around for threads extern GtkBuilder *_builder_; // work around for threads
extern void addvar_displaywithvalues (gpointer data, GuiValue *v); extern void addvar_displaywithvalues (gpointer data, GuiValue *v);
extern int gnome_dblclick_timeout;
int gui_double_click = 0;
struct timeval doubleclick_time;
/// @brief function is too slow i need <400ms .... :( but we will resit the value jzst in case...
/// @param data
/// @return
gboolean cb_timeout_doubleclick(gpointer data) {
gui_double_click = 0;
return FALSE;
};
////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////
// //
// call back functions // call back functions
// //
gboolean cb_window_delete_event (GtkWidget *widget, GdkEvent *event, gpointer data) {
// GtkBuilder *builder = (GtkBuilder *) data;
gboolean cb_window_delete_event (GtkWidget *widget, gpointer data) {
cb_menu_save(widget, data); cb_menu_save(widget, data);
return FALSE; return FALSE;
} }
@ -44,9 +56,9 @@ void cb_window_show (GtkWidget *widget, gpointer data) {
void cb_menu_new (GtkWidget *widget, gpointer data) { void cb_menu_new (GtkWidget *widget, gpointer data) {
// GtkBuilder *builder = (GtkBuilder *) data; // GtkBuilder *builder = (GtkBuilder *) data;
modbus.EnableAll(0); modbussrv.EnableAll(0);
MBData_EnableAll(0); MBData_EnableAll(0);
modbus.RequestsClear(); modbussrv.RequestsClear();
MBData_ReqReset (); MBData_ReqReset ();
Value_DelAll(); Value_DelAll();
}; };
@ -92,6 +104,91 @@ void cb_menu_open (GtkWidget *widget, gpointer data) {
}; };
void cb_menu_openbulk (GtkWidget *widget, gpointer data) {
GtkBuilder *builder = (GtkBuilder *) data;
GtkWindow *window = GTK_WINDOW (gtk_builder_get_object (builder, "testmodbus-server"));
GtkWidget *dialog;
GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_OPEN;
GtkFileFilter *filter;
gint res;
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
dialog = gtk_file_chooser_dialog_new ("Open Bulk File",
window,
action,
"_Cancel",
GTK_RESPONSE_CANCEL,
"_Open",
GTK_RESPONSE_ACCEPT,
NULL);
filter = gtk_file_filter_new();
gtk_file_filter_add_pattern(filter, "*.csv");
gtk_file_filter_set_name(filter, "CSV File");
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
filter = gtk_file_filter_new();
gtk_file_filter_add_pattern(filter, "*.*");
gtk_file_filter_set_name(filter, "All Files");
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
res = gtk_dialog_run (GTK_DIALOG (dialog));
if (res == GTK_RESPONSE_ACCEPT) {
char *filename;
GtkFileChooser *chooser = GTK_FILE_CHOOSER (dialog);
filename = gtk_file_chooser_get_filename (chooser);
load_bulkfile(filename);
g_free(filename);
}
gtk_widget_destroy (dialog);
};
gboolean cb_vars_btnrelease (GtkWidget *widget, gpointer user_data) {
//
// selfhandling double click :) seem to work
if (gui_double_click == 1 && get_cycletime(&doubleclick_time) < gnome_dblclick_timeout) {
GuiValue v;
GtkTreeIter iter;
GtkTreeModel *model;
GtkWidget *vars = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "vars_tv"));
gchar *v_name;
gchar *v_fc;
gchar *v_reg;
gchar *v_type;
gchar *v_sim;
gchar *v_value;
GtkTreeSelection *sel;
sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(vars));
if (sel && gtk_tree_selection_get_selected(GTK_TREE_SELECTION(sel), &model, &iter)) {
gtk_tree_model_get (model, &iter,
VALDATA_COL_NAME, &v_name,
VALDATA_COL_FC, &v_fc,
VALDATA_COL_REGSTART, &v_reg,
VALDATA_COL_TYPE, &v_type,
VALDATA_COL_SIM, &v_sim,
VALDATA_COL_VALUE, &v_value,
-1);
v.name = v_name;
v.reg = atoi (v_reg);
v.fc = atoi (v_fc);
v.type = v_type;
v.sim = v_sim;
v.value = v_value;
addvar_displaywithvalues(_builder_, &v);
}
}
else {
gui_double_click = 1;
gettimeofday(&doubleclick_time, NULL);
g_timeout_add(gnome_dblclick_timeout, cb_timeout_doubleclick, _builder_);
}
return FALSE;
};
void cb_menu_save (GtkWidget *widget, gpointer data) { void cb_menu_save (GtkWidget *widget, gpointer data) {
// GtkBuilder *builder = (GtkBuilder *) data; // GtkBuilder *builder = (GtkBuilder *) data;
@ -177,21 +274,21 @@ void cb_btn_start (GtkWidget *widget, gpointer data) {
int port = atoi(gtk_entry_get_text(GTK_ENTRY(portentry))); int port = atoi(gtk_entry_get_text(GTK_ENTRY(portentry)));
if (modbus.isRunning()) { if (modbussrv.isRunning()) {
printf ("Stop Server\n"); printf ("Stop Server\n");
modbus.Stop(); modbussrv.Stop();
gtk_widget_set_sensitive(portentry, TRUE); gtk_widget_set_sensitive(portentry, TRUE);
gtk_button_set_label(GTK_BUTTON(widget), _("Start")); gtk_button_set_label(GTK_BUTTON(widget), _("Start"));
} }
else { else {
printf ("Start Server (port: %d)\n", port); printf ("Start Server (port: %d)\n", port);
if (modbus.Start(port)) { if (modbussrv.Start(port)) {
gtk_button_set_label(GTK_BUTTON(widget),_("Stop")); gtk_button_set_label(GTK_BUTTON(widget),_("Stop"));
gtk_widget_set_sensitive(portentry, FALSE); gtk_widget_set_sensitive(portentry, FALSE);
} }
usleep (250000); usleep (250000);
if (modbus.isRunning() == 0) { if (modbussrv.isRunning() == 0) {
modbus.Stop(); modbussrv.Stop();
displayerror("modbus server could not been started.\nSee console output for errors."); displayerror("modbus server could not been started.\nSee console output for errors.");
gtk_widget_set_sensitive(portentry, TRUE); gtk_widget_set_sensitive(portentry, TRUE);
gtk_button_set_label(GTK_BUTTON(widget), _("Start")); gtk_button_set_label(GTK_BUTTON(widget), _("Start"));
@ -256,9 +353,8 @@ void addvar_displaywithvalues (gpointer data, GuiValue *v) {
vn.value = gtk_entry_get_text(GTK_ENTRY(value)); // load the from the entry 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)) { if (Value_SetValue(vn.value, vn.type, vn.fc, &regstowrite, regvals)) {
modbus.SetRegValue(vn.fc, vn.reg, regstowrite, (uint16_t*)regvals); modbussrv.SetRegValue(vn.fc, vn.reg, regstowrite, (uint16_t*)regvals);
} }
} }
} }
gtk_widget_hide(GTK_WIDGET(dlg)); gtk_widget_hide(GTK_WIDGET(dlg));
@ -335,23 +431,21 @@ gboolean cb_thread_network_data_add (gpointer data) {
struct modbus_data *mbdata = (struct modbus_data *)data; struct modbus_data *mbdata = (struct modbus_data *)data;
std::string text; std::string text;
char timetext[255]; char timetext[255];
GtkTextTag *tag_datetime;
GtkTextTag *tag_data;
GtkTextTag *tag_info;
GtkTextTag *tag_modbus;
time_t _tm =time(NULL); time_t _tm =time(NULL);
struct tm * curtime = localtime (&_tm); struct tm * curtime = localtime (&_tm);
static int _once = 0; static int _once = 0;
if (_once == 0) { if (_once == 0) {
_once = 1; _once = 1;
tag_datetime = gtk_text_buffer_create_tag (textbuffer, "Date_Time", gtk_text_buffer_create_tag (textbuffer, "Date_Time",
"foreground", "blue", "style", PANGO_WEIGHT_BOLD, "family", "Monospace", NULL); "foreground", "blue", "style", PANGO_WEIGHT_BOLD, "family", "Monospace", NULL);
tag_data = gtk_text_buffer_create_tag (textbuffer, "Data", gtk_text_buffer_create_tag (textbuffer, "Data",
"foreground", "black", "style", PANGO_WEIGHT_NORMAL, "family", "Monospace", NULL); "foreground", "black", "style", PANGO_WEIGHT_NORMAL, "family", "Monospace", NULL);
tag_info = gtk_text_buffer_create_tag (textbuffer, "Info", gtk_text_buffer_create_tag (textbuffer, "Info",
"foreground", "green", "style", PANGO_WEIGHT_THIN, "family", "Sans", NULL); "foreground", "green", "style", PANGO_WEIGHT_THIN, "family", "Sans", NULL);
tag_modbus = gtk_text_buffer_create_tag (textbuffer, "Modbus", gtk_text_buffer_create_tag (textbuffer, "Error",
"foreground", "red", "style", PANGO_WEIGHT_BOLD, "family", "Sans", NULL);
gtk_text_buffer_create_tag (textbuffer, "Modbus",
"foreground", "black", "style", PANGO_WEIGHT_NORMAL, "family", "Sans", NULL); "foreground", "black", "style", PANGO_WEIGHT_NORMAL, "family", "Sans", NULL);
} }
strftime (timetext, 255, "%H:%M:%S", curtime); strftime (timetext, 255, "%H:%M:%S", curtime);
@ -360,7 +454,7 @@ gboolean cb_thread_network_data_add (gpointer data) {
// build hex dump // build hex dump
// //
text = ""; text = "";
for (int i = 0; i < mbdata->bufferlen; i++) { for (size_t i = 0; i < mbdata->bufferlen; i++) {
unsigned char c = mbdata->buffer[i]; unsigned char c = mbdata->buffer[i];
char hexnum[] = "0123456789ABCDEF"; char hexnum[] = "0123456789ABCDEF";
@ -368,11 +462,12 @@ gboolean cb_thread_network_data_add (gpointer data) {
else if (i % 32 == 0) text += "\n "; else if (i % 32 == 0) text += "\n ";
else if (i % 4 == 0 && i > 0) text += " : "; else if (i % 4 == 0 && i > 0) text += " : ";
else if (i % 2 == 0 && i > 0) text += ":"; else if (i % 2 == 0 && i > 0) text += ":";
// else text += " ";
text += hexnum[c/16]; text += hexnum[c/16];
text += hexnum[c%16]; text += hexnum[c%16];
} }
text += "\n";
gtk_text_buffer_get_start_iter(textbuffer, &start); gtk_text_buffer_get_start_iter(textbuffer, &start);
gtk_text_buffer_insert_with_tags_by_name(textbuffer, &start, text.c_str(), -1, "Data", NULL); gtk_text_buffer_insert_with_tags_by_name(textbuffer, &start, text.c_str(), -1, "Data", NULL);
@ -400,23 +495,33 @@ gboolean cb_thread_network_data_add (gpointer data) {
} }
else { else {
text = text + " Registers: " + std::to_string (mbdata->regstart); text = text + " Registers: " + std::to_string (mbdata->regstart);
text = text + " Bytes: " + std::to_string (mbdata->regcnt); text = text + " Cnt: " + std::to_string (mbdata->regcnt);
} }
} }
text = text + "\n"; text = text + " Bytecnt: "+ std::to_string (mbdata->bytecnt) +"\n";
gtk_text_buffer_get_start_iter(textbuffer, &start); gtk_text_buffer_get_start_iter(textbuffer, &start);
gtk_text_buffer_insert_with_tags_by_name(textbuffer, &start, text.c_str(), -1, "Modbus", NULL); 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);
// //
text =""; // Hostname
text += mbdata->hostname; 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_get_start_iter(textbuffer, &start);
gtk_text_buffer_insert_with_tags_by_name(textbuffer, &start, text.c_str(), -1, "Info", NULL); 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 // add date
@ -448,9 +553,7 @@ gboolean cb_thread_network_text_add (gpointer data) {
char timetext[255]; char timetext[255];
GtkWidget *textview = GTK_WIDGET(gtk_builder_get_object (_builder_, "network_text")); GtkWidget *textview = GTK_WIDGET(gtk_builder_get_object (_builder_, "network_text"));
GtkTextBuffer *textbuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview)); GtkTextBuffer *textbuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview));
GtkTextIter start, end; GtkTextIter start;
GtkTextTag *tag_datetime;
GtkTextTag *tag_info;
char *textprm = (char*) data; char *textprm = (char*) data;
time_t _tm =time(NULL); time_t _tm =time(NULL);
struct tm * curtime = localtime (&_tm); struct tm * curtime = localtime (&_tm);
@ -458,17 +561,14 @@ gboolean cb_thread_network_text_add (gpointer data) {
if (_once == 0) { if (_once == 0) {
_once = 1; _once = 1;
tag_datetime = gtk_text_buffer_create_tag (textbuffer, "Date_Time", gtk_text_buffer_create_tag (textbuffer, "Date_Time",
"foreground", "blue", "style", PANGO_WEIGHT_BOLD, "family", "Monospace", NULL); "foreground", "blue", "style", PANGO_WEIGHT_BOLD, "family", "Monospace", NULL);
tag_info = gtk_text_buffer_create_tag (textbuffer, "Connection", gtk_text_buffer_create_tag (textbuffer, "Connection",
"foreground", "red", "style", PANGO_WEIGHT_BOLD, "family", "Sans", NULL); "foreground", "red", "style", PANGO_WEIGHT_BOLD, "family", "Sans", NULL);
} }
strftime (timetext, 255, "%H:%M:%S", curtime); strftime (timetext, 255, "%H:%M:%S", curtime);
//
// build hex dump
//
// //
// //
text =""; text ="";
@ -501,10 +601,7 @@ gboolean cb_thread_status (gpointer data) {
void cb_networkdata_show (GtkWidget *widget, gpointer data) { void cb_networkdata_show (GtkWidget *widget, gpointer data) {
GtkWidget *textview = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(data), "network_text")); GtkWidget *textview = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(data), "network_text"));
GtkTextBuffer *textbuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview)); gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview));
printf ("*************************** \n");
}; };
void cb_addvar_close (GtkWidget *widget, gpointer data) { void cb_addvar_close (GtkWidget *widget, gpointer data) {
@ -529,6 +626,7 @@ void displayerror (string error) {
gtk_widget_destroy(dialog); gtk_widget_destroy(dialog);
} }
void cb_addvar_addedit (GtkWidget *widget, gpointer data) { void cb_addvar_addedit (GtkWidget *widget, gpointer data) {
GtkBuilder *builder = (GtkBuilder *) data; GtkBuilder *builder = (GtkBuilder *) data;
GtkWidget *dlg = GTK_WIDGET (gtk_builder_get_object (builder, "addvar")); GtkWidget *dlg = GTK_WIDGET (gtk_builder_get_object (builder, "addvar"));
@ -561,7 +659,7 @@ void cb_menu_about(GtkWidget *widget, gpointer data) {
GtkWidget *dlg = GTK_WIDGET (gtk_builder_get_object (builder, "dlgabout")); GtkWidget *dlg = GTK_WIDGET (gtk_builder_get_object (builder, "dlgabout"));
GtkWidget *label = GTK_WIDGET (gtk_builder_get_object (builder, "dlgabout_version")); GtkWidget *label = GTK_WIDGET (gtk_builder_get_object (builder, "dlgabout_version"));
gtk_label_set_text(GTK_LABEL(label), VERSION); gtk_label_set_text(GTK_LABEL(label), VERSION);
gint result = gtk_dialog_run(GTK_DIALOG(dlg)); gtk_dialog_run(GTK_DIALOG(dlg));
gtk_widget_hide(GTK_WIDGET(dlg)); gtk_widget_hide(GTK_WIDGET(dlg));
return; return;
@ -575,19 +673,19 @@ void cb_about_btnclose(GtkWidget *widget, gpointer data) {
} }
void cb_btn_enableall (GtkWidget *widget, gpointer data) { void cb_btn_enableall (GtkWidget *widget, gpointer data) {
modbus.EnableAll(1); modbussrv.EnableAll(1);
MBData_EnableAll(1); MBData_EnableAll(1);
}; };
void cb_btn_disableall (GtkWidget *widget, gpointer data) { void cb_btn_disableall (GtkWidget *widget, gpointer data) {
modbus.EnableAll(0); modbussrv.EnableAll(0);
MBData_EnableAll(0); MBData_EnableAll(0);
}; };
void cb_btn_clearreq (GtkWidget *widget, gpointer data) { void cb_btn_clearreq (GtkWidget *widget, gpointer data) {
modbus.RequestsClear(); modbussrv.RequestsClear();
MBData_ReqReset (); MBData_ReqReset ();
}; };
@ -620,7 +718,7 @@ void cb_btn_enablevalues (GtkWidget *widget, gpointer data) {
break; break;
} }
modbus.Enable(atoi(v_fc), atoi(v_reg), Value_GetSize(v_type), 1); modbussrv.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); MBData_Enable(atoi(v_fc), atoi(v_reg), Value_GetSize(v_type), 1);
if (v_name != NULL) free (v_name); if (v_name != NULL) free (v_name);
@ -718,12 +816,10 @@ void load_file(std::string fn) {
GtkWidget *guiautovalue = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "conf_autoaddvalues")); GtkWidget *guiautovalue = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "conf_autoaddvalues"));
GtkWidget *guiport = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "port_entry")); GtkWidget *guiport = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "port_entry"));
GuiValue g; GuiValue g;
int autoadd = 0;
modbus.EnableAll(0); modbussrv.EnableAll(0);
MBData_EnableAll(0); MBData_EnableAll(0);
modbus.RequestsClear(); modbussrv.RequestsClear();
MBData_ReqReset (); MBData_ReqReset ();
Value_DelAll(); Value_DelAll();
std::string confdata; std::string confdata;
@ -759,15 +855,88 @@ void load_file(std::string fn) {
for (i = 0; json.GetObjectIdx("values", i, &value); i++) { for (i = 0; json.GetObjectIdx("values", i, &value); i++) {
uint16_t regvals[4];
int regstowrite = 1;
value.GetValue("name", &g.name); value.GetValue("name", &g.name);
value.GetValue("type", &g.type); value.GetValue("type", &g.type);
value.GetValue("sim", &g.sim); value.GetValue("sim", &g.sim);
value.GetValue("value", &g.value); value.GetValue("value", &g.value);
value.GetValue("fc", &temp); g.fc = atoi(temp.c_str()); value.GetValueInt("fc", &g.fc);
value.GetValue("reg", &temp); g.reg = atoi(temp.c_str()); value.GetValueInt("reg", &g.reg);
Value_Add(&g); Value_Add(&g);
if (Value_SetValue(g.value, g.type, g.fc, &regstowrite, regvals)) {
modbussrv.SetRegValue(g.fc, g.reg, regstowrite, (uint16_t*)regvals);
}
} }
}; };
void load_bulkfile(std::string fn) {
GuiValue g;
FILE *f;
char buffer[FILEBUFFER];
char *pos, *next;
JSONParse json;
JSONParse value;
std::string temp;
uint16_t regvals[4];
int regstowrite = 1;
printf ("%s\n", __FUNCTION__);
f = fopen(fn.c_str(),"r");
if (f != NULL) {
while (!feof(f)) {
// NAME,TYPE,FC,REG,VALUE
fgets (buffer, FILEBUFFER, f);
// name
pos = buffer;
if ((next = strchr(pos, ',')) == NULL) {
printf ("load bulk: could not find ','\n");
continue;
}
*next = 0;
g.name = pos;
// type
pos = next+1;
if ((next = strchr(pos, ',')) == NULL) continue;
*next = 0;
g.type = pos;
// fc
pos = next+1;
if ((next = strchr(pos, ',')) == NULL) continue;
*next = 0;
g.fc = atoi(pos);
// reg
pos = next+1;
if ((next = strchr(pos, ',')) == NULL) continue;
*next = 0;
g.reg = atoi(pos);
// value
pos = next+1;
g.value = pos;
printf ("%s -> %s\n", pos, g.value.c_str());
g.sim = "NONE";
Value_Add(&g);
printf ("%s -> %s\n", pos, g.value.c_str());
regstowrite = 1;
if (Value_SetValue(g.value, g.type, g.fc, &regstowrite, regvals)) {
modbussrv.SetRegValue(g.fc, g.reg, regstowrite, (uint16_t*)regvals);
printf ("%s add %s type:%s with value %s\n", __FUNCTION__, g.name.c_str(), g.type.c_str(), g.value.c_str());
}
else printf ("%s add %s without value\n", __FUNCTION__, g.name.c_str());
}
fclose (f);
}
else printf ("error on open bulk: %s\n", strerror(errno));
};

11
gui.h

@ -15,14 +15,16 @@
#include <iostream> #include <iostream>
#include <list> #include <list>
#define BUILDER_FILE "testmodbus-server.ui"
#include "guivalues.h" #include "guivalues.h"
#include "guimodbusdata.h" #include "guimodbusdata.h"
#define LEN_FIELD 128
std::string to_hex16 (int v); std::string to_hex16 (int v);
extern uint16_t modbusdata[4][0x10000]; extern uint16_t modbusdata[4][0x10000];
void load_file(std::string fn); void load_file(std::string fn);
void load_bulkfile(std::string fn);
void save_file(std::string fn); void save_file(std::string fn);
void displayerror (string error); void displayerror (string error);
@ -36,10 +38,10 @@ extern "C" {
// main windows call backs // main windows call backs
// //
G_MODULE_EXPORT void cb_window_show (GtkWidget *widget, gpointer data); G_MODULE_EXPORT void cb_window_show (GtkWidget *widget, gpointer data);
G_MODULE_EXPORT gboolean cb_window_delete_event (GtkWidget *widget, G_MODULE_EXPORT gboolean cb_window_delete_event (GtkWidget *widget, gpointer data);
GdkEvent *event, gpointer data);
G_MODULE_EXPORT void cb_menu_new (GtkWidget *widget, gpointer data); G_MODULE_EXPORT void cb_menu_new (GtkWidget *widget, gpointer data);
G_MODULE_EXPORT void cb_menu_open (GtkWidget *widget, gpointer data); G_MODULE_EXPORT void cb_menu_open (GtkWidget *widget, gpointer data);
G_MODULE_EXPORT void cb_menu_openbulk (GtkWidget *widget, gpointer data);
G_MODULE_EXPORT void cb_menu_save (GtkWidget *widget, gpointer data); G_MODULE_EXPORT void cb_menu_save (GtkWidget *widget, gpointer data);
G_MODULE_EXPORT void cb_menu_saveas (GtkWidget *widget, gpointer data); G_MODULE_EXPORT void cb_menu_saveas (GtkWidget *widget, gpointer data);
G_MODULE_EXPORT void cb_menu_quit (GtkWidget *widget, gpointer data); G_MODULE_EXPORT void cb_menu_quit (GtkWidget *widget, gpointer data);
@ -59,6 +61,7 @@ G_MODULE_EXPORT void cb_btn_delvar (GtkWidget *widget, gpointer data);
// Add Variable Dialog // Add Variable Dialog
G_MODULE_EXPORT void cb_addvar_close (GtkWidget *widget, gpointer data); G_MODULE_EXPORT void cb_addvar_close (GtkWidget *widget, gpointer data);
G_MODULE_EXPORT void cb_addvar_addedit (GtkWidget *widget, gpointer data); G_MODULE_EXPORT void cb_addvar_addedit (GtkWidget *widget, gpointer data);
G_MODULE_EXPORT gboolean cb_vars_btnrelease (GtkWidget *widget, gpointer user_data);
// //
// Register Buttons // Register Buttons

@ -12,9 +12,9 @@
#include "gui.h" #include "gui.h"
#include "guimodbusdata.h" #include "guimodbusdata.h"
#include "modbus.h" #include "modbussrv.h"
extern Modbus modbus; extern ModbusSrv modbussrv;
extern GtkBuilder *_builder_; // work around for threads extern GtkBuilder *_builder_; // work around for threads
void mbdata_enabletoggled_cb(GtkCellRendererToggle *cellrenderer, char *path, gpointer data); 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); gtk_tree_store_set (store, &secondlevel, MBDATA_COL_FCREG, regname1.c_str(),-1);
} }
modbus.GetRegister(fc, regnum, &r); modbussrv.GetRegister(fc, regnum, &r);
regname2 = "FC" + std::to_string(fc) + " " + std::to_string(regnum); regname2 = "FC" + std::to_string(fc) + " " + std::to_string(regnum);
if (fc < 3) { if (fc < 3) {
if (r.value == 0) txt = "false"; 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, gtk_tree_store_set(GTK_TREE_STORE(model), &iter,
MBDATA_COL_ENABLED, enabled, MBDATA_COL_ENABLED, enabled,
-1); -1);
modbus.Enable(fc, reg, 1, enabled); modbussrv.Enable(fc, reg, 1, enabled);
g_free (fcreg); g_free (fcreg);
fcreg = NULL; fcreg = NULL;
} }
@ -166,16 +166,15 @@ void MBData_ChangeRegs (int fc, int regstart, int count, ModbusRegister *r) {
GtkWidget *mbdata = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "regs_tv")); GtkWidget *mbdata = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "regs_tv"));
GtkTreeIter iter; GtkTreeIter iter;
GtkTreeModel *model; GtkTreeModel *model;
int i,j; int i;
gchar *v_fcreg = NULL; gchar *v_fcreg = NULL;
string path; string path;
char value[16] = "0000"; char value[16] = "0000";
char hex[] = "0123456789ABCDEF";
model = gtk_tree_view_get_model(GTK_TREE_VIEW(mbdata)); model = gtk_tree_view_get_model(GTK_TREE_VIEW(mbdata));
for (i = 0; regstart < MAXREG && i < count; i++, regstart++) { for (i = 0; regstart < MAXREG && i < count; i++, regstart++) {
for (j = 0; j < 4; j++) value[3-j] = hex[(r[i].value >> j)%16]; strncpy(value, to_hex16(r[i].value).c_str(), 16);
path = std::to_string(fc-1) + ":" + std::to_string(regstart / STEPREG) + ":" + std::to_string(regstart % STEPREG); 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()); // 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_ #define _GUIMODBUSDATA_H_
#include "gui.h" #include "gui.h"
#include "modbus.h" #include "modbussrv.h"
#include "guivalues.h" #include "guivalues.h"
enum { enum {

@ -16,10 +16,10 @@
#include "gui.h" #include "gui.h"
#include "config.h" #include "config.h"
#include "mbsconfig.h" #include "mbsconfig.h"
#include "modbus.h" #include "modbussrv.h"
#include "guivalues.h" #include "guivalues.h"
void Value_ModStore(GtkTreeModel *model, GtkTreeIter *iter, GuiValue *g);
extern GtkBuilder *_builder_; // work around for threads extern GtkBuilder *_builder_; // work around for threads
GuiValue::GuiValue() { GuiValue::GuiValue() {
@ -226,15 +226,21 @@ gboolean Value_Loop(gpointer data) {
v.reg = atoi(v_reg); v.reg = atoi(v_reg);
v.type = v_type; v.type = v_type;
v.sim = v_sim; v.sim = v_sim;
Value_Set (&v);
changed = Value_Simulation(&v); changed = Value_Simulation(&v);
if (changed) { if (changed) {
uint16_t regvals[4]; uint16_t regvals[4];
int regstowrite = 1; int regstowrite = 1;
if (Value_SetValue(v.value, v.type, v.fc, &regstowrite, regvals)) { if (Value_SetValue(v.value, v.type, v.fc, &regstowrite, regvals)) {
modbus.SetRegValue(v.fc, v.reg, regstowrite, (uint16_t*)regvals); modbussrv.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); g_free(v_name);
@ -266,6 +272,7 @@ void Value_Set(GuiValue *g) {
if (strcmp(v_name, g->name.c_str()) == 0) { if (strcmp(v_name, g->name.c_str()) == 0) {
Value_ModStore(model, &iter, g); Value_ModStore(model, &iter, g);
changed = 1; changed = 1;
break;
} }
g_free(v_name); g_free(v_name);
} }
@ -297,13 +304,12 @@ void Value_Add(GuiValue *g) {
Value_ModStore(model, &iter, g); Value_ModStore(model, &iter, g);
count = Value_GetSize(g->type); count = Value_GetSize(g->type);
modbus.Enable(g->fc, g->reg, count, 1); modbussrv.Enable(g->fc, g->reg, count, 1);
MBData_Enable(g->fc, g->reg, count, 1); MBData_Enable(g->fc, g->reg, count, 1);
} }
void Value_ModStore(GtkTreeModel *model, GtkTreeIter *iter, GuiValue *g) { void Value_ModStore(GtkTreeModel *model, GtkTreeIter *iter, GuiValue *g) {
g->value = Value_GetValue(g->fc, g->reg, g->type);
gtk_list_store_set(GTK_LIST_STORE(model), iter, gtk_list_store_set(GTK_LIST_STORE(model), iter,
VALDATA_COL_NAME, g->name.c_str(), VALDATA_COL_NAME, g->name.c_str(),
VALDATA_COL_FC, std::to_string(g->fc).c_str(), VALDATA_COL_FC, std::to_string(g->fc).c_str(),
@ -312,17 +318,11 @@ void Value_ModStore(GtkTreeModel *model, GtkTreeIter *iter, GuiValue *g) {
VALDATA_COL_VALUE, Value_GetValue(g->fc, g->reg, g->type).c_str(), VALDATA_COL_VALUE, Value_GetValue(g->fc, g->reg, g->type).c_str(),
VALDATA_COL_SIM, g->sim.c_str(), VALDATA_COL_SIM, g->sim.c_str(),
-1); -1);
// for (int i = 0; i < 10; i++) {
// float *f = (float *)&modbusdata[2][i];
// printf ("%f ", *f);
// }
// printf ("\n");
}; };
/////////////////////////////////////////////////// ///////////////////////////////////////////////////
// return valuze as string // return value as string
std::string Value_GetValue(int fc, int reg, string type) { std::string Value_GetValue(int fc, int reg, string type) {
std::string result = ""; std::string result = "";
@ -372,6 +372,9 @@ std::string Value_GetValue(int fc, int reg, string type) {
int c; int c;
for (result = "", c = 0; c < 16; c++) { for (result = "", c = 0; c < 16; c++) {
if (c % 8 == 0 && c != 0) result = ":" + result;
else if (c % 4 == 0 && c != 0) result = "." + result;
if (modbusdata[fc-1][reg] & (1<<c)) result = "1" + result; if (modbusdata[fc-1][reg] & (1<<c)) result = "1" + result;
else result = "0" + result; else result = "0" + result;
} }
@ -385,9 +388,15 @@ std::string Value_GetValue(int fc, int reg, string type) {
} }
/// @brief convert the value to the memory representation of the register
/// @param value value to convert
/// @param type type
/// @param fc function code
/// @param regcnt return: contains number of changed registers
/// @param regvalues return: contains registers to change (must be at last 4 bytes wide)
/// @return
int Value_SetValue(string value, string type, int fc, int *regcnt, uint16_t *regvalues) { int Value_SetValue(string value, string type, int fc, int *regcnt, uint16_t *regvalues) {
uint8_t data[4]; uint8_t data[4];
if (fc == 1 || fc == 2) { if (fc == 1 || fc == 2) {
*regcnt = 1; *regcnt = 1;
if (value.compare("false") == 0 || value.compare("0") == 0) if (value.compare("false") == 0 || value.compare("0") == 0)
@ -416,6 +425,19 @@ int Value_SetValue(string value, string type, int fc, int *regcnt, uint16_t *reg
memcpy (regvalues, &i16, 2); memcpy (regvalues, &i16, 2);
*regcnt = 1; *regcnt = 1;
} }
else if (type.compare("BOOL") == 0) {
uint16_t i16;
int ival;
std::size_t c;
for (ival = 0, c = 0; c < value.length(); c++) {
if (value[c] == '0') ival = ival << 1;
else if (value[c] == '1') ival = (ival << 1) + 1;
}
i16 = (uint16_t) ival;
memcpy (regvalues, &i16, 2);
*regcnt = 1;
}
} }
return 1; return 1;

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

@ -43,7 +43,7 @@ void JSONParse::Clear() {
// read every element and keep only this in memory. // read every element and keep only this in memory.
// //
int JSONParse::Set(string json) { int JSONParse::Set(string json) {
int i; std::size_t i;
int step; int step;
int level; int level;
bool ignorenext; bool ignorenext;
@ -205,23 +205,21 @@ int JSONParse::GetValue(string varname, string *dest) {
int JSONParse::GetValueInt(string varname, int *dest) { int JSONParse::GetValueInt(string varname, int *dest) {
string s; string s;
int res = GetValue(varname, &s); int res = GetValue(varname, &s);
if (res) { if (res) *dest = atoi (s.c_str());
*dest = atoi (s.c_str());
return 1; return res;
}
return 0;
}; };
int JSONParse::GetValueInt64(string varname, int64_t *dest) { int JSONParse::GetValueInt64(string varname, int64_t *dest) {
string s; string s;
int res = GetValue(varname, &s); int res = GetValue(varname, &s);
if (res) { if (res) *dest = atol (s.c_str());
*dest = atol (s.c_str());
return 1; return res;
}
return 0;
}; };
@ -244,7 +242,8 @@ int JSONParse::GetObject(string varname, JSONParse *dest) {
#define MAXRECURSIVE 255 #define MAXRECURSIVE 255
int JSONParse::GetIdx(string src, int idx, string *dest) { int JSONParse::GetIdx(string src, int idx, string *dest) {
char recursive[MAXRECURSIVE]; char recursive[MAXRECURSIVE];
int i = 0, rcnt = 0, cnt = 0; int rcnt = 0, cnt = 0;
std::size_t i;
(*dest) = ""; (*dest) = "";
// printf("\n***************************************idx:%d\n", idx); // printf("\n***************************************idx:%d\n", idx);

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

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

@ -6,27 +6,58 @@
#include <errno.h> #include <errno.h>
#include <glib.h> #include <glib.h>
#include <sys/time.h>
#if defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__) #if defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
#else #else
#include <unistd.h> /* close() */ #include <unistd.h> /* close() */
#endif #endif
#include "gui.h" #include "gui.h"
#include "modbus.h" #include "modbussrv.h"
#include "mbsconfig.h" #include "mbsconfig.h"
#include "config.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 // C / C++ Wrapper
gpointer _ServerThread (gpointer data) { gpointer _ServerThread (gpointer data) {
modbus.ServerThread (); modbussrv.ServerThread ();
return NULL; return NULL;
}; };
// //
// //
Modbus::Modbus () { ModbusSrv::ModbusSrv () {
onchangecallback = NULL; onchangecallback = NULL;
ModbusRegister r = {0, false, 0, false}; ModbusRegister r = {0, false, 0, false};
port = 502; port = 502;
@ -44,7 +75,7 @@ Modbus::Modbus () {
} }
}; };
Modbus::~Modbus () { ModbusSrv::~ModbusSrv () {
for (int i = 0; i < MODBUS_MAXCLIENTS; i++) { for (int i = 0; i < MODBUS_MAXCLIENTS; i++) {
if (clients[i] != NULL) { if (clients[i] != NULL) {
delete clients[i]; delete clients[i];
@ -54,12 +85,12 @@ Modbus::~Modbus () {
}; };
int Modbus::isRunning() { int ModbusSrv::isRunning() {
return tcpserver.IsListen(); return tcpserver.IsListen();
}; };
int Modbus::Start(int serverport) { int ModbusSrv::Start(int serverport) {
port = serverport; port = serverport;
serverthread = g_thread_new("network thread", _ServerThread, NULL); serverthread = g_thread_new("network thread", _ServerThread, NULL);
@ -67,7 +98,7 @@ int Modbus::Start(int serverport) {
return 1; return 1;
}; };
void Modbus::Stop() { void ModbusSrv::Stop() {
g_mutex_lock(&servermutex); g_mutex_lock(&servermutex);
for (int i = 0; i < MODBUS_MAXCLIENTS; i++) { for (int i = 0; i < MODBUS_MAXCLIENTS; i++) {
if (clients[i] != NULL) { if (clients[i] != NULL) {
@ -80,7 +111,7 @@ void Modbus::Stop() {
}; };
void Modbus::CloseConnection(int slot) { void ModbusSrv::CloseConnection(int slot) {
if (slot < 0 || slot >= MODBUS_MAXCLIENTS) return; // slot out of bound if (slot < 0 || slot >= MODBUS_MAXCLIENTS) return; // slot out of bound
if (clients[slot] != NULL) if (clients[slot] != NULL)
delete clients[slot]; delete clients[slot];
@ -88,30 +119,12 @@ void Modbus::CloseConnection(int slot) {
}; };
void Modbus::SetCallback (gboolean (*callback_func)(gpointer data)) { void ModbusSrv::SetCallback (gboolean (*callback_func)(gpointer data)) {
onchangecallback = callback_func; 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 void ModbusSrv::ServerThread() {
if (clients[slot] == NULL) return; // slot not connected?
len = clients[slot]->Read(inbuffer, MODBUS_IOBUFFER);
if (len < 0) {
CloseConnection(slot);
}
};
void Modbus::ServerThread() {
int keep_running = 1; int keep_running = 1;
int ret; int ret;
struct timeval cycletimestamp = { 0 }; struct timeval cycletimestamp = { 0 };
@ -148,12 +161,18 @@ void Modbus::ServerThread() {
char *msg; char *msg;
clients[slot] = tcp; clients[slot] = tcp;
msg = (char*) malloc (255); msg = (char*) malloc (255);
snprintf (msg, 255, "new connection from %s\n", clients[slot]->GetRemoteAddr().c_str()); snprintf (msg, 255, "new connection from %s, use slot:%d\n", clients[slot]->GetRemoteAddr().c_str(), slot);
gdk_threads_add_idle(cb_thread_network_text_add, msg); gdk_threads_add_idle(cb_thread_network_text_add, msg);
} }
else { else {
// no free slot, accept and close right away. // no free slot, accept and close right away.
if (tcp) delete tcp; 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;
}
} }
} }
@ -164,6 +183,10 @@ void Modbus::ServerThread() {
if (clients[slot] != NULL) { if (clients[slot] != NULL) {
len = clients[slot]->ReadTimeout(inbuffer, MODBUS_IOBUFFER, 0); len = clients[slot]->ReadTimeout(inbuffer, MODBUS_IOBUFFER, 0);
if (len < 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]; delete clients[slot];
clients[slot] = NULL; clients[slot] = NULL;
} }
@ -191,9 +214,12 @@ void Modbus::ServerThread() {
mbindata->transactionid = 0; mbindata->transactionid = 0;
mbindata->protoolid = 0; mbindata->protoolid = 0;
Decode(mbindata); if (Decode(mbindata) == 0) {
mbindata->direction = 2; // mark as error
gdk_threads_add_idle(cb_thread_network_data_add, mbindata);
continue;
}
gdk_threads_add_idle(cb_thread_network_data_add, mbindata); gdk_threads_add_idle(cb_thread_network_data_add, mbindata);
// //
// fill in outdata // fill in outdata
// //
@ -218,8 +244,11 @@ void Modbus::ServerThread() {
} }
else { else {
char *txt = (char*)malloc(255); char *txt = (char*)malloc(255);
snprintf (txt, 255, "error on processing message\n"); snprintf (txt, 255, "error on processing message, close connection\n");
gdk_threads_add_idle(cb_thread_network_text_add, txt); gdk_threads_add_idle(cb_thread_network_text_add, txt);
delete clients[slot];
clients[slot] = NULL;
} }
} }
else if (mbindata->fc == 5 || mbindata->fc == 6) { else if (mbindata->fc == 5 || mbindata->fc == 6) {
@ -228,8 +257,10 @@ void Modbus::ServerThread() {
} }
else { else {
char *txt = (char*)malloc(255); char *txt = (char*)malloc(255);
snprintf (txt, 255, "error on processing message\n"); snprintf (txt, 255, "error on processing message, close connection\n");
gdk_threads_add_idle(cb_thread_network_text_add, txt); gdk_threads_add_idle(cb_thread_network_text_add, txt);
delete clients[slot];
clients[slot] = NULL;
} }
} }
else if (mbindata->fc == 15 || mbindata->fc == 16) { else if (mbindata->fc == 15 || mbindata->fc == 16) {
@ -238,8 +269,10 @@ void Modbus::ServerThread() {
} }
else { else {
char *txt = (char*)malloc(255); char *txt = (char*)malloc(255);
snprintf (txt, 255, "error on processing message\n"); snprintf (txt, 255, "error on processing message, close connection\n");
gdk_threads_add_idle(cb_thread_network_text_add, txt); 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); gdk_threads_add_idle(cb_thread_network_data_add, mboutdata);
@ -267,7 +300,7 @@ void Modbus::ServerThread() {
// return 0 on error // return 0 on error
int Modbus::WorkerAndEncodeRead(struct modbus_data *mbin, struct modbus_data *mbout) { int ModbusSrv::WorkerAndEncodeRead(struct modbus_data *mbin, struct modbus_data *mbout) {
// //
// to prevent race condition and invalid data: servermutex must be already locked // to prevent race condition and invalid data: servermutex must be already locked
// buffer on outdata must be of size 0x10000 // buffer on outdata must be of size 0x10000
@ -414,40 +447,15 @@ int Modbus::WorkerAndEncodeRead(struct modbus_data *mbin, struct modbus_data *mb
} }
int Modbus::WorkerAndEncodeWriteSingle(struct modbus_data *mbin, struct modbus_data *mbout) { int ModbusSrv::WorkerAndEncodeWriteSingle(struct modbus_data *mbin, struct modbus_data *mbout) {
uint16_t i16;
int pos = 0;
int error = 0; int error = 0;
// transaction // transaction
mbout->transactionid = mbin->transactionid; 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->protoolid = mbin->protoolid;
i16 = htons((uint16_t)mbin->protoolid); mbout->length = 0;
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; mbout->unitid = mbin->unitid;
memcpy (mbout->buffer+pos, &mbout->unitid, sizeof(uint8_t));
pos += sizeof (uint8_t);
// fc
mbout->fc = mbin->fc; mbout->fc = mbin->fc;
memcpy (mbout->buffer+pos, &mbout->fc, sizeof(uint8_t));
pos += sizeof (uint8_t);
mbout->direction = 1; mbout->direction = 1;
if (mbin->fc == 5) { if (mbin->fc == 5) {
@ -457,33 +465,17 @@ int Modbus::WorkerAndEncodeWriteSingle(struct modbus_data *mbin, struct modbus_d
else mbarray[FC1][mbin->regstart].value = 0; else mbarray[FC1][mbin->regstart].value = 0;
} }
else error = 1; 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) { if (mbin->fc == 6) {
mbarray[FC3][mbin->regstart].requested |= 2; mbarray[FC3][mbin->regstart].requested |= 2;
if (mbarray[FC3][mbin->regstart].enabled) if (mbarray[FC3][mbin->regstart].enabled)
mbarray[FC3][mbin->regstart].value = mbin->regcnt; mbarray[FC3][mbin->regstart].value = mbin->regcnt;
else error = 1; 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);
} }
mbout->bufferlen = pos; // mirror the output
memcpy (mbout->buffer, mbin->buffer, mbin->bufferlen);
mbout->bufferlen = mbin->bufferlen;
// //
// inform the application about the modbus values change // inform the application about the modbus values change
@ -510,7 +502,7 @@ int Modbus::WorkerAndEncodeWriteSingle(struct modbus_data *mbin, struct modbus_d
} }
int Modbus::WorkerAndEncodeWriteMulti(struct modbus_data *mbin, struct modbus_data *mbout) { int ModbusSrv::WorkerAndEncodeWriteMulti(struct modbus_data *mbin, struct modbus_data *mbout) {
uint16_t i16; uint16_t i16;
int pos = 0; int pos = 0;
int i; int i;
@ -627,16 +619,18 @@ int Modbus::WorkerAndEncodeWriteMulti(struct modbus_data *mbin, struct modbus_da
} }
//
void Modbus::Decode(struct modbus_data *mbdata) { // return 1 on success, 0 on error
int ModbusSrv::Decode(struct modbus_data *mbdata) {
// //
uint16_t i16; uint16_t i16;
uint8_t i8; uint8_t i8;
int pos = 0; int pos = 0;
int ret = 1;
mbdata->fc = 0; mbdata->fc = 0;
mbdata->regcnt = -1; mbdata->regcnt = 0;
mbdata->regstart = -1; mbdata->regstart =-1;
mbdata->unitid = 0; mbdata->unitid = 0;
mbdata->length = 0; mbdata->length = 0;
mbdata->direction = 0; mbdata->direction = 0;
@ -644,7 +638,7 @@ void Modbus::Decode(struct modbus_data *mbdata) {
mbdata->protoolid = 0; mbdata->protoolid = 0;
mbdata->bytecnt = 0; mbdata->bytecnt = 0;
if (mbdata->bufferlen < 8) return; if (mbdata->bufferlen < 8) return 0;
// Transaction // Transaction
memcpy (&i16, mbdata->buffer+pos, sizeof(i16)); memcpy (&i16, mbdata->buffer+pos, sizeof(i16));
@ -662,32 +656,45 @@ void Modbus::Decode(struct modbus_data *mbdata) {
mbdata->length = ntohs(i16); mbdata->length = ntohs(i16);
// unitid // unitid
if (mbdata->length < pos-6) ret = 0;
memcpy (&i8, mbdata->buffer+pos, sizeof(i8)); memcpy (&i8, mbdata->buffer+pos, sizeof(i8));
pos += sizeof(i8); pos += sizeof(i8);
mbdata->unitid = i8; mbdata->unitid = i8;
// function code // function code
if (mbdata->length < pos-6) ret = 0;
memcpy (&i8, mbdata->buffer+pos, sizeof(i8)); memcpy (&i8, mbdata->buffer+pos, sizeof(i8));
pos += sizeof(i8); pos += sizeof(i8);
mbdata->fc = i8; mbdata->fc = i8;
// register // register
if (mbdata->length < pos-6) ret = 0;
memcpy (&i16, mbdata->buffer+pos, sizeof(i16)); memcpy (&i16, mbdata->buffer+pos, sizeof(i16));
pos += sizeof(i16); pos += sizeof(i16);
mbdata->regstart = ntohs(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 // number of registers
if (mbdata->length < pos-6) ret = 0;
memcpy (&i16, mbdata->buffer+pos, sizeof(i16)); memcpy (&i16, mbdata->buffer+pos, sizeof(i16));
pos += sizeof(i16); pos += sizeof(i16);
mbdata->regcnt = ntohs(i16); mbdata->regcnt = ntohs(i16);
// unitid // bytecnt
// if (mbdata->length < pos-6) ret = 0;
memcpy (&i8, mbdata->buffer+pos, sizeof(i8)); memcpy (&i8, mbdata->buffer+pos, sizeof(i8));
pos += sizeof(i8); pos += sizeof(i8);
mbdata->bytecnt = i8; mbdata->bytecnt = i8;
return ret;
}; };
int Modbus::GetRegister(int fc, int regnum, ModbusRegister *r) { int ModbusSrv::GetRegister(int fc, int regnum, ModbusRegister *r) {
r->enabled = false; r->enabled = false;
r->requested = 0; r->requested = 0;
r->updated = false; r->updated = false;
@ -708,7 +715,7 @@ int Modbus::GetRegister(int fc, int regnum, ModbusRegister *r) {
}; };
int Modbus::GetRegisters(int fc, int regnum, int count, ModbusRegister *r) { int ModbusSrv::GetRegisters(int fc, int regnum, int count, ModbusRegister *r) {
r->enabled = false; r->enabled = false;
r->requested = 0; r->requested = 0;
r->updated = false; r->updated = false;
@ -729,7 +736,7 @@ int Modbus::GetRegisters(int fc, int regnum, int count, ModbusRegister *r) {
}; };
int Modbus::SetRegister(int fc, int regnum, ModbusRegister *r) { int ModbusSrv::SetRegister(int fc, int regnum, ModbusRegister *r) {
if (regnum < 0 || regnum >= 0x10000) return -1; if (regnum < 0 || regnum >= 0x10000) return -1;
g_mutex_lock(&servermutex); g_mutex_lock(&servermutex);
@ -745,7 +752,7 @@ int Modbus::SetRegister(int fc, int regnum, ModbusRegister *r) {
} }
int Modbus::SetRegisters(int fc, int regnum, int count, ModbusRegister *r) { int ModbusSrv::SetRegisters(int fc, int regnum, int count, ModbusRegister *r) {
int reg = regnum; int reg = regnum;
int regend = regnum+count; int regend = regnum+count;
@ -768,7 +775,7 @@ int Modbus::SetRegisters(int fc, int regnum, int count, ModbusRegister *r) {
} }
void Modbus::Enable(int fc, int regstart, int count, int onoff) { void ModbusSrv::Enable(int fc, int regstart, int count, int onoff) {
int i; int i;
if (fc < 1 || fc > 4) return; if (fc < 1 || fc > 4) return;
if (regstart < 0) return; if (regstart < 0) return;
@ -782,7 +789,7 @@ void Modbus::Enable(int fc, int regstart, int count, int onoff) {
}; };
void Modbus::RequestsClear() { void ModbusSrv::RequestsClear() {
int fc, reg; int fc, reg;
g_mutex_lock(&servermutex); g_mutex_lock(&servermutex);
@ -793,7 +800,7 @@ void Modbus::RequestsClear() {
}; };
void Modbus::EnableAll(int onoff) { void ModbusSrv::EnableAll(int onoff) {
int fc, reg; int fc, reg;
g_mutex_lock(&servermutex); g_mutex_lock(&servermutex);
@ -804,9 +811,7 @@ void Modbus::EnableAll(int onoff) {
}; };
void Modbus::SetRegValue(int fc, int regstart, int count, uint16_t *values) { void ModbusSrv::SetRegValue(int fc, int regstart, int count, uint16_t *values) {
int reg;
if (fc <= 0 || fc > 4) { if (fc <= 0 || fc > 4) {
printf ("%s:%d fc(%d) is set out of range\n", __FILE__, __LINE__, fc); printf ("%s:%d fc(%d) is set out of range\n", __FILE__, __LINE__, fc);
return; return;
@ -860,31 +865,6 @@ void Modbus::SetRegValue(int fc, int regstart, int count, uint16_t *values) {
g_mutex_lock(&servermutex); 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); g_mutex_unlock(&servermutex);
}; };

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

@ -4,23 +4,27 @@
// //
///////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////
#include <sys/time.h> #include <gio/gio.h>
#include <stdio.h>
#include <glib.h>
#include "config.h" #include "config.h"
#include "mbsconfig.h" #include "mbsconfig.h"
#include "gui.h" #include "gui.h"
#include "modbus.h" #include "modbussrv.h"
////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////
// //
// global variables // global variables
// //
#define BUILDER_FILE "testmodbus-server.ui"
Config config; Config config;
Modbus modbus; ModbusSrv modbussrv;
GtkBuilder *_builder_ = NULL; // work around for the thread situation 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 uint16_t modbusdata[4][0x10000]; // needed for work with the gui will by synced by the modbus call back functions
int gnome_dblclick_timeout = 500;
gboolean modbus_callback(gpointer data); gboolean modbus_callback(gpointer data);
int main (int argc, char **argv) { int main (int argc, char **argv) {
@ -36,6 +40,26 @@ int main (int argc, char **argv) {
printf (" https://steffen.gulpe.de/modbus-tcpip\n"); printf (" https://steffen.gulpe.de/modbus-tcpip\n");
printf (" written by Steffen Pohle <steffen@gulpe.de>\n"); printf (" written by Steffen Pohle <steffen@gulpe.de>\n");
//
// read out some gnome defined values
#if defined _WIN32 || defined _WIN64 || defined __CYGWIN__
#else
GSettings *settings;
// from the google KI :)
// Das Schema (Schema) für die Mauseinstellungen erstellen
// In neueren GNOME-Versionen ist das Schema: 'org.gnome.desktop.peripherals.mouse'
// In älteren Versionen könnte es 'org.gnome.settings-daemon.peripherals.mouse' sein
settings = g_settings_new("org.gnome.desktop.peripherals.mouse");
if (settings == NULL) {
fprintf(stderr, "Fehler beim Laden des GSettings-Schemas.\n");
return 1;
}
gnome_dblclick_timeout = g_settings_get_int(settings, "double-click");
printf("Die aktuelle Doppelklickzeit beträgt: %d ms\n", gnome_dblclick_timeout);
g_object_unref(settings);
#endif
gtk_init (&argc, &argv); gtk_init (&argc, &argv);
_builder_ = builder = gtk_builder_new (); _builder_ = builder = gtk_builder_new ();
gtk_builder_add_from_file (builder, BUILDER_FILE, NULL); gtk_builder_add_from_file (builder, BUILDER_FILE, NULL);
@ -47,7 +71,7 @@ int main (int argc, char **argv) {
// #endif // #endif
// //
modbus.SetCallback(&modbus_callback); modbussrv.SetCallback(&modbus_callback);
window = gtk_builder_get_object (builder, "testmodbus-server"); window = gtk_builder_get_object (builder, "testmodbus-server");
gtk_widget_show_all (GTK_WIDGET(window)); gtk_widget_show_all (GTK_WIDGET(window));
@ -67,20 +91,6 @@ int main (int argc, char **argv) {
return 0; 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) { gboolean modbus_callback(gpointer data) {
struct modbus_callback_data *mdata = (struct modbus_callback_data *) data; struct modbus_callback_data *mdata = (struct modbus_callback_data *) data;
@ -93,15 +103,3 @@ gboolean modbus_callback(gpointer data) {
return FALSE; 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;
}

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

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

@ -4,11 +4,29 @@
// //
///////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////
#include <UDPTCPNetwork.h> #include "tcp.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h>
#define SIZE_BUFFER 4096 #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) { int main (int argc, char **argv) {
unsigned char data[] = { 0x00,0x70,0x00,0x00 , 0x00,0x0B,0x01,0x10 , unsigned char data[] = { 0x00,0x70,0x00,0x00 , 0x00,0x0B,0x01,0x10 ,
0x00,0x04,0x00,0x02 , 0x04,0xC0,0x02,0x7B , 0x00,0x04,0x00,0x02 , 0x04,0xC0,0x02,0x7B ,
@ -27,9 +45,14 @@ int main (int argc, char **argv) {
memset (buffer, 0x00, SIZE_BUFFER); memset (buffer, 0x00, SIZE_BUFFER);
if (argc < 3) { if (argc < 6) {
printf("test-fc16 server port register values...\n"); printf ("%d\n", argc);
printf("test-fc16 localhost 502 16 25.0 0.54 1000.5\n"); 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");
return 0; return 0;
} }
@ -43,9 +66,9 @@ int main (int argc, char **argv) {
if (argc == 3) { if (argc == 3) {
tcp.Write((char*)data, sizeof(data)); tcp.Write((char*)data, sizeof(data));
} }
else if (argc > 4) { else if (argc > 5) {
regstart = atoi (argv[3]); regstart = atoi (argv[3]);
regcnt = argc-4; regcnt = argc-5;
printf ("writing %d floats, offset %d\n", regcnt, regstart); printf ("writing %d floats, offset %d\n", regcnt, regstart);
@ -93,8 +116,8 @@ int main (int argc, char **argv) {
pos += sizeof(ui8); pos += sizeof(ui8);
for (i = 0; i < regcnt; i++) { for (i = 0; i < regcnt; i++) {
f = (float) atof(argv[i+4]); f = (float) atof(argv[i+5]);
printf ("i: %d string:%s f:%f\n", i, argv[i+4], f); printf ("i: %d string:%s f:%f\n", i, argv[i+5], f);
memcpy (&ui16, &f, sizeof(ui16)); memcpy (&ui16, &f, sizeof(ui16));
ui16 = htons(ui16); ui16 = htons(ui16);
@ -105,10 +128,20 @@ int main (int argc, char **argv) {
ui16 = htons(ui16); ui16 = htons(ui16);
memcpy (buffer+pos, &ui16, sizeof(ui16)); memcpy (buffer+pos, &ui16, sizeof(ui16));
pos += 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);
}
} }
tcp.Write((char*)buffer, pos); printf ("Wrote %d (out of %d) bytes\n", tcp.Write((char*)buffer, pos), pos);
} }
pos = tcp.ReadTimeout(buffer, SIZE_BUFFER, 1000);
printf ("Got %d bytes.\n", pos);
tcp.Close(); tcp.Close();
return 0; return 0;

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save