diff --git a/.gitignore b/.gitignore index 52873f5..e3f130d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +.project + # ---> Autotools # http://www.gnu.org/software/automake diff --git a/Changelog b/Changelog new file mode 100644 index 0000000..b1d89a7 --- /dev/null +++ b/Changelog @@ -0,0 +1,3 @@ +2023-08-27: +- prepare basic codebase + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..fcff9ba --- /dev/null +++ b/LICENSE @@ -0,0 +1,6 @@ + +The license model for this software (TestModbus-Client) is not yet choosen. +At the moment you can use this software free of charge at your own risk. + +27.Aug.2023 Steffen Pohle + diff --git a/Makefile.rules.crosswindows b/Makefile.rules.crosswindows new file mode 100644 index 0000000..58a2bbe --- /dev/null +++ b/Makefile.rules.crosswindows @@ -0,0 +1,9 @@ + +TARGETEXT = .exe +CONFIGSET = YES +CROSSENV = /opt/W64-cross-compile/ +CPP = /usr/bin/x86_64-w64-mingw32-g++ +CPPFLAGS = -ggdb -Wall -O0 `PKG_CONFIG_PATH=$(CROSSENV)/lib/pkgconfig pkg-config --cflags gtk+-3.0 gmodule-export-2.0` -Wl,--export-dynamic -DBUILD_WINDOWS=1 -Wdeprecated +INCLUDES = +LDFLAGS = -lws2_32 +LIBS = `PKG_CONFIG_PATH=$(CROSSENV)/lib/pkgconfig pkg-config --libs gtk+-3.0 gmodule-export-2.0` -L/usr/lib -mwindows diff --git a/Makefile.rules.linux b/Makefile.rules.linux new file mode 100644 index 0000000..b5e0556 --- /dev/null +++ b/Makefile.rules.linux @@ -0,0 +1,8 @@ + +TARGETEXT = +CONFIGSET = YES +CPP = c++ +CPPFLAGS = -ggdb -Wall -O0 `pkg-config --cflags gtk+-3.0 gmodule-export-2.0` -Wl,--export-dynamic -I/usr/include -DBUILD_LINUX=1 +INCLUDES = +LDFLAGS = +LIBS = `pkg-config --libs gtk+-3.0 gmodule-export-2.0` -L/usr/lib diff --git a/Makefile.rules.windows b/Makefile.rules.windows new file mode 100644 index 0000000..826eb30 --- /dev/null +++ b/Makefile.rules.windows @@ -0,0 +1,8 @@ + +TARGETEXT = .exe +CONFIGSET = YES +CPP = g++ +CPPFLAGS = -ggdb -Wall -O0 `pkg-config --cflags gtk+-3.0 gmodule-export-2.0` -Wl,--export-dynamic -I/usr/include -DBUILD_WINDOWS=1 +INCLUDES = +LDFLAGS = -lWs2_32 +LIBS = `pkg-config --libs gtk+-3.0 gmodule-export-2.0` -L/usr/lib diff --git a/client.cc b/client.cc new file mode 100644 index 0000000..fc71d78 --- /dev/null +++ b/client.cc @@ -0,0 +1,52 @@ +#include + +#include "config.h" +#include "client.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 + +int main (int argc, char **argv) { + GtkBuilder *builder; + GObject *window; + +#ifdef BUILD_WINDOWS + char buffer[16]; + setvbuf (stdout, buffer, _IONBF, 16); +#endif + + printf ("TestModbus-Client - %s\n", VERSION); + printf (" https://steffen.gulpe.de/modbus-tcpip\n"); + printf (" written by Steffen Pohle \n"); + + gtk_init (&argc, &argv); + _builder_ = builder = gtk_builder_new (); + gtk_builder_add_from_file (builder, BUILDER_FILE, NULL); + gtk_builder_connect_signals(builder, builder); + + // + // #if defined _WIN32 || defined _WIN64 || defined __CYGWIN__ + // #else + // #endif + // + +// modbuscli.SetCallback(&modbus_callback); + window = gtk_builder_get_object (builder, "testmodbus-client"); + gtk_widget_show_all (GTK_WIDGET(window)); + gtk_main (); + + return 0; +} + + +gboolean modbuscli_callback(gpointer data) { + void *mdata = data; + free (mdata); + + return FALSE; +}; diff --git a/client.h b/client.h new file mode 100644 index 0000000..468b010 --- /dev/null +++ b/client.h @@ -0,0 +1,35 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// client.h is part of TestModbus-Client. +// +///////////////////////////////////////////////////////////////////////////////// + +#ifndef _CLIENT_H_ +#define _CLIENT_H_ + +#include +#include +#include + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +// *********************************************************************** +// +// main windows call backs +// + +G_MODULE_EXPORT gboolean modbus_callback (gpointer data); + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/copydlls.sh b/copydlls.sh new file mode 100755 index 0000000..7b7cbb4 --- /dev/null +++ b/copydlls.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +CROSS_DEST_DIR=/opt/W64-cross-compile/lib +CROSS_COMPILER_DIR=/usr/x86_64-w64-mingw32/lib +CROSS_GCC_DIR=/usr/lib/gcc/x86_64-w64-mingw32/10-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 +copy_dependency testmodbus-client.exe + diff --git a/copyshare.sh b/copyshare.sh new file mode 100755 index 0000000..2eb2180 --- /dev/null +++ b/copyshare.sh @@ -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 + diff --git a/tcp.cc b/tcp.cc new file mode 100644 index 0000000..8689944 --- /dev/null +++ b/tcp.cc @@ -0,0 +1,519 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// tcp.cc is part of TestModbus-Server. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "tcp.h" +#include +#if defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__) +#else + #include /* close() */ +#endif +#include +#include /* memset() */ +#include + +using namespace std; + +int tcpinit; +// +// convert host and port to sockaddr_in6 +// +int dns_filladdr (string host, string port, int ai_family, struct sockaddr_storage *sAddr) { + struct addrinfo hints, *res; + int err; + + bzero (&hints, sizeof (struct addrinfo)); + hints.ai_family = ai_family; + hints.ai_socktype = SOCK_DGRAM; + + if ((err = getaddrinfo (host.c_str(), port.c_str(), &hints, &res)) < 0) { + fprintf (stdout, "dns_filladdr (getaddrinfo):%s\n", gai_strerror (err)); + return -1; + } + + memcpy (sAddr, res->ai_addr, res->ai_addrlen); + freeaddrinfo (res); + + return 1; +}; + + +// +// convert int to char* +// +char* itoa(char* buffer, int number, int size) { + snprintf (buffer, size, "%d", number); + return buffer; +} + + +TCP::~TCP() { + Close(); +} + +TCP::TCP() { + if (tcpinit == 0) { +#if defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__) || defined(BUILD_WINDOWS) + + WORD wVersionRequested; + WSADATA wsaData; + int err; + + /* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */ + wVersionRequested = MAKEWORD(2, 2); + + err = WSAStartup(wVersionRequested, &wsaData); + if (err != 0) { + /* Tell the user that we could not find a usable */ + /* Winsock DLL. */ + printf("WSAStartup failed with error: %d\n", err); + return; + } +#endif + tcpinit = 1; + } + sock = 0; + writecnt = 0; + readcnt = 0; + islisten = 0; +}; + +TCP::TCP(int s) { + TCP(); + sock = s; +// memset (&localaddr, 0x0, sizeof(localaddr)); +// memset (&remoteaddr, 0x0, sizeof(remoteaddr)); + writecnt = 0; + readcnt = 0; + islisten = 0; +}; + +TCP::TCP(string h, string p) { + TCP(); + Connect (h,p); +}; + + +/* + * puts the tcp server to listen mode. This code works on linux with IPV4 and IPV6 + */ +int TCP::Listen(int port) { + char buffer[NET_BUFFERSIZE]; + int err, i; + struct addrinfo hints, *res, *rp; + + if (sock > 0) Close(); + bzero (&hints, sizeof (struct addrinfo)); + hints.ai_flags = AI_PASSIVE; +#if defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__) + hints.ai_family = AF_INET; +#else + hints.ai_family = AF_INET6; +#endif + hints.ai_socktype = SOCK_STREAM; + if ((err = getaddrinfo (NULL, itoa(buffer, port, 32), &hints, &res)) != 0) { + return 0; + } + + // + // walk through all results until we could connect + // + for (rp = res; rp != NULL; rp = rp->ai_next) { + sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + if (sock == -1) continue; + + i = 1; + if ((err = setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, (char*)&i, sizeof (i))) != 0) { + printf ("%s:%d setsockopt error\n", __FILE__, __LINE__); + } + + if ((err = bind (sock, rp->ai_addr, rp->ai_addrlen)) < 0) { + close (sock); + sock = -1; + continue; + } + if (listen (sock, 8) < 0) { // maximum of 8 connections at the time + close (sock); + sock = -1; + continue; + } + break; + } + + freeaddrinfo (res); + + if (rp == NULL) { + sock = -1; + return 0; + } + + islisten = 1; + + return 1; +}; + + +TCP* TCP::Accept() { + fd_set rfds; + struct timeval tv; + int retval; + SOCKET newsock; + struct sockaddr_storage cliaddr; + socklen_t cliaddr_len = sizeof(struct sockaddr_storage); + TCP *tcp = NULL; + + if (sock <= 0) return NULL; + + FD_ZERO(&rfds); + FD_SET(sock, &rfds); + tv.tv_sec = 0; + tv.tv_usec = 1000; + + retval = select (sock+1, &rfds, NULL, NULL, &tv); + if (retval == -1 && errno == EINTR) { + retval = 0; + } + else if (retval == -1) { + return NULL; + } + else if (retval) { +#if defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__) + newsock = accept (sock, (struct sockaddr *) &cliaddr, (int*) &cliaddr_len); +#else + newsock = accept (sock, (struct sockaddr *) &cliaddr, &cliaddr_len); +#endif + if (newsock < 0) return NULL; + tcp = new TCP(); + tcp->SetSocket(newsock, &cliaddr, cliaddr_len); + + return tcp; + } + return NULL; +} + + +int TCP::Connect(string h, string p) { + remote_host = h; + remote_port = p; + + return Connect(); +}; + + +int TCP::Connect(string hostport, int defaultport) { + char buffer[32]; + int pos = hostport.rfind(':', hostport.length()); + if (pos == -1) { + remote_port = itoa (buffer, defaultport, 32); + remote_host = hostport; + } + else { + remote_port = hostport.substr (pos+1, hostport.length() - pos); + remote_host = hostport.substr (0, pos); + } + + return Connect(); +}; + + +int TCP::Connect() { + int err, s; + struct addrinfo hints, *res, *rp; + struct timeval timeout; + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; // use IPv4 or IPv6 + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = 0; + hints.ai_protocol = 0; + + err = getaddrinfo(remote_host.c_str(), remote_port.c_str(), &hints, &res); + if (err != 0) { + fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(err)); + return 0; + } + + // + // walk through all results until we could connect + // + for (rp = res; rp != NULL; rp = rp->ai_next) { + s = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + + // setup timeout to max 2 secs + timeout.tv_sec = 2; + timeout.tv_usec = 0; + setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout, sizeof(timeout)); + + if (s == -1) continue; + if (connect(s, rp->ai_addr, rp->ai_addrlen) != -1) { + sock = s; + break; + } + close(s); + } + + freeaddrinfo(res); + + // + // connect not successfull + // + if (rp == NULL) return 0; + + writecnt = 0; + readcnt = 0; + + return 1; +}; + + +long int TCP::ReadPop (char *buffer, long int pktlen, long int bufferlen) { + memmove (buffer, buffer+pktlen, bufferlen-pktlen); + return bufferlen-pktlen; +} + + +long int TCP::Read(char *buffer, long int len) { + long int len_ = len; + + if (sock <= 0) return -2; + len_ = recv (sock, buffer, len, 0); + + if (len_ < 0 && errno == EAGAIN) len_ = 0; + else if (len_ < 0 && errno != EAGAIN) { +#ifdef BUILD_WINDOWS + printf ("%s ERROR:%s\n", __FUNCTION__, strerror (errno)); +#else + fprintf (stderr, "%s ERROR:%s\n", __FUNCTION__, strerror (errno)); +#endif + len_ = -2; + } + else if (len_ == 0) len_ = -1; + if (len_ < 0) Close(); + + readcnt += len_; + + return len_; +}; + + +long int TCP::ReadTimeout(char *buffer, long int len, int timeout) { + int data = IsData (timeout); + + if (data > 0) return Read (buffer, len); + else if (data < 0) return -1; + else return 0; +}; + + +////////////////////////////////////////////////////////// +// +// write data, generate no signal if some error occures +long int TCP::Write(char *buffer, long int len) { + int i; + int to = NET_MAX_RETRY; + + if (sock <= 0) return -1; + + do { + i = send (sock, buffer, len, MSG_NOSIGNAL); + } while (i == -1 && (to--) > 0 && errno == EINTR); + + if (i < 0) Close (); + writecnt += i; + + return i; +}; + + +void TCP::Close() { +#ifdef BUILD_WINDOWS + closesocket(sock); +#else + if (sock > 0) close (sock); +#endif + sock = -1; + islisten = false; +}; + + +void TCP::SetSocket(SOCKET s, struct sockaddr_storage *saddr, socklen_t saddrlen) { + char host[NET_HOSTLEN]; + char port[NET_PORTLEN]; + int err; + + if (sock > 0) Close(); + if (s > 0) { + sock = s; + + if (saddr != NULL) { + memcpy (&peeraddr, saddr, sizeof(peeraddr)); + if ((err = getnameinfo ((struct sockaddr*) saddr, saddrlen, host, NET_HOSTLEN, + port, NET_PORTLEN, NI_NUMERICHOST | NI_NUMERICSERV)) == 0) { + remote_host = host; + remote_port = port; + } else { + printf ("error: getnameinfo"); +/* if (err == EAI_AGAIN) printf ("EAI_AGAIN\n"); + if (err == EAI_BADFLAGS) printf ("EAI_BADFLAGS\n"); + if (err == EAI_FAIL) printf ("EAI_FAIL\n"); + if (err == EAI_FAMILY) printf ("EAI_FAMILY\n"); + if (err == EAI_MEMORY) printf ("EAI_MEMORY\n"); + if (err == EAI_NONAME) printf ("EAI_NONAME\n"); + if (err == EAI_OVERFLOW) printf ("EAI_OVERFLOW\n"); + if (err == EAI_SYSTEM) printf ("EAI_SYSTEM\n"); */ // windows seem to have different error codes + } + } + } + else sock = -1; +}; + + +int TCP::IsConnected() { + return (sock > 0); +}; + + +int TCP::IsData(int timeout) { + fd_set sockset; + struct timeval tval; + + if (sock <= 0) return -1; + + FD_ZERO (&sockset); + FD_SET (sock, &sockset); + tval.tv_sec = timeout / 1000; + tval.tv_usec = (timeout % 1000); + if ((select (sock + 1, &sockset, NULL, NULL, &tval)) != -1) { + if (FD_ISSET (sock, &sockset)) return 1; + return 0; + } + else { + if (errno == EBADF) sock = -1; + } + return 0; +}; + + +int TCP::WebGetFile (string url, char *buffer, int maxsize) { + char outdata[NET_BUFFERSIZE]; + char indata[NET_BUFFERSIZE]; + char host[NET_HOSTLEN]; + char port[NET_PORTLEN]; + int breakup, len, head, i, buffpos = 0; + + if (!IsConnected()) { + strncpy (host, WebGetURLHost (url).c_str(), NET_HOSTLEN); + strncpy (port, WebGetURLPort (url).c_str(), NET_PORTLEN); + Connect (host, port); + } + + if (!IsConnected()) return -1; + + // send http request + snprintf (outdata, NET_BUFFERSIZE, "GET %s HTTP/1.0\nUser-Agent: unknown \nHost: %s\n\n", WebGetURLFile (url).c_str(), host); + Write (outdata, strlen (outdata)); + + // wait for data start + i = breakup = 0; + head = 1; + while (!breakup && head && (len = ReadTimeout (indata, NET_BUFFERSIZE-1, 2000)) >= 0) { + indata[len] = 0; + while (i < len -4 && head && !breakup) { + if (indata[i] == 0x0d && indata [i+1] == 0x0a && indata [i+2] == 0x0d && indata [i+3] == 0x0a) { + head = 0; + i = i + 4; + buffpos = len-i; + if (buffpos > maxsize) buffpos = maxsize; + memcpy (buffer, indata+i, buffpos); + } + + else if (strncmp (indata+i, "Content-Length:", 15) == 0) { + i = i + 16; + } + + else if (strncmp (indata+i, "403 ", 4) == 0) breakup = 1; + else i++; + } + } + + // read data + while (!breakup && (len = ReadTimeout (indata, NET_BUFFERSIZE-1, 2000)) >= 0) { + i = len; + if (i > maxsize-buffpos) i = maxsize-buffpos; + if (i > 0) { + memcpy (buffer+buffpos, indata, i); + buffpos += i; + } + } + + return buffpos; +}; + +const string TCP::WebGetURLHost (string url) { + string result; + int posSServPort = 7; // begin server:port + int posEServPort = 0; // end Server:Port + int posPort = -1; // port Position + + posEServPort = url.find("/", 7); + result = url.substr (posSServPort, posEServPort-posSServPort); + posPort = result.find(":"); + if (posPort > 0) + result = url.substr (posSServPort, posPort); + + return result; +}; + +const string TCP::WebGetURLPort (string url) { + string result; + int posSServPort = 7; // begin server:port + int posEServPort = 0; // end Server:Port + int posPort = -1; // port Position + + posEServPort = url.find("/", 7); + result = url.substr (posSServPort, posEServPort-posSServPort); + posPort = result.find(":"); + if (posPort > 0) + result = result.substr (posPort+1); + else + result = "80"; + + return result; +}; + +const string TCP::WebGetURLFile (string url) { + string result; + int posEServPort = 0; // end Server:Port + + posEServPort = url.find("/", 7); + result = url.substr (posEServPort); + + return result; +}; + + +const string TCP::GetRemoteAddr() { + string ret = ""; + socklen_t addrlen = sizeof (peeraddr); + char host[256] = ""; + char port[256] = ""; + + if (getnameinfo ((struct sockaddr*)&peeraddr, addrlen, host, 255, port, 255, NI_NUMERICHOST | NI_NUMERICSERV) != 0) { + printf ("getnameinfo error: %s\n", strerror(errno)); + } + + ret = (string)host + ":" + (string)port; + + return ret; +}; + + +const string TCP::GetLocalAddr() { + string ret; + + return ret; +}; + + diff --git a/tcp.h b/tcp.h new file mode 100644 index 0000000..23ca6b9 --- /dev/null +++ b/tcp.h @@ -0,0 +1,123 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// tcp.h is part of TestModbus-Server. +// +///////////////////////////////////////////////////////////////////////////////// + +#ifndef _TCP_H_ +#define _TCP_H_ + +#if defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__) + +#define WIN32_LEAN_AND_MEAN + +#define _NTDDI_VERSION_FROM_WIN32_WINNT2(ver) ver##0000 +#define _NTDDI_VERSION_FROM_WIN32_WINNT(ver) _NTDDI_VERSION_FROM_WIN32_WINNT2(ver) + +#ifndef _WIN32_WINNT +# define _WIN32_WINNT 0x501 +#endif +#ifndef NTDDI_VERSION +# define NTDDI_VERSION _NTDDI_VERSION_FROM_WIN32_WINNT(_WIN32_WINNT) +#endif + +// #include +#include +#include +#include +#include + +#define socklen_t size_t + +#ifndef bzero +#define bzero(__z__, __x__) memset (__z__, 0x0, __x__) +#endif + +#ifndef MSG_NOSIGNAL +# define MSG_NOSIGNAL 0 +#endif + +#else + +#include +#include +#include +#include +#include +#include + +#endif + +#include + +using namespace std; + +#define SOCKET int + +#define NET_HOSTLEN 256 +#define NET_PORTLEN 6 +#define NET_BUFFERSIZE 1024 +#define NET_MAX_RETRY 5 // retry to send data EINTR +#define NET_MAX_TIMEOUT 30000 // timeout in ms + + +/************************************************************************ + * + * global functions needed for networking + * + */ +int dns_filladdr (string host, string port, int ai_family, + struct sockaddr_storage *sAddr); +char *itoa(char* buffer, int number, int size); +void UDPTCPNetwork_Startup(); +extern int UDPTCPNetwork_init; + + +/************************************************************************ + * tcp related functions + */ +class TCP { +private: + SOCKET sock; + struct sockaddr_storage peeraddr; + string remote_host; + string remote_port; + int readcnt; + int writecnt; + int islisten; +public: + TCP(); + TCP(SOCKET s); + TCP(string h, string p); + TCP(string hostport, int defaultport); + ~TCP(); + + int Connect(); + int Connect(string h, string p); + int Connect(string hostport, int defaultport); + long int ReadPop (char *buffer, long int pktlen, long int bufferlen); + long int ReadTimeout(char *buffer, long int len, int timeout); + long int Read(char *buffer, long int len); + long int Write(char *buffer, long int len); + void Close(); + int IsConnected(); + int IsData(int timeout); // timeout in ms; + int IsListen() { return islisten; }; + + int Listen(int port); + TCP* Accept(); + + SOCKET GetSocket() { return sock; }; + void SetSocket(SOCKET s, struct sockaddr_storage *saddr, socklen_t saddrlen); + + const string GetRemoteAddr(); + const string GetLocalAddr(); + + const string WebGetURLHost (string url); + const string WebGetURLPort (string url); + const string WebGetURLFile (string url); + int WebGetFile (string url, char *buffer, int maxsize); +}; + +#endif + diff --git a/testmodbus-client.ui b/testmodbus-client.ui new file mode 100644 index 0000000..6bdd1a5 --- /dev/null +++ b/testmodbus-client.ui @@ -0,0 +1,289 @@ + + + + + + False + + + + True + False + vertical + + + True + False + 4 + 4 + 4 + 4 + 0 + + + True + False + 12 + + + True + False + vertical + 4 + + + True + False + 4 + + + True + False + vertical + 4 + + + True + False + 4 + + + True + False + Host: + + + False + True + 0 + + + + + True + True + localhost + + + False + True + 1 + + + + + True + False + Port: + + + False + True + 2 + + + + + True + True + 6 + 502 + + + False + True + 3 + + + + + False + True + 0 + + + + + True + False + 4 + + + True + False + Refresh [ms]: + + + False + True + 0 + + + + + True + True + 4 + 1000 + + + False + True + 1 + + + + + False + True + 1 + + + + + False + True + 0 + + + + + True + False + vertical + + + Auto Reconnect + True + True + False + True + True + + + False + True + 0 + + + + + Read Only + True + True + False + True + True + + + False + True + 1 + + + + + + + + False + True + 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 + True + 0 + + + + + True + False + last error | status + + + False + False + 1 + + + + + + + + + True + False + Destination Host + + + + + + + + + False + False + 0 + + + + + + + + + + + +