Compare commits

...

25 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

@ -1,3 +1,30 @@
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: 2022-10-31:
- fixed use of uninitialized and wrong value. - fixed use of uninitialized and wrong value.

@ -27,7 +27,7 @@ This configuration file will be needed on all meson based builds.
cpu = 'x86_64' cpu = 'x86_64'
endian = 'little' endian = 'little'
[properties] [built-in options]
c_args = [] c_args = []
c_link_args = [] c_link_args = []
@ -39,7 +39,7 @@ This configuration file will be needed on all meson based builds.
pkgconfig = '/usr/bin/x86_64-w64-mingw32-pkg-config' pkgconfig = '/usr/bin/x86_64-w64-mingw32-pkg-config'
windres = '/usr/bin/x86_64-w64-mingw32-windres' windres = '/usr/bin/x86_64-w64-mingw32-windres'
ld = '/usr/bin/x86_64-w64-mingw32-ld' ld = '/usr/bin/x86_64-w64-mingw32-ld'
exe_wrapper = 'wine64' exe_wrapper = 'wine'
## lib-glib ## lib-glib
@ -48,8 +48,8 @@ Compile the library using the following steps.
mkdir build mkdir build
cd build cd build
meson --buildtype=release --prefix=/opt/W64-cross-compile/ --cross-file ../../cross-file.ini meson setup --buildtype=release --prefix=/opt/W64-cross-compile/ --cross-file ../../cross-file.ini
mseon compile 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. 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.
@ -65,7 +65,7 @@ The flags -Dintrospection=false will tell meson to disable some building options
mkdir build mkdir build
cd build cd build
PKG_CONFIG_PATH=/opt/W64-cross-compile/lib/pkgconfig meson --buildtype=release -Dintrospection=false -Ddocs=false --prefix=/opt/W64-cross-compile/ --cross-file ../../cross-file.ini 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 compile
meson install meson install
@ -73,14 +73,22 @@ Copy manualy all compiled `*.dll` files to the destination
cp `find -name "*.dll"` /opt/W64-cross-compile/lib/ cp `find -name "*.dll"` /opt/W64-cross-compile/lib/
## pango ## pango
Compile the library using the following steps. This will also download and compile some more librarys like `libpng` and `cairo` librarys. Compile the library using the following steps. This will also download and compile some more librarys like `libpng` and `cairo` librarys.
mkdir build mkdir build
cd 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 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
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. 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.
@ -91,7 +99,7 @@ In case of an error with unresolved symbols like undefined reference to '__strca
mkdir build mkdir build
cd 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 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 compile
meson install meson install
cp `find -name "*.dll"` /opt/W64-cross-compile/lib/ cp `find -name "*.dll"` /opt/W64-cross-compile/lib/

@ -1,23 +1,22 @@
.SILENT: help .SILENT: help
VERSION = 1.0.1 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
@ -52,12 +51,13 @@ $(TARGET): $(OBJECTS)
clean: clean:
rm -rf TestModbus-Server-$(VERSION)/ rm -rf TestModbus-Server-$(VERSION)/
rm -f *.o *.oo *.c~ *.h~ *.cc~ *.ui~ $(APP) Makefile~ 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)
@ -94,11 +94,15 @@ buildwindows: clean
cp Changelog TestModbus-Server-$(VERSION)/ cp Changelog TestModbus-Server-$(VERSION)/
cp LICENSE TestModbus-Server-$(VERSION)/ cp LICENSE TestModbus-Server-$(VERSION)/
./copydlls.sh ./copydlls.sh
./copydlls.sh
./copydlls.sh
./copydlls.sh
./copyshare.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 *.dll TestModbus-Server-$(VERSION)/
mv share TestModbus-Server-$(VERSION)/ mv share TestModbus-Server-$(VERSION)/
#tar xvzf $(CROSSENV)/files/winbuild-dll.tgz -C TestModbus-Server-$(VERSION)/ zip -r TestModbus-Server-$(VERSION)-win.zip TestModbus-Server-$(VERSION)/
#tar xvzf $(CROSSENV)/files/winbuild-share.tgz -C 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

@ -2,10 +2,16 @@
CROSS_DEST_DIR=/opt/W64-cross-compile/lib CROSS_DEST_DIR=/opt/W64-cross-compile/lib
CROSS_COMPILER_DIR=/usr/x86_64-w64-mingw32/lib CROSS_COMPILER_DIR=/usr/x86_64-w64-mingw32/lib
CROSS_GCC_DIR=/usr/lib/gcc/x86_64-w64-mingw32/10-win32
#
# 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 ./ cp -v $CROSS_COMPILER_DIR/zlib1.dll ./
# copy dll dependencys # copy dll dependencys
copy_dependency() { copy_dependency() {
local I local I

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;
modbussrv.EnableAll(0);
modbus.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,11 +166,10 @@ 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));

@ -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,15 +619,17 @@ 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;
@ -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;
}

@ -158,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;
@ -197,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;

@ -7,6 +7,7 @@
#include "tcp.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) {

@ -7,6 +7,7 @@
#include "tcp.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

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