/*-------------------------------------------------------------------- * File: gtkhistory.g * * Description: Demonstrates the Cascade Historian * * Functions and methods by category * * Interpolator: InterpolatorSettings.change_int * InterpolatorSettings.assign_values * InterpolatorSettings.get_data * Query: allow_entry_values * countdown * record_data * reset_deadbands * plot_prep * send_query * write_minmax * file_add * show_data * Deadbanding: db_options * db_labels * create_dbtype_win * Window: make_toggle_button * qry_radio_but * qry_entry * create_history * Main: main *------------------------------------------------------------------*/ /******************************************************** * GENERAL UTILITY Code * ********************************************************/ /* Get access to the library of common functions. */ require("lib/common.g"); /* Keep track of all child processes that this process has started. */ Children := nil; /******************************************************** * INTERPOLATOR Code * ********************************************************/ /*-------------------------------------------------------------------- * Method: InterpolatorSettings.change_int * Returns: t or nil * Description: Responding to a click on a "Choose an Interpolator" * radio button, this method calls the allow_entry_values() * function on the active button. The callback is set up * in qry_radio_but(). *------------------------------------------------------------------*/ method InterpolatorSettings.change_int(button, str, w1, w2, w3, e1, e2, e3) { if (button.switched_on()) { .fn = str; allow_entry_values(w1, w2, w3, e1, e2, e3); } } /*-------------------------------------------------------------------- * Method: InterpolatorSettings.assign_values * Returns: t or nil * Description: Assigns the values from the interpolator entry widgets * to the appropriate instance variables of the class. * Called by send_query(). *------------------------------------------------------------------*/ method InterpolatorSettings.assign_values(e1, e2, e3, e4, e5, e6) { .y_history = assign_history(.dbflag, .y_history, e1.get_text()); .start = number(e2.get_text()); .duration = number(e3.get_text()); .x_history = assign_history(.dbflag, .x_history, e4.get_text()); .interval = number(e5.get_text()); .max_gap = number(e6.get_text()); } /*-------------------------------------------------------------------- * Method: InterpolatorSettings.get_data * Returns: a list of two lists * Description: Sends the query and retrieves the data. Activated by * the send_query() function. *------------------------------------------------------------------*/ method InterpolatorSettings.get_data(e1, e2, e3, e4, e5, e6, e7) { local tsk, intpl, buf_length, alldata, count, dur, data, outfile; local xdata = list(); local ydata = list(); local midnite = find_midnite(); try { /* Make sure there are valid values in the entry widgets.*/ if (undefined_p(.start) || (!number_p(.start))) { .start = 0; e2.set_text("0"); } if (undefined_p(.duration) || (!number_p(.duration)) || (.duration <= 0)) { .duration = 10; e3.set_text("10"); } if (undefined_p(.interval) || (!number_p(.interval)) || (.interval < .01)) { .interval = .01; e5.set_text("0.01"); } if ((tsk = locate_task("demohistdb", nil)) != nil) { alldata = list(); count = 0; intpl = self.set_interpolator(tsk); buf_length = caddr(send(tsk, `bufferIdLength(@intpl))); if(!((.fn == "TimeSetup") || (.fn == "RelSetup"))) e7.set_text(string(buf_length)); while (count < buf_length) { if((buf_length - count) > 100) dur = 100; else dur = buf_length - count; data = send(tsk, `bufferIdDataAscii(@intpl, @count, @dur)); data = cddr(cdr(data)); alldata = append(alldata, data); count = count + 100; } if(.dbflag == "NONE") outfile = open("/tmp/cogentdemo/hsoutput.dat", "w"); if(.dbflag == "DB") outfile = open("/tmp/cogentdemo/hsoutput2.dat", "w"); if(.dbflag == "DBP") outfile = open("/tmp/cogentdemo/hsoutput3.dat", "w"); if (outfile) if (buf_length == 0) { writec(outfile, "# Sorry, no data matched your query."); writec(outfile, string("\n", midnite, " 0", "\n", (midnite + 1), " 0")); close(outfile); } else { with d in alldata do writec(outfile, string(car(d), " ", cadr(d), "\n")); close(outfile); } while (alldata != nil) { if(.fn == "TimeSetup" || .fn == "NoInterpolator" || .fn == "Periodic") xdata = cons(caar(alldata) - midnite, xdata); else xdata = cons(caar(alldata), xdata); ydata = cons(cadar(alldata), ydata); alldata = cdr(alldata); } xdata = reverse(xdata); ydata = reverse(ydata); send(tsk, `bufferIdDestroy(@intpl)); } list(xdata, ydata); } catch list(nil, nil); } /******************************************************** * QUERY Code * ********************************************************/ /*-------------------------------------------------------------------- * Function: allow_entry_values * Returns: t or nil * Description: Sets the three optional parameter entry widgets * (X history, Time Interval, and Max. gap) sensitive or * non-sensitive. Called by qry_radio_but() and * InterpolatorSettings.change_int(). The possible values * for e1 - e3 are 0 (FALSE) or 1 (TRUE). *------------------------------------------------------------------*/ function allow_entry_values(w1, w2, w3, e1, e2, e3) { w1.set_sensitive(e1); w2.set_sensitive(e2); w3.set_sensitive(e3); } /*-------------------------------------------------------------------- * Function: countdown * Returns: t or nil * Description: Called by record_data() to do the time count-down. *------------------------------------------------------------------*/ function countdown(txt_wgt, time) { txt_wgt.set_point(42); txt_wgt.forward_delete(txt_wgt.get_length() - 42); txt_wgt.insert(FONT, nil, nil, string(time - clock()), -1); } /* Assign a global variable for recording time, and a font. */ RECORD_TIME = 5; FONT = gdk_font_load ("-adobe-courier-medium-r-normal--*-120-*-*-*-*-*-*"); /*-------------------------------------------------------------------- * Function: record_data * Returns: t or nil * Description: Records data for the specified time, then sends a query. * Arguments: button: The Record button * iset: An InterpolatorSettings instance * e1 - e6: The six Interpolator options entry widgets * e7: The "Number of points from last query" display * but_db1 - 3: The three Deadband options buttons * b1 - b4: The four Interpolator options buttons * b6: The Update display button *------------------------------------------------------------------*/ function record_data(button, iset, but_db1, but_db2, but_db3, text, e1, e2, e3, e4, e5, e6, e7, b1, b2, b3, b4, b6) { if (button.switched_on()) { local time = clock() + RECORD_TIME; text.backward_delete(text.get_length()); text.insert(FONT, nil, nil, (string("Recording,please wait.\nSeconds remaining: ", RECORD_TIME)), -1); numtimer = every (1, `countdown(@text, @time)); e3.set_text(string(RECORD_TIME + 1)); iset.set_defaults(button, e2); send_hs_command(button, "enable", e1.get_text(), nil); after(RECORD_TIME, `(@button).set_active(FALSE)); after((RECORD_TIME + .1), `(send_hs_command(@button, "enable", (@e1).get_text(), nil))); after((RECORD_TIME + .1), `(cancel(numtimer))); after((RECORD_TIME + .15), `(reset_deadbands(nil, @iset, @but_db1, @but_db2, @but_db3, @text, @e1, @e2, @e3, @e4, @e5, @e6, @e7, @b1, @b2, @b3, @b4, @button, @b6))); } } /*-------------------------------------------------------------------- * Function: reset_deadbands * Returns: t or nil * Description: Clears all traces and sets the Full data set (no deadband) * option. Called when non-deadband buttons are activated. *------------------------------------------------------------------*/ function reset_deadbands(button, iset, but1, but2, but3, text, e1, e2, e3, e4, e5, e6, e7, b1, b2, b3, b4, b5, b6) { but2.set_active(FALSE); but3.set_active(FALSE); but1.set_active(TRUE); if(is_file("/tmp/cogentdemo/hsoutput2.dat")) unlink("/tmp/cogentdemo/hsoutput2.dat"); if(is_file("/tmp/cogentdemo/hsoutput3.dat")) unlink("/tmp/cogentdemo/hsoutput3.dat"); plot_prep(but1, iset, but1, but2, but3, text, e1, e2, e3, e4, e5, e6, e7, b1, b2, b3, b4, b5, b6); } /*-------------------------------------------------------------------- * Function: plot_prep * Returns: t or nil * Description: Writes to the plhistsetup.dat file the relevant values * for the time of midnight, x-axis label, and deadband * status. *------------------------------------------------------------------*/ function plot_prep (button, iset, but_db1, but_db2, but_db3, text, e1, e2, e3, e4, e5, e6, e7, b1, b2, b3, b4, b5, b6) { local fp, histtime, line; /* Write the time. */ fp = open("/tmp/cogentdemo/plhistsetup.dat", "w", nil); histtime = find_midnite(); line = string("histtime = ", histtime, "\n"); writec(fp, line); /* Set up the X-axis label. */ if ((iset.fn == "NoInterpolator") || (iset.fn == "Periodic")) line = "xlab = 1\n"; else line = "xlab = 2\n"; writec(fp, line); /* Set the deadband flag in the InterpolatorSettings instance. */ if(button.switched_on() && button == but_db1) iset.dbflag = "NONE"; if(button.switched_on() && button == but_db2) iset.dbflag = "DB"; if(button.switched_on() && button == but_db3) iset.dbflag = "DBP"; /* Write the on or off value for each deadband. */ if (but_db1.switched_on()) line = "db1 = 1\n"; else line = "db1 = 0\n"; writec(fp, line); if (but_db2.switched_on()) line = "db2 = 1\n"; else line = "db2 = 0\n"; writec(fp, line); if (but_db3.switched_on()) line = "db3 = 1\n"; else line = "db3 = 0\n"; writec(fp, line); close(fp); send_query(button, iset, text, e1, e2, e3, e4, e5, e6, e7, b1, b2, b3, b4, b5, b6); } /*-------------------------------------------------------------------- * Function: send_query * Returns: t or nil * Description: Calls the necessary functions to send a query to the * Historian, and handle the data returned. It is activated * by the "Record" button popping out, or any radio button. * It sends two queries, the first to calculate the minimum * and maximum values for use in creating plots, and the * second to get the actual data. * Arguments: button: The button that activated the function * iset: An InterpolatorSettings instance * e1 - e6: The six Interpolator options entry widgets * e7: The "Number of points from last query" display * b1 - b4: The four Interpolator options buttons * b5: The Record button * b6: The Update display button *------------------------------------------------------------------*/ function send_query(button, iset, text, e1, e2, e3, e4, e5, e6, e7, b1, b2, b3, b4, b5, b6) { local fnholder, datalist, minmaxlist; if ((button == nil) || (button == b6) || (button.switched_on())) { if ((button == b1 || button == b2 || button == b3 || button == b4 || button == b5 || button == b6)) iset.dbflag = "NONE"; iset.assign_values(e1, e2, e3, e4, e5, e6); datalist = list(); fnholder = iset.fn; /* Assign a name for the setup query. */ if ((iset.fn == "NoInterpolator") || (iset.fn == "Periodic")) iset.fn = "TimeSetup"; else iset.fn = "RelSetup"; /* Make the setup query and assign minimum and maximum values. */ datalist = iset.get_data(e1, e2, e3, e4, e5, e6, e7); if (car(datalist) && cadr(datalist)) minmaxlist = list(min_max(car(datalist)), min_max(cadr(datalist))); else minmaxlist = nil; /* Make the actual query. */ iset.fn = fnholder; datalist = iset.get_data(e1, e2, e3, e4, e5, e6, e7); show_data(text, iset, button, datalist, minmaxlist); } else { write_minmax(iset.misc_info); } } /*-------------------------------------------------------------------- * Function: write_minmax * Returns: t or nil * Description: Writes a string to the plhistsetup.dat file containing * four lines, each line assigning a value for an X or Y axis * minimum or maximum variable, which are used by gnuplot. *------------------------------------------------------------------*/ function write_minmax(minmax_string) { local fp = open("/tmp/cogentdemo/plhistsetup.dat", "a", nil); writec(fp, minmax_string); close(fp); } /*-------------------------------------------------------------------- * Function: file_add * Returns: t or nil * Description: Adds content from a file previously opened for reading * (inptr) to a file previously opened for writing (outptr). * Adds extra newlines, which gnuplot uses to mark the beginning * of a new index file. Called only by show_data(). *------------------------------------------------------------------*/ function file_add(inptr, outptr) { local line; while(line != _eof_) { line = read_line(inptr); if (line != "Unexpected end of file") writec(outptr, string(line, "\n")); } writec(outptr, "\n\n"); close(inptr); } /*-------------------------------------------------------------------- * Function: show_data * Returns: t or nil * Description: Shows interpolated query results from the Cascade Historian * in the text widget. Sets up a single file (hsoutputpl.dat) * that contains the content of all existing hsoutput files. * This is necessary because gnuplot must read from a single file. * Uses file_add() to do the actual reading and writing of the files. *------------------------------------------------------------------*/ function show_data(txt_wgt, int_set, button, datalist, minmaxlist) { local start_time, tsk, infile, line, string_list, line_ret; local title_string, x_list, y_list; local f1, f2, f3, f4; x_list = car(datalist); y_list = cadr(datalist); midnite = find_midnite(); if (int_set.fn == "NoInterpolator" || int_set.fn == "Periodic") { x_is_time = t; title_string = "Query results: \n Time Y History\n"; } else { x_is_time = nil; title_string = "Query results: \nX-hist / Y-hist\n"; } // midnite = find_midnite(); txt_wgt.freeze(); txt_wgt.backward_delete(txt_wgt.get_length()); txt_wgt.insert(FONT, nil, nil, title_string, -1); if(int_set.dbflag == "NONE") infile = open("/tmp/cogentdemo/hsoutput.dat", "r"); if(int_set.dbflag == "DB") infile = open("/tmp/cogentdemo/hsoutput2.dat", "r"); if(int_set.dbflag == "DBP") infile = open("/tmp/cogentdemo/hsoutput3.dat", "r"); if (infile) { line = nil; while(line != _eof_) { line = read_line(infile); if (line != "Unexpected end of file") { if ((strstr(line,"#") != -1)) { txt_wgt.insert(FONT, nil, nil, line, -1); read_line(infile); read_line(infile); } else { string_list = string_split(line, " ", 2); if (int_set.fn == "NoInterpolator" || int_set.fn == "Periodic") line_ret = string(number(car(string_list)) - midnite, " ", cadr(string_list),"\n"); else line_ret = string(number(car(string_list)), " ", cadr(string_list),"\n"); txt_wgt.insert(FONT, nil, nil, line_ret, -1); } } } close(infile); if(x_list && y_list && minmaxlist != nil) { if (x_is_time) { x_min = caar(minmaxlist); x_max = cadar(minmaxlist); } else { x_min = floor(caar(minmaxlist)); x_max = ceil(cadar(minmaxlist)); } y_min = floor(caadr(minmaxlist)); y_max = ceil(car(cdadr(minmaxlist))) + 1; int_set.misc_info = string("x_min = ", x_min, "\n", "x_max = ", x_max, "\n", "y_min = ", y_min, "\n", "y_max = ", y_max, "\n"); write_minmax(int_set.misc_info); } else { txt_wgt.backward_delete(txt_wgt.get_point()); txt_wgt.insert(FONT, nil, nil, string("Sorry, there was an error retrieving\n", "data from the Cascade Historian."), -1); } } txt_wgt.thaw(); if(is_file("/tmp/cogentdemo/hsoutput.dat")) f1 = open("/tmp/cogentdemo/hsoutput.dat", "r"); if(is_file("/tmp/cogentdemo/hsoutput2.dat")) f2 = open("/tmp/cogentdemo/hsoutput2.dat", "r"); if(is_file("/tmp/cogentdemo/hsoutput3.dat")) f3 = open("/tmp/cogentdemo/hsoutput3.dat", "r"); f4 = open("/tmp/cogentdemo/hsoutputpl.dat", "w"); if(f1) { file_add(f1, f4); if(f2) file_add(f2, f4); else /* Put in a spacer line so gnuplot starts a new plot. */ writec(f4, "999 999\n\n\n"); if(f3) file_add(f3, f4); } close(f4); } /******************************************************** * DEADBANDING Code * ********************************************************/ /*-------------------------------------------------------------------- * Function: db_options * Returns: t or nil * Description: Creates a GtkEntry widget and puts it into a table. * The widget calls the update_value() function when it * gets changed. *------------------------------------------------------------------*/ function db_options(tbl, p_array, left, right) { local entry; for (i=0; i<=3; i++) { entry = new(GtkEntry); entry.width = 40; entry.set_text(string(p_array[i])); entry.signal("changed", `(@p_array)[@i] = number((@entry).get_text())); tbl.attach_defaults(entry, left, right, i + 2, i + 3); } } /*-------------------------------------------------------------------- * Function: db_labels * Returns: t or nil * Description: Creates labels and puts them in a table. *------------------------------------------------------------------*/ function db_labels(tbl, title, left, right, top, bottom) { local label; label = new(GtkLabel); label.set_text(title); tbl.attach_defaults(label, left, right, top, bottom); } /*-------------------------------------------------------------------- * Function: create_dbtype_win * Returns: A GtkWindow, or a destroyed instance * Description: Creates the Deadband Type window. *------------------------------------------------------------------*/ function create_dbtype_win (!point_list, button) { local db1, db2, db3, vbox, table, pa1, pa2, pa3; local label, separator, box2, abut, cbut, okbut; if (((undefined_p(win_db) || (win_db == nil)) && (button.get_active() == TRUE))) { db1 = car(point_list); db2 = cadr(point_list); win_db = new (GtkWindow); send_message("6.50"); win_db.signal ("destroy", #win_db = nil); win_db.title = "Deadband Type"; win_db.set_uposition(20, 440); win_db.set_color(1, GTK_STATE_NORMAL, 0xdddddd); win_db.width = 500; table = gtk_table_new(7, 4, FALSE); table.border_width = 15; table.set_col_spacings(15); table.set_row_spacings(3); table.set_row_spacing(0, 10); table.set_row_spacing(3, 10); table.set_row_spacing(5, 10); db_labels(table, "Set up deadband types", 0, 4, 0, 1); db_labels(table, "MV", 1, 2, 1, 2); db_labels(table, "PV", 2, 3, 1, 2); db_labels(table, "Absolute:", 0, 1, 2, 3); db_labels(table, "Percent:", 0, 1, 3, 4); db_labels(table, "Time Limit:", 0, 1, 4, 5); db_labels(table, "Count Limit:", 0, 1, 5, 6); db_labels(table, string("Deadband range is set to this ", "value. "), 3, 4, 2, 3); db_labels(table, string("Range set to percent of last logged ", "value. "), 3, 4, 3, 4); db_labels(table, string("The maximum time period to deadband.", " "), 3, 4, 4, 5); db_labels(table, string("The max number of received values to", " deadband."), 3, 4, 5, 6); db_labels(table, string("Note: These settings don't take effect", " until the next record session."), 0, 4, 6, 7); pa1 = array(db1.absolute, db1.percent, db1.timelimit, db1.countlimit); pa2 = array(db2.absolute, db2.percent, db2.timelimit, db2.countlimit); db_options(table, pa1, 1, 2); db_options(table, pa2, 2, 3); vbox = new(GtkVBox); win_db.add(vbox); vbox.pack_start(table, TRUE, TRUE, 0); separator = new(GtkHSeparator); vbox.pack_start(separator, TRUE, TRUE, 0); box2 = new(GtkHButtonBox); box2.border_width = 10; box2.set_layout(GTK_BUTTONBOX_SPREAD); vbox.pack_start(box2, TRUE, TRUE, 0); cbut = new(GtkButton); cbut.label = "Cancel"; cbut.signal("clicked", `(@button).set_active(FALSE)); cbut.signal("clicked", `(@win_db).destroy()); button_messages (cbut, "6.55", "6.50"); box2.pack_start(cbut, TRUE, TRUE, 0); cbut.show(); okbut = new(GtkButton); okbut.label = "OK"; okbut.signal("clicked", `(@db1).set_parms(@okbut, @pa1)); okbut.signal("clicked", `(@db2).set_parms(@okbut, @pa2)); okbut.signal("clicked", `(@button).set_active(FALSE)); okbut.signal("clicked", `(@win_db).destroy()); button_messages (okbut, "6.56", "6.50"); box2.pack_start(okbut, TRUE, TRUE, 0); okbut.show(); win_db.signal("destroy", `(@button).set_active(FALSE)); win_db.show_all(); win_db; } else if(instance_p(win_db)) win_db.destroy(); } /******************************************************** * HISTORY WINDOW Code * ********************************************************/ /*-------------------------------------------------------------------- * Function: make_toggle_button * Returns: A GtkToggleButton * Description: Creates toggle buttons. *------------------------------------------------------------------*/ function make_toggle_button(lbl, color) { local button; button = new(GtkToggleButton); button.label = lbl; button.set_color(1, GTK_STATE_NORMAL, color); button.set_color(1, GTK_STATE_PRELIGHT, (color + 0x111111)); button.set_color(1, GTK_STATE_ACTIVE, (color - 0x111111)); button; } /*-------------------------------------------------------------------- * Function: qry_radio_but * Returns: A GtkRadioButton * Description: Creates the "Choose an Interpolator" radio buttons and * puts them into a table. The last 6 parameters simply * get passed along to the allow_entry_values() function * and the .change_int() method. *------------------------------------------------------------------*/ function qry_radio_but(tbl, txt, butlist, int_set, msg, top, bottom, w1, w2, w3, e1, e2, e3) { local button; button = gtk_radio_button_new_with_label(butlist, txt); if (txt == "NoInterpolator") { button.set_active(TRUE); allow_entry_values(w1, w2, w3, e1, e2, e3); } button.signal("clicked", `((@int_set).change_int(@button, @txt, @w1, @w2, @w3, @e1, @e2, @e3))); button_messages (button, msg, "6"); tbl.attach_defaults(button, 0, 1, top, bottom); button; } /*-------------------------------------------------------------------- * Function: qry_entry * Returns: A GtkEntry or GtkCombo widget, as specified * Description: Creates a GtkEntry or GtkCombo widget, sets defaut values, * and puts it into a table. *------------------------------------------------------------------*/ function qry_entry(tbl, txt, value, top, bottom) { local box, label, entry, cbitems, cmb, ent_but = nil; box = new(GtkHBox); label = new(GtkLabel); label.set_text(txt); label.width = 80; box.pack_start(label, TRUE, TRUE, 0); if ((strstr(txt, "history")) == -1) { entry = new(GtkEntry); entry.width = 75; if (value == nil) entry.set_text(""); else entry.set_text(string(value)); box.pack_start(entry, TRUE, TRUE, 0); } else { cbitems = list("MV_001", "PV_001"); cmb = new(GtkCombo); cmb.width = 75; cmb.use_arrows = 0; cmb.set_popdown_strings(cbitems); entry = car(cmb.children()); ent_but = cadr(cmb.children()); entry.set_editable(FALSE); if (value == nil) entry.set_text(""); else entry.set_text(string(value)); box.pack_start(cmb, TRUE, TRUE, 0); } tbl.attach_defaults(box, 1, 2, top, bottom); entry; } /*-------------------------------------------------------------------- * Function: create_history * Returns: A GtkWindow * Description: Creates the History window. *------------------------------------------------------------------*/ function create_history () { local history_win, title, frame, box1, box2, box3, table; local label, label1, label2, but_int1, but_int2, but_int3, but_int4; local recbut, entry, qubut, dbsbut, text, but_db1, but_db2, but_db3; local spinner, adj, xbut, iset, ent_yhs, ent_str, ent_dur; local ent_xhs, ent_int, ent_max, ent_res, dbmv_set, dbpv_set, db_list; local dbsbut, plbut, swin, buttons; history_win = new (GtkWindow); send_message("6"); history_win.signal ("destroy", #history_win = nil); history_win.title = "Cogent Tools Demo: History"; history_win.set_color(1, GTK_STATE_NORMAL, 0xdddddd); history_win.border_width = 10; history_win.width = 380; /* Title frame. */ box1 = new(GtkVBox); title = new (GtkLabel); title.set_text("Cogent Tools Demo - History"); title.set_color(1, GTK_STATE_NORMAL, 0xff0000); title.height = 25; frame = new(GtkFrame); frame.set_color(1, GTK_STATE_NORMAL, 0xff0000); frame.add(title); frame.border_width = 5; box1.pack_start(frame, TRUE, TRUE, 0); history_win.add (box1); /* Record Values and Exit buttons. */ table = gtk_table_new(5, 1, FALSE); table.border_width = 5; table.set_homogeneous(FALSE); recbut = make_toggle_button("Record", 0xddccee); recbut.signal("clicked", `send_hs_command(@recbut, "enable", nil, nil)); button_messages (recbut, "6.2", "6"); label1 = new(GtkLabel); label1.set_text("data for"); adj = gtk_adjustment_new (0, 1, 200, 1, 5, 0.0); spinner = new(GtkSpinButton); spinner.set_adjustment(adj); spinner.set_value(RECORD_TIME); adj.signal("value_changed", `(RECORD_TIME = (@adj).value)); label2 = new(GtkLabel); label2.set_text("seconds. "); xbut = new(GtkButton); xbut.label = "Exit"; xbut.signal("clicked", `(@history_win).destroy()); iset = new(InterpolatorSettings); table.attach_defaults(recbut, 0, 1, 0, 1); table.attach_defaults(label1, 1, 2, 0, 1); table.attach_defaults(spinner, 2, 3, 0, 1); table.attach_defaults(label2, 3, 4, 0, 1); table.attach_defaults(xbut, 4, 5, 0, 1); box1.pack_start(table, TRUE, TRUE, 5); text = new(GtkText); text.set_editable(FALSE); /* Interpolator options. */ frame = new(GtkFrame); frame.border_width = 5; frame.set_color(1, GTK_STATE_NORMAL, 0xddccee); frame.set_label(" Interpolator options: "); frame.set_label_align(.05, 1); frame.set_shadow_type(GTK_SHADOW_IN); box1.pack_start(frame, TRUE, TRUE, 0); table = gtk_table_new(2, 6, FALSE); table.border_width = 10; table.set_col_spacing(0, 20); table.set_row_spacings(3); frame.add(table); ent_yhs = qry_entry(table, "Y history:", iset.y_history, 0, 1); ent_str = qry_entry(table, "Start:", iset.start, 1, 2); ent_dur = qry_entry(table, "Duration:", iset.duration, 2, 3); ent_xhs = qry_entry(table, "X history:", iset.x_history, 3, 4); ent_int = qry_entry(table, "Time Interval:", iset.interval, 4, 5); ent_max = qry_entry(table, "Max. gap:", iset.max_gap, 5, 6); but_int1 = qry_radio_but(table, "NoInterpolator", nil, iset, "6.31", 0, 1, ent_xhs, ent_int, ent_max, 0, 0, 0); but_int2 = qry_radio_but(table, "Periodic", list(but_int1), iset, "6.32", 1, 2, ent_xhs, ent_int, ent_max, 0, 1, 1); but_int3 = qry_radio_but(table, "Relative", list(but_int1, but_int2), iset, "6.33", 2, 3, ent_xhs, ent_int, ent_max, 1, 0, 0); but_int4 = qry_radio_but(table, "FixedRelative", list(but_int1, but_int2, but_int3), iset, "6.34", 3, 4, ent_xhs, ent_int, ent_max, 1, 1, 0); ent_res = new(GtkEntry); ent_res.width = 45; qubut = new(GtkButton); qubut.label = "Update display"; qubut.set_color(1, GTK_STATE_NORMAL, 0xddccee); qubut.set_color(1, GTK_STATE_PRELIGHT, 0xeeddff); button_messages (qubut, "6.3", "6"); table.attach_defaults(qubut, 0, 1, 5, 6); /* Deadband options. */ dbmv_set = new(DeadbandSettings); dbmv_set.history = "MV_001"; dbpv_set = new(DeadbandSettings); dbpv_set.history = "PV_001"; db_list = list(dbmv_set, dbpv_set); box2 = new(GtkHBox); box1.pack_start(box2, TRUE, TRUE, 0); frame = new(GtkFrame); frame.border_width = 5; frame.set_color(1, GTK_STATE_NORMAL, 0xddccee); frame.set_label(" Deadband options: "); frame.set_label_align(.05, 1); frame.set_shadow_type(GTK_SHADOW_IN); box2.pack_start(frame, TRUE, TRUE, 0); table = gtk_table_new(1, 4, FALSE); table.border_width = 10; table.set_row_spacings(3); frame.add(table); but_db1 = gtk_check_button_new_with_label ("Full data set (no deadband)"); but_db2 = gtk_check_button_new_with_label ("Deadband on, prior value off"); but_db3 = gtk_check_button_new_with_label ("Deadband on, prior value on"); but_db1.signal("enter", `send_message("6.51")); but_db2.signal("enter", `send_message("6.52")); but_db3.signal("enter", `send_message("6.53")); dbsbut = make_toggle_button("Set up deadband types", 0xddccee); dbsbut.signal("toggled", `create_dbtype_win(@db_list, @dbsbut)); dbsbut.signal("enter", `send_message("6.5")); table.attach_defaults(but_db1, 0, 1, 0, 1); table.attach_defaults(but_db2, 0, 1, 1, 2); table.attach_defaults(but_db3, 0, 1, 2, 3); table.attach_defaults(dbsbut, 0, 1, 3, 4); /* Plot and text display. */ box3 = new(GtkVBox); box2.pack_start(box3, TRUE, TRUE, 30); local button; plbut = new(GtkToggleButton); plbut.height = 20; plbut.label = "Plot Data"; plbut.set_color(1, GTK_STATE_NORMAL, 0xccccb0); plbut.set_color(1, GTK_STATE_PRELIGHT, 0xddddbb); plbut.set_color(1, GTK_STATE_ACTIVE, 0xbbbb99); plbut.signal("toggled", `start_stop(@plbut, "gnuplot", "plothist1", "-background", "gray", "-geometry", "500x400-10-30", "plhist.cfg", nil, nil, nil)); plbut.signal("toggled", `anygui_move_window(@plbut, @history_win, 380, 45, 100, 45)); button_messages (plbut, "6.4", "6"); label = new(GtkLabel); label.set_text("Number\nof points\nfrom last\nquery:"); box3.pack_end(ent_res, FALSE, FALSE, 5); box3.pack_end(label, TRUE, TRUE, 5); box3.pack_end(plbut, TRUE, TRUE, 5); swin = new(GtkScrolledWindow); swin.set_policy(GTK_POLICY_NEVER, GTK_POLICY_ALWAYS); swin.border_width = 5; swin.height = 200; swin.width = 400; swin.add(text); box1.pack_start(swin, TRUE, TRUE, 0); recbut.signal("clicked", `record_data(@recbut, @iset, @but_db1, @but_db2, @but_db3, @text, @ent_yhs, @ent_str, @ent_dur, @ent_xhs, @ent_int, @ent_max, @ent_res, @but_int1, @but_int2, @but_int3, @but_int4, @qubut)); /* Callbacks for non-deadband buttons to send a query. */ buttons = list(but_int1, but_int2, but_int3, but_int4, qubut); with b in buttons do { b.signal("clicked", `reset_deadbands(@b, @iset, @but_db1, @but_db2, @but_db3, @text, @ent_yhs, @ent_str, @ent_dur, @ent_xhs, @ent_int, @ent_max, @ent_res, @but_int1, @but_int2, @but_int3, @but_int4, @recbut, @qubut)); } /* Callbacks for deadband buttons to prepare for and send a query. */ buttons = list(but_db1, but_db2, but_db3); with b in buttons do { b.signal("clicked", `plot_prep(@b, @iset, @but_db1, @but_db2, @but_db3, @text, @ent_yhs, @ent_str, @ent_dur, @ent_xhs, @ent_int, @ent_max, @ent_res, @but_int1, @but_int2, @but_int3, @but_int4, @recbut, @qubut)); } /* Display version info and start-up message.*/ ret = display_hs_info(text); history_win.show_all(); history_win.reposition(380, 45); history_win; } /******************************************************** * MAIN FUNCTION Code * ********************************************************/ /*-------------------------------------------------------------------- * Function: main * Returns: doesn't return * Description: Calls the common.g program_startup() function and loops. *------------------------------------------------------------------*/ function main() { program_startup("history", "historyq", #create_history(), "6"); atexit(#stop_processes()); /* Loop forever handling events. */ gtk_main (); }
Copyright © 1995-2010 by Cogent Real-Time Systems, Inc. All rights reserved.