///////////////////////////////////////////////////////////////////////////////// // // 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 = ""; memset (&req_mbh, 0x0, sizeof(modbustcp_rq_header)); req_new = 0; memset (&req_time, 0x0, sizeof (req_time)); req_timeout = 0; }; 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; }; int NetworkThread::SendRequestRead(int unitid, int fc, int reg, int num) { Lock(); if (req_mbh.fc != 0 || req_new != 0) { printf ("%s%d %s req_new: %d req_mbh.fc: %d\n", __FILE__, __LINE__, __FUNCTION__, req_new, req_mbh.fc); UnLock(); return 0; } req_new = 1; req_mbh.fc = fc; req_mbh.offset = reg; req_mbh.number = num; req_mbh.uid = unitid; printf ("%s:%d build request fc:%d offset:%d number:%d\n", __FILE__, __LINE__, req_mbh.fc, req_mbh.offset, req_mbh.number); UnLock(); return 1; } void NetworkThread::GuiSendStatustext(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); } /* * send response to the gui. * the data block must be freed. */ void NetworkThread::GuiSendResult(char *buffer, int len, modbustcp_rq_header *mbh_rq) { NWTReqResult *res = (NWTReqResult*) malloc(sizeof (NWTReqResult)); int i, cnt; uint16_t tmp; res->fc = mbh_rq->fc; res->cnt = mbh_rq->number; res->reg = mbh_rq->offset; if (res->fc == 1 || res->fc == 2) { } else { for (cnt = 0, i = 9; i < len && cnt < 0x100 && cnt < mbh_rq->number; cnt++) { memcpy (&tmp, buffer+i, 2); res->data[cnt] = ntohs(tmp); i += 2; } } gdk_threads_add_idle(mbcli_thread_cb_net, (void *) res); } /* * data must be Thread Locked already * request information must be set already */ void NetworkThread::BuildAndSendReadReq(char *buffer, int size) { char *pos; req_mbh.length = 0; req_mbh.transid++; pos = modbustcp_pkt_headerrq(buffer, size, &req_mbh); tcp.Write(buffer, (pos-buffer)); }; #define BUFFER_SIZE 0x10000 void NetworkThread::Thread() { int i; long int len; char buffer[BUFFER_SIZE]; modbustcp_res_header in_mbh; // incomming mbh data char *pos; printf ("%s:%d NetworkThread::Thread Started\n", __FILE__, __LINE__); GuiSendStatustext((char*)"connecting"); Lock(); req_mbh.fc = 0; req_mbh.transid = 0; UnLock(); // // connect to ip address // SetState (NWT_connect); i = tcp.Connect(host, port); if (i < 0) { // // error on connect, stop thread. GuiSendStatustext(strerror(errno)); SetState(NWT_nothing); GuiSendStatustext(NULL); printf ("%s:%d NetworkThread::Thread Finished on connect\n", __FILE__, __LINE__); return; } if (i == 1) GuiSendStatustext((char*)"connected"); // FIXME: else: still connecting need some timeout and checks. SetState(NWT_running); // // connection established // go into the main loop while (GetState() == NWT_running) { // // new request? Lock(); if (req_new == 1) { BuildAndSendReadReq(buffer, BUFFER_SIZE); req_new = 0; } UnLock(); // // check for new data i = tcp.IsData(10); if (i < 0) { SetState(NWT_error); break; } else if (i == 0) continue; // // we got some data Lock(); printf ("read data\n"); len = tcp.Read(buffer, BUFFER_SIZE); if (len < 0) state = NWT_close; else { // // we could get some data, if busy reset connection if (req_mbh.fc == 0) { // got data without request? - Protokol error errno = EPROTO; state = NWT_error; break; } // // return data if ((pos = modbustcp_unpkt_headerres(&in_mbh, buffer, len)) == NULL) { printf ("%s:%d error on reading modbus header (%s)\n", __FILE__, __LINE__, strerror(errno)); errno = EPROTO; GuiSendStatustext(strerror(errno)); } // // process data is valid if ((in_mbh.fc == 1 || in_mbh.fc == 2) && (in_mbh.fc == req_mbh.fc && in_mbh.number == (((req_mbh.number-1) / 8)+1) && in_mbh.transid == req_mbh.transid)) { GuiSendResult(buffer, len, &req_mbh); req_mbh.fc = 0; } else if ((in_mbh.fc == 3 || in_mbh.fc == 4) && (in_mbh.fc == req_mbh.fc && in_mbh.number/2 == req_mbh.number && in_mbh.transid == req_mbh.transid)) { GuiSendResult(buffer, len, &req_mbh); req_mbh.fc = 0; } else { printf ("%s:%d incorrect data: fc: %d == %d number: %d == %d(%d) transid: %d == %d\n", __FILE__, __LINE__, in_mbh.fc, req_mbh.fc, in_mbh.number, (((req_mbh.number-1) / 8)+1), req_mbh.number, in_mbh.transid, req_mbh.transid); errno = EPROTO; GuiSendStatustext(strerror(errno)); } req_mbh.fc = 0; } UnLock(); } // // main loop stopped, clean up i = GetState(); switch (i) { case NWT_error: GuiSendStatustext(strerror(errno)); tcp.Close(); break; case NWT_close: GuiSendStatustext((char*)"Connection Closed"); tcp.Close(); break; default: GuiSendStatustext((char*)"Unknown Error"); tcp.Close(); break; } SetState(NWT_nothing); printf ("%s:%d NetworkThread::Thread Finished\n", __FILE__, __LINE__); };