From 8ca01af2d1c6c805cd0818d48691e3777fe35f02 Mon Sep 17 00:00:00 2001 From: Steffen Pohle Date: Sun, 27 Aug 2023 22:34:38 +0200 Subject: [PATCH] connect and close is working --- .gitignore | 2 + client.cc | 91 +++++++++++++- client.h | 9 +- nwthread.cc | 148 ++++++++++++++++++++++ nwthread.h | 49 ++++++++ tcp.h | 2 +- testmodbus-client.ui | 283 ++++++++++++++++++++++++------------------- 7 files changed, 450 insertions(+), 134 deletions(-) create mode 100644 nwthread.cc create mode 100644 nwthread.h diff --git a/.gitignore b/.gitignore index e3f130d..5d60970 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ .project +testmodbus-client.ui~ +*.oo # ---> Autotools # http://www.gnu.org/software/automake diff --git a/client.cc b/client.cc index fc71d78..a288b89 100644 --- a/client.cc +++ b/client.cc @@ -1,15 +1,28 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// client.cc is part of TestModbus-Client. +// +///////////////////////////////////////////////////////////////////////////////// + + #include #include "config.h" #include "client.h" +#include "nwthread.h" #define BUILDER_FILE "testmodbus-client.ui" /************************************************************************************ * Global Variables */ -GtkBuilder *_builder_ = NULL; // work around for the thread situation -gboolean modbuscli_callback(gpointer data); // callback for threads +GtkBuilder *_builder_ = NULL; // work around for the thread situation +gboolean mbcli_thread_cb_net(gpointer data); // callback thread network data +gboolean mbcli_thread_cb_error(gpointer data); // callback thread error +void mbcli_connect_btn_sensitive (bool enable); // enable/disable connect buttons + +NetworkThread netthread; + int main (int argc, char **argv) { GtkBuilder *builder; @@ -35,7 +48,6 @@ int main (int argc, char **argv) { // #endif // -// modbuscli.SetCallback(&modbus_callback); window = gtk_builder_get_object (builder, "testmodbus-client"); gtk_widget_show_all (GTK_WIDGET(window)); gtk_main (); @@ -44,9 +56,76 @@ int main (int argc, char **argv) { } -gboolean modbuscli_callback(gpointer data) { - void *mdata = data; - free (mdata); + +/* + * display error if somethin happened within a thread + */ +gboolean mbcli_thread_cb_error(gpointer data) { + if (data == NULL) { + displayerror ("unknown error"); + } + else { + std::string text = (char*)data; + free (data); + displayerror (text); + } return FALSE; }; + + +void displayerror (std::string error) { + GtkWidget *dialog; + GtkWidget *window = GTK_WIDGET (gtk_builder_get_object (_builder_, "testmodbus-client")); + dialog = gtk_message_dialog_new(GTK_WINDOW(window), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_OK, + error.c_str()); + gtk_window_set_title(GTK_WINDOW(dialog), "Error"); + gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); +} + + +/* + * network thread callback + */ +gboolean mbcli_thread_cb_status(gpointer data) { + GtkWidget *statusbar = GTK_WIDGET (gtk_builder_get_object (_builder_, "cli_statusbar")); + + mbcli_connect_btn_sensitive (netthread.GetState() == NWT_nothing); + if (data) { + gtk_label_set_label(GTK_LABEL(statusbar), (char*)data); + free (data); + } + + return FALSE; +}; + + +void mbcli_connect_btn_sensitive (bool enable) { + GtkWidget *txthost = GTK_WIDGET (gtk_builder_get_object (_builder_, "cli_host")); + GtkWidget *txtport = GTK_WIDGET (gtk_builder_get_object (_builder_, "cli_port")); + GtkWidget *btnconnect = GTK_WIDGET (gtk_builder_get_object (_builder_, "cli_btnConnect")); + GtkWidget *btndisconnect = GTK_WIDGET (gtk_builder_get_object (_builder_, "cli_btnDisconnect")); + + gtk_widget_set_sensitive(txthost, enable); + gtk_widget_set_sensitive(txtport, enable); + gtk_widget_set_sensitive(btnconnect, enable); + gtk_widget_set_sensitive(btndisconnect, !enable); +}; + + +void mbcli_cb_connect (GtkWidget *widget, gpointer data) { + GtkWidget *txthost = GTK_WIDGET (gtk_builder_get_object (_builder_, "cli_host")); + GtkWidget *txtport = GTK_WIDGET (gtk_builder_get_object (_builder_, "cli_port")); + + mbcli_connect_btn_sensitive(false); + netthread.Connect(gtk_entry_get_text(GTK_ENTRY(txthost)), gtk_entry_get_text(GTK_ENTRY(txtport))); +}; + +void mbcli_cb_disconnect (GtkWidget *widget, gpointer data) { + netthread.Disconnect(); +}; + diff --git a/client.h b/client.h index 468b010..2db7433 100644 --- a/client.h +++ b/client.h @@ -19,13 +19,20 @@ extern "C" { #endif +#define LEN_STATUSTEXT 255 + +void displayerror (std::string error); + // *********************************************************************** // // main windows call backs // +gboolean mbcli_thread_cb_error(gpointer data); +gboolean mbcli_thread_cb_status(gpointer data); -G_MODULE_EXPORT gboolean modbus_callback (gpointer data); +G_MODULE_EXPORT void mbcli_cb_connect (GtkWidget *widget, gpointer data); +G_MODULE_EXPORT void mbcli_cb_disconnect (GtkWidget *widget, gpointer data); #ifdef __cplusplus } diff --git a/nwthread.cc b/nwthread.cc new file mode 100644 index 0000000..635cf86 --- /dev/null +++ b/nwthread.cc @@ -0,0 +1,148 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// nwthread.cc is part of TestModbus-Client. +// +///////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include + +#include +#include + +#if defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__) +#else + #include /* close() */ +#endif + +#include "tcp.h" +#include "nwthread.h" +#include "client.h" + +extern NetworkThread netthread; + +// c / C++ wrapper +gpointer _Thread (gpointer data) { + netthread.Thread (); + return NULL; +}; + + + +NetworkThread::NetworkThread() { + g_mutex_init (&mutex); + thread = NULL; + state = 0; + host = ""; + port = ""; +}; + +NetworkThread::~NetworkThread() { + Disconnect(); + g_mutex_clear(&mutex); +}; + +void NetworkThread::Lock() { + g_mutex_lock(&mutex); +}; + +void NetworkThread::UnLock() { + g_mutex_unlock(&mutex); +}; + + +/* + * start network thread and connect + */ +int NetworkThread::Connect(std::string dest_host, std::string dest_port) { + printf ("%s:%d NetworkThread::Connect to %s:%s\n", __FILE__, __LINE__, dest_host.c_str(), dest_port.c_str()); + + // + // if there is an open connection close this one first + if (GetState() != NWT_nothing) Disconnect(); + + host = dest_host; + port = dest_port; + thread = g_thread_new("network thread", _Thread, NULL); + + return -1; +}; + + +/* + * stop network connection + */ +int NetworkThread::Disconnect() { + printf ("%s:%d NetworkThread::Disconnect\n", __FILE__, __LINE__); + + Lock(); + if (state != NWT_nothing) state = NWT_close; + UnLock(); + while (GetState() != NWT_nothing) { usleep(1000); }; + + if (thread != NULL) g_thread_unref(thread); + thread = NULL; + + return 0; +}; + + +void NetworkThread::SetState(int s) { + Lock(); + state = s; + UnLock(); +}; + + +int NetworkThread::GetState() { + int s; + + Lock(); + s = state; + UnLock(); + + return s; +}; + + +void NetworkThread::ClientSendStatustext(char *txt) { + char *msg = NULL; + if (txt) { + int l = strlen (txt)+1; + msg = (char*) malloc(l+1); + memset (msg, 0x0, l+1); + strncpy (msg, txt, strlen (txt)); + } + gdk_threads_add_idle(mbcli_thread_cb_status, msg); +} + + + +void NetworkThread::Thread() { + printf ("%s:%d NetworkThread::Thread Started\n", __FILE__, __LINE__); + + TCP tcp; + ClientSendStatustext((char*)"connecting"); + + SetState (NWT_connect); + if (tcp.Connect(host, port) != 1) { + ClientSendStatustext(strerror(errno)); + } + else { + // + // destination host and port should be set already + SetState(NWT_running); + while (GetState() == NWT_running) { + ClientSendStatustext((char*)"connected"); + usleep (1000); + } + if(GetState() == NWT_close) { + ClientSendStatustext((char*)""); + } + } + SetState(NWT_nothing); + ClientSendStatustext(NULL); + printf ("%s:%d NetworkThread::Thread Finished\n", __FILE__, __LINE__); +}; + diff --git a/nwthread.h b/nwthread.h new file mode 100644 index 0000000..681b34e --- /dev/null +++ b/nwthread.h @@ -0,0 +1,49 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// nwthread.h is part of TestModbus-Client. +// +///////////////////////////////////////////////////////////////////////////////// + +#ifndef _NWTHREAD_H_ +#define _NWTHREAD_H_ + +#include +#include +#include +#include + +enum { + NWT_nothing, + NWT_connect, + NWT_running, + NWT_close +}; + + +class NetworkThread { +private: + GMutex mutex; + GThread *thread; + int state; + std::string host, port; + + void SetState(int s); + void ClientSendStatustext(char* txt); + +public: + NetworkThread(); + ~NetworkThread(); + + void Lock(); + void UnLock(); + + int Connect(std::string dest_host, std::string dest_port); + int Disconnect(); + + int GetState(); + + void Thread(); +}; + + +#endif diff --git a/tcp.h b/tcp.h index 23ca6b9..52b6914 100644 --- a/tcp.h +++ b/tcp.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// tcp.h is part of TestModbus-Server. +// tcp.h is part of TestModbus-Client. // ///////////////////////////////////////////////////////////////////////////////// diff --git a/testmodbus-client.ui b/testmodbus-client.ui index 6bdd1a5..5582bbf 100644 --- a/testmodbus-client.ui +++ b/testmodbus-client.ui @@ -9,6 +9,10 @@ True False + 4 + 4 + 4 + 4 vertical @@ -16,8 +20,6 @@ False 4 4 - 4 - 4 0 @@ -28,29 +30,76 @@ True False - vertical - 4 True False - 4 + vertical True False - vertical 4 True False + vertical 4 - + True False - Host: + 4 + + + True + False + Host: + + + False + True + 0 + + + + + True + True + localhost + + + False + True + 1 + + + + + True + False + Port: + + + False + True + 2 + + + + + True + True + 6 + 1502 + + + False + True + 3 + + False @@ -59,40 +108,40 @@ - - True - True - localhost - - - False - True - 1 - - - - + True False - Port: - - - False - True - 2 - - - - - True - True - 6 - 502 + 4 + + + True + False + Refresh [ms]: + + + False + True + 0 + + + + + True + True + 4 + 1000 + + + False + True + 1 + + False True - 3 + 1 @@ -106,12 +155,17 @@ True False - 4 + 4 + 4 + vertical - + + Auto Reconnect True - False - Refresh [ms]: + True + False + True + True False @@ -120,11 +174,13 @@ - + + Read Only True True - 4 - 1000 + False + True + True False @@ -132,6 +188,9 @@ 1 + + + False @@ -147,43 +206,19 @@ - + True False - vertical - - - Auto Reconnect - True - True - False - True - True - - - False - True - 0 - - - - - Read Only - True - True - False - True - True - - - False - True - 1 - - - - - + 8 + 8 + 8 + 8 + 8 + 8 + + + + False @@ -191,51 +226,6 @@ 1 - - - True - False - vertical - 3 - - - gtk-connect - True - True - True - True - True - - - False - True - 0 - - - - - gtk-disconnect - True - False - True - True - True - True - - - False - True - 1 - - - - - False - True - end - 2 - - False @@ -244,14 +234,55 @@ - + True False - last error | status + center + center + 4 + 4 + 4 + 4 + vertical + 4 + + + gtk-connect + True + True + True + True + True + + + + False + True + 0 + + + + + gtk-disconnect + True + False + True + True + True + True + + + + False + True + 1 + + False - False + True + end 1