///////////////////////////////////////////////////////////////////////////////// // // client.cc is part of TestModbus-Client. // ///////////////////////////////////////////////////////////////////////////////// #include #include "config.h" #include "client.h" #include "nwthread.h" #include "modbus.h" #define BUILDER_FILE "testmodbus-client.ui" /************************************************************************************ * Global Variables */ 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 int old_refreshtime = -1; int num_errors = 0; // error counter int num_requests = 0; // request counter NetworkThread netthread; 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; } 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 // window = gtk_builder_get_object (builder, "testmodbus-client"); gtk_widget_show_all (GTK_WIDGET(window)); gtk_main (); return 0; } void mbcli_cb_show(GtkWidget *widget, gpointer data) { GtkTextTag *tag_addr; GtkTextTag *tag_values; GtkTextTag *tag_head; GtkWidget *textview = GTK_WIDGET(gtk_builder_get_object (_builder_, "cli_RawResult")); GtkTextBuffer *textbuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview)); tag_head = gtk_text_buffer_create_tag (textbuffer, "Head", "foreground", "green", "style", PANGO_WEIGHT_HEAVY, "family", "Monospace", NULL); tag_addr = gtk_text_buffer_create_tag (textbuffer, "Addr", "foreground", "blue", "style", PANGO_WEIGHT_BOLD, "family", "Monospace", NULL); tag_values = gtk_text_buffer_create_tag (textbuffer, "Data", "foreground", "black", "style", PANGO_WEIGHT_NORMAL, "family", "Monospace", NULL); } /* * got some data */ gboolean mbcli_thread_cb_net(gpointer data) { NWTReqResult *res = (NWTReqResult*) data; GtkWidget *textview = GTK_WIDGET (gtk_builder_get_object (_builder_, "cli_RawResult")); GtkTextBuffer *textbuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview)); GtkTextIter start, end; char *tmpdata = (char *) res->data; std::string text; float f1, f2; char tmp[255]; printf ("%s:%d %s got some data\n", __FILE__, __LINE__, __FUNCTION__); gtk_text_buffer_get_start_iter(textbuffer, &start); gtk_text_buffer_get_end_iter(textbuffer, &end); gtk_text_buffer_delete(textbuffer, &start, &end); if (res->fc == 1 || res->fc == 2) { // // binary data // gtk_text_buffer_get_end_iter(textbuffer, &end); gtk_text_buffer_insert_with_tags_by_name(textbuffer, &end, " Addr [HEX] Registers\n", -1, "Head", NULL); for (int i = 0; i < res->cnt; i++) { if ((i % 32) == 0) { if (i > 0) { text += "\n"; gtk_text_buffer_get_end_iter(textbuffer, &end); gtk_text_buffer_insert_with_tags_by_name(textbuffer, &end, text.c_str(), -1, "Data", NULL); } text = "| "; snprintf (tmp, 255, "%5d [%s] ", res->reg + i, to_hex16(res->reg+i).c_str()); gtk_text_buffer_get_end_iter(textbuffer, &end); gtk_text_buffer_insert_with_tags_by_name(textbuffer, &end, tmp, -1, "Addr", NULL); } else if ((i % 16) == 0) text += " : "; else if ((i % 8) == 0) text += " "; if (tmpdata[i/8] & (1<cnt; i++) { // add addr to textbuffer snprintf (tmp, 255, "%5d ", res->reg + i); gtk_text_buffer_get_end_iter(textbuffer, &end); gtk_text_buffer_insert_with_tags_by_name(textbuffer, &end, tmp, -1, "Addr", NULL); // add data to textbuffer text = to_hex16((int) res->data[i]); if ((res->reg + i)%2 == 0 && i < res->cnt-1) { memcpy (((char*)&f1) + 0, &res->data[i], 2); memcpy (((char*)&f1) + 2, &res->data[i+1], 2); memcpy (((char*)&f2) + 2, &res->data[i], 2); memcpy (((char*)&f2) + 0, &res->data[i+1], 2); snprintf (tmp, 255, " | %6d | %9.3g | %9.3g", res->data[i], f1, f2); text = text + tmp; } else { snprintf (tmp, 255, " | %6d | | ", res->data[i]); text = text + tmp; } gtk_text_buffer_get_end_iter(textbuffer, &end); gtk_text_buffer_insert_with_tags_by_name(textbuffer, &end, text.c_str(), -1, "Data", NULL); gtk_text_buffer_get_end_iter(textbuffer, &end); gtk_text_buffer_insert(textbuffer, &end, (char *) "\n", -1); } } GtkWidget *statusbar = GTK_WIDGET (gtk_builder_get_object (_builder_, "cli_statusbar")); gtk_label_set_label(GTK_LABEL(statusbar), (char*)"got data"); free (res); return FALSE; }; /* * 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(); }; /* * returns the currently selected FC */ int mbcli_get_FC () { GtkWidget *FC_n[4] = { NULL, NULL, NULL, NULL }; int fc = 0, i = 0; FC_n[fc++] = GTK_WIDGET (gtk_builder_get_object (_builder_, "cli_FC1")); FC_n[fc++] = GTK_WIDGET (gtk_builder_get_object (_builder_, "cli_FC2")); FC_n[fc++] = GTK_WIDGET (gtk_builder_get_object (_builder_, "cli_FC3")); FC_n[fc++] = GTK_WIDGET (gtk_builder_get_object (_builder_, "cli_FC4")); for (i = 0, fc = -1; i < 4; i++) if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(FC_n[i]))) fc = i+1; return fc; } /* * returns the refresh time */ int mbcli_get_refreshtime() { GtkWidget *rd_refresh = GTK_WIDGET (gtk_builder_get_object (_builder_, "cli_refreshtime")); return atoi(gtk_entry_get_text(GTK_ENTRY(rd_refresh))); } /* * returns the register */ int mbcli_get_register() { GtkWidget *rd_refresh = GTK_WIDGET (gtk_builder_get_object (_builder_, "cli_register")); return atoi(gtk_entry_get_text(GTK_ENTRY(rd_refresh))); } /* * returns the number */ int mbcli_get_number() { GtkWidget *rd_refresh = GTK_WIDGET (gtk_builder_get_object (_builder_, "cli_number")); return atoi(gtk_entry_get_text(GTK_ENTRY(rd_refresh))); } /* * returns the unitid */ int mbcli_get_unitid() { GtkWidget *rd_refresh = GTK_WIDGET (gtk_builder_get_object (_builder_, "cli_unitid")); return atoi(gtk_entry_get_text(GTK_ENTRY(rd_refresh))); } /* * returns status of the update checkbox */ int mbcli_get_update () { GtkWidget *tb_update = GTK_WIDGET (gtk_builder_get_object (_builder_, "cli_Update")); if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(tb_update))) return 1; return 0; } /* * returns status of the reconnect checkbox */ int mbcli_get_autoconnect () { GtkWidget *tb_update = GTK_WIDGET (gtk_builder_get_object (_builder_, "cli_Reconnect")); if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(tb_update))) return 1; return 0; } /* * sets the update checkbox */ void mbcli_set_update (int active) { GtkWidget *tb_update = GTK_WIDGET (gtk_builder_get_object (_builder_, "cli_Update")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tb_update), active); } /* * returns status of the dont_use_FC1516 button */ int mbcli_get_FC1516 () { GtkWidget *tb_update = GTK_WIDGET (gtk_builder_get_object (_builder_, "cli_dontuse_FC1516")); if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(tb_update))) return 1; return 0; } /* * toglebutton to read some data is changed. */ void mbcli_cb_updateread (GtkToggleButton *togglebutton, gpointer user_data) { printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); if (mbcli_get_update()) { num_requests = 0; num_errors = 0; g_timeout_add(mbcli_get_refreshtime(), mbcli_refreshtimeout, NULL); if (mbcli_get_FC1516()) mbcli_set_update(0); } } gboolean mbcli_refreshtimeout(gpointer data) { int timeout = mbcli_get_refreshtime(); int update = mbcli_get_update(); int fc1516 = mbcli_get_FC1516(); int fc = mbcli_get_FC(); int reg = mbcli_get_register(); int num = mbcli_get_number(); int unitid = mbcli_get_unitid(); int state = netthread.GetState(); GtkWidget *statusbar = GTK_WIDGET (gtk_builder_get_object (_builder_, "cli_statusbar")); GtkWidget *rate = GTK_WIDGET (gtk_builder_get_object (_builder_, "cli_rate")); char txt[255]; printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); if (state == NWT_running) { num_requests++; if (netthread.SendRequestRead(unitid, fc, reg, num) == 0) { num_errors++; gtk_label_set_label(GTK_LABEL(statusbar), "busy, another request in progress"); } else { gtk_label_set_label(GTK_LABEL(statusbar), "request send"); } snprintf (txt, 255, "%d / %d", num_errors, num_requests); gtk_label_set_label(GTK_LABEL(rate), txt); } else { gtk_label_set_label(GTK_LABEL(rate), "- / -"); if (mbcli_get_autoconnect()) mbcli_cb_connect(NULL, NULL); // reconnect if needed } // // need to continue if (fc1516) { mbcli_set_update(0); return FALSE; } if (!update) return FALSE; // // refresh time changed? if (timeout != old_refreshtime) { old_refreshtime = timeout; g_timeout_add(timeout, mbcli_refreshtimeout, NULL); return FALSE; } return TRUE; // continue with timer };