/*-------------------------------------------------------------------- * File: phhistory.g * * Description: Demonstrates the Cascade Historian * * Classes: HistoryWindow * DeadbandType * * Functions and methods by category: * * Int & Query: InterpolatorSettings.assign_values * InterpolatorSettings.get_data * send_query * countdown * record_data * show_data * query_refresh * Deadbanding: reset_deadbands * db_prep_query * DeadbandType.constructor * db_options * create_dbtype_win * Plotting: make_CwGraph_points * make_graph * Window: HistoryWindow.constructor * PtText.set_sensitive * PtComboBox.set_sensitive * HistoryWindow.allow_entry_values * HistoryWindow.change_int * create_history * Main main *------------------------------------------------------------------*/ /* Get access to the library of common functions. */ require("lib/common.g"); require_lisp("Profile"); anyver_loadlibs(); /* Keep track of all child processes that this process has started.*/ Children := nil; /******************************************************** * INTERPOLATOR and QUERY Code * ********************************************************/ /*-------------------------------------------------------------------- * 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. *------------------------------------------------------------------*/ method InterpolatorSettings.assign_values(e1, e2, e3, e4, e5, e6) { .y_history = assign_history(.dbflag, .y_history, e1.text_string); .start = number(e2.text_string); .duration = number(e3.text_string); .x_history = assign_history(.dbflag, .x_history, e4.text_string); .interval = number(e5.text_string); .max_gap = number(e6.text_string); } /*-------------------------------------------------------------------- * Method: InterpolatorSettings.get_data * Returns: a list of x-data and y-data, as strings * Description: Sends a query to the Historian and receives the data. * Activated by the send_query function. *------------------------------------------------------------------*/ method InterpolatorSettings.get_data() { 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; hw.StartEnt.text_string = "0"; } if (undefined_p(.duration) || (!number_p(.duration)) || (.duration <= 0)) { .duration = 10; hw.DurEnt.text_string = "10"; } if (undefined_p(.interval) || (!number_p(.interval)) || (.interval < .01)) { .interval = .01; hw.IntEnt.text_string = "0.01"; } if ((tsk = locate_task("demohistdb", nil)) != nil) { intpl = self.set_interpolator(tsk); buf_length = caddr(send(tsk, `bufferIdLength(intpl))); if(!((.fn == "TimeSetup") || (.fn == "RelSetup"))) hw.NumPts.text_string = string(buf_length); alldata = list(); count = 0; 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 (outfile = open("/tmp/cogentdemo/hsoutput.dat", "w")) 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); } /*-------------------------------------------------------------------- * Function: send_query * Returns: t or nil * Description: Calls the necessary functions to send a query to the * Historian, and handles the data returned. It is activated * by the "Record" button popping out, or any radio button. *------------------------------------------------------------------*/ function send_query(iset, text, parent, ent1, ent2, ent3, ent4, ent5, ent6, button) { local fnholder, datalist, minmaxlist; if ((button == hw.NoIntBut || button == hw.PeriodBut || button == hw.RelBut || button == hw.FixRelBut || button == hw.DisplayBut || button == hw.RecBut)) iset.dbflag = "NONE"; iset.assign_values(ent1, ent2, ent3, ent4, ent5, ent6); 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(); 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(); show_data(text, iset, parent, button, datalist, minmaxlist); } /*-------------------------------------------------------------------- * Function: countdown * Returns: an integer * Description: Called by record_data to facilitate the time count-down. * This functionality had to be separated out from the callback. *------------------------------------------------------------------*/ function countdown(starttime) { starttime - clock(); } RECORD_TIME = 5; /*-------------------------------------------------------------------- * Function: record_data * Returns: an integer (timer number), or nil * Description: Records data for the specified time, then sends a query. *------------------------------------------------------------------*/ function record_data(but1, but2, iset, text, window, e1, e2, e3, e4, e5, e6) { if (but1.switched_on()) { local time = clock() + RECORD_TIME; text.text_string = string("Recording,please wait.\nSeconds remaining: ", RECORD_TIME); numtimer = every (1, `((@text).text_string = string(substr((@text).text_string, 0, 42), string((countdown(@time)))))); e3.text_string = string(RECORD_TIME + 1); iset.set_defaults(but1, e2); send_hs_command(but1, "enable", e1.text_string, nil); after(RECORD_TIME, `((@but1).flags = cons(Pt_SET, nil))); after((RECORD_TIME + .1), `(send_hs_command(@but1, "enable", (@e1).text_string, nil))); after((RECORD_TIME + .1), `(cancel(numtimer))); after((RECORD_TIME + .15), `(query_refresh(nil, nil))); after((RECORD_TIME + .25), `PtFlush()); } } /*-------------------------------------------------------------------- * Function: show_data * Returns: t or nil * Description: Shows interpolated query results from the Cascade Historian * in the text widget and plots the results in the CwGraph widget. *------------------------------------------------------------------*/ function show_data(txt_wgt, int_set, parent, button, datalist, minmaxlist) { local start_time, infile, line, string_list, line_ret; local x_is_time, x_min, x_max, y_min, y_max, x_list, y_list; local outstring = open_string (""); x_list = car(datalist); y_list = cadr(datalist); txt_wgt.text_string = ""; start_time = find_midnite(); if (int_set.fn == "NoInterpolator" || int_set.fn == "Periodic") { x_is_time = t; txt_wgt.text_string = "Query results: \n Time Y History\n"; } else { x_is_time = nil; txt_wgt.text_string = "Query results: \nX-hist / Y-hist\n"; } infile = open("/tmp/cogentdemo/hsoutput.dat", "r"); if (infile) { line = nil; while(line != _eof_) { line = read_line(infile); line_ret = ""; if (line != "Unexpected end of file") { if ((strstr(line,"#") != -1)) { writec (outstring, line); read_line(infile); read_line(infile); } else { string_list = string_split(line, " ", 2); if (x_is_time) { line_ret = string(number(car(string_list)) - start_time, " ", cadr(string_list),"\n"); } else { line_ret = string(number(car(string_list)), " ", cadr(string_list),"\n"); } writec (outstring, line_ret); } } } txt_wgt.text_string = string(txt_wgt.text_string, string_file_buffer(outstring)); 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; PtSetParentWidget(parent); make_graph(x_min, x_max, y_min, y_max, x_list, y_list, int_set.dbflag); } else txt_wgt.text_string = string("Sorry, there was an error retrieving\n", "data from the Cascade Historian."); close(infile); } } /*-------------------------------------------------------------------- * Function: query_refresh * Returns: t or nil * Description: Sets the interpolator, resets the deadband, and sends a * query. Used by callbacks on the four interpolator buttons, * the Update display button, and a timer on the Record button. *------------------------------------------------------------------*/ function query_refresh(button, title_string) { if (title_string) hw.change_int(button, title_string); reset_deadbands(); send_query(hw.int_set, hw.Text, hw.PtHist, hw.YHistEnt, hw.StartEnt, hw.DurEnt, hw.XHistEnt, hw.IntEnt, hw.GapEnt, button); } /******************************************************** * DEADBANDING Code * ********************************************************/ /*-------------------------------------------------------------------- * Function: reset_deadbands * Returns: an integer * Description: Clears all traces and sets the Full data set (no deadband) * option. Called when non-deadband buttons are activated. *------------------------------------------------------------------*/ function reset_deadbands() { hw.DBBut.flags = cons(Pt_SET, nil); hw.DBPBut.flags = cons(Pt_SET, nil); if(!undefined_p(GraphWidget)) { CwGraphClearTrace (GraphWidget, 0); CwGraphClearTrace (GraphWidget, 1); CwGraphClearTrace (GraphWidget, 2); } hw.DBNoneBut.flags = Pt_SET; } /*-------------------------------------------------------------------- * Function: db_prep_query * Returns: t or nil * Description: Sends a query when a Deadband button is toggled on, and * erases the corresponding graph trace when a Deadband button * is untoggled. *------------------------------------------------------------------*/ function db_prep_query(button) { if ((button.flags & Pt_SET) != 0) send_query(hw.int_set, hw.Text, hw.PtHist, hw.YHistEnt, hw.StartEnt, hw.DurEnt, hw.XHistEnt, hw.IntEnt, hw.GapEnt, button); else { if(!undefined_p(GraphWidget)) { if(button == hw.DBNoneBut) CwGraphClearTrace (GraphWidget, 0); else if(button == hw.DBBut) CwGraphClearTrace (GraphWidget, 1); else if(button == hw.DBPBut) CwGraphClearTrace (GraphWidget, 2); } } } /******************************************************** * DEADBAND TYPE WINDOW Code * ********************************************************/ /*-------------------------------------------------------------------- * Class: DeadbandType * Description: Creates the Deadband Type window using PhabAttachWidgets. *------------------------------------------------------------------*/ class DeadbandType { window; } PhabAttachWidgets (DeadbandType, anyos_assign("deadband_widgetfile")); /*-------------------------------------------------------------------- * Method: DeadbandType.constructor * Returns: the root widget of a widget hierarchy * Description: Instantiates a DeadbandType window. *------------------------------------------------------------------*/ method DeadbandType.constructor () { .window = PhabRoot(.PhabInstantiate (t)); } /*-------------------------------------------------------------------- * Function: db_options * Returns: a PtText widget * Description: Creates a PtText widget, gives it a position, and gives * it a callback to update the corresponding value in the * parameter array. *------------------------------------------------------------------*/ function db_options (p_array, index, col, row) { local option; local cols = [86, 148]; local rows = [55, 86, 127, 157]; option = new(PtText); option.SetDim(40, 20); option.fill_color = 0xffffee; option.border_width = 1; option.text_string = (string(p_array[index])); option.SetPos(cols[col], rows[row]); PtAttachCallback(option, Pt_CB_TEXT_CHANGED, `((@p_array)[@index] = number((@option).text_string))); option; } /*-------------------------------------------------------------------- * Function: create_dbtype_win * Returns: a Deadband Type window, or a destroyed instance * Description: Creates the Deadband Type window. *------------------------------------------------------------------*/ function create_dbtype_win (!point_list, button) { local db1, db2, pa1, pa2; if ((button.flags & Pt_SET) != 0) { if (undefined_p(db) || db.window == nil) { db = new (DeadbandType); db.DeadBandWindow.SetPos(150, 300); attach_msg(db.DeadBandWindow, "6.54", "6"); db1 = car(point_list); db2 = cadr(point_list); pa1 = array(db1.absolute, db1.percent, db1.timelimit, db1.countlimit); pa2 = array(db2.absolute, db2.percent, db2.timelimit, db2.countlimit); db_options(pa1, 0, 0, 0); db_options(pa1, 1, 0, 1); db_options(pa1, 2, 0, 2); db_options(pa1, 3, 0, 3); db_options(pa2, 0, 1, 0); db_options(pa2, 1, 1, 1); db_options(pa2, 2, 1, 2); db_options(pa2, 3, 1, 3); attach_msg(db.CancelBut, "6.55", "6.5"); attach_msg(db.OKBut, "6.56", "6.5"); PtAttachCallback(db.CancelBut, Pt_CB_ACTIVATE, `((@button).flags = cons(Pt_SET, nil))); PtAttachCallback(db.CancelBut, Pt_CB_ACTIVATE, `PtDestroyWidget((@db).window)); PtAttachCallback(db.OKBut, Pt_CB_ACTIVATE, `(@db1).set_parms((@db).OKBut, @pa1)); PtAttachCallback(db.OKBut, Pt_CB_ACTIVATE, `(@db2).set_parms((@db).OKBut, @pa2)); PtAttachCallback(db.OKBut, Pt_CB_ACTIVATE, `((@button).flags = cons(Pt_SET, nil))); PtAttachCallback(db.OKBut, Pt_CB_ACTIVATE, `PtDestroyWidget((@db).window)); PtAttachCallback(db.window, Pt_CB_DESTROYED, `((@button).flags = cons(Pt_SET, nil))); PtAttachCallback(db.window, Pt_CB_DESTROYED, `((@db).window = nil)); } if(db) PtRealizeWidget (db.window); db; } else PtDestroyWidget (db.window); } /******************************************************** * PLOTTING * ********************************************************/ /*-------------------------------------------------------------------- * Function: make_CwGraph_points * Returns: a list * Description: Applied to the x and y arguments of the CwGraphAddXYPoints() * function, which are lists. This function destructively * modifies those lists, adding extra values that, when plotted * by CwGraph, render as small, diamond-shaped points. The xval * parameter must be set to t for the x-coordinate, and to nil * for the y coordinate. *------------------------------------------------------------------*/ function make_CwGraph_points (ptlist, ptsize, xval) { parray = list_to_array(ptlist); i = 0; if(xval) { /* Add x-values to the trace. */ while (i < length(parray)) { insert(parray, i+1, parray[i] + (ptsize)); insert(parray, i+2, parray[i]); insert(parray, i+3, parray[i] - (ptsize)); insert(parray, i+4, parray[i]); insert(parray, i+5, parray[i] + (ptsize)); insert(parray, i+6, parray[i]); i = i + 7; } } else { /* Add y-values to the trace. */ while (i < length(parray)) { insert(parray, i+1, parray[i]); insert(parray, i+2, parray[i] - (ptsize)); insert(parray, i+3, parray[i]); insert(parray, i+4, parray[i] + (ptsize)); insert(parray, i+5, parray[i]); insert(parray, i+6, parray[i]); i = i + 7; } } ret = array_to_list(parray); } /*-------------------------------------------------------------------- * Function: make_graph * Returns: a CwGraph widget * Description: Sets up a CwGraph widget to plot the query results. *------------------------------------------------------------------*/ function make_graph (xmin, xmax, ymin, ymax, xlist, ylist, dband) { local grf; /* Set a size for the points created by make_CwGraph_points. */ local xdist = (xmax - xmin) * .007; local ydist = (ymax - ymin) * .007; if (undefined_p(GraphWidget) || !GraphWidget) { /* Make a new graph, if one doesn't already exist. */ PtSetParentWidget (hw.GraphPane); GraphWidget = new(CwGraph); GraphWidget.SetArea(0, 0, hw.GraphPane.dim.w, hw.GraphPane.dim.h); GraphWidget.fill_color = 0xffffe5; GraphWidget.bot_border_color = 0x000000; GraphWidget.graph_y_label_left = "Y history"; GraphWidget.graph_x_font = anyos_assign("graph_font"); GraphWidget.graph_y_font_left = anyos_assign("graph_font"); GraphWidget.ClearBit(#graph_flags, Cw_GRAPH_Y_AXIS_RIGHT); GraphWidget.ClearBit(#graph_flags, Cw_GRAPH_Y_AXIS_LABEL_RIGHT); GraphWidget.ClearBit(#graph_flags, Cw_GRAPH_Y_AXIS_TITLE_RIGHT); GraphWidget.ClearBit(#graph_flags, Cw_GRAPH_Y_MAJOR_TICK_RIGHT); GraphWidget.ClearBit(#graph_flags, Cw_GRAPH_Y_MINOR_TICK_RIGHT); PtAttachCallback (hw.GraphPane, Pt_CB_RESIZE, `GraphWidget.SetArea(0, 0, hw.GraphPane.dim.w, hw.GraphPane.dim.h)); } /* Change the tick size and scale of the existing graph for a new data plot. */ grf = GraphWidget; grf.graph_x_major_tick = (xmax - xmin) / 5; grf.graph_x_minor_tick = (xmax - xmin) / 25; grf.graph_y_major_tick_left = (ymax - ymin) / 5; grf.graph_y_minor_tick_left = (ymax - ymin) / 25; grf.graph_xmin = xmin; grf.graph_xmax = xmax; grf.graph_ymin_left = ymin; grf.graph_ymax_left = ymax; grf.graph_traces = 3; if (xmax > 1000) grf.graph_x_label = "Time (number of seconds after midnight)"; else grf.graph_x_label = "X history"; /* Assign trace limits and colors for the new data plot. */ CwGraphSetYLimits(grf, 0, ymin, ymax); CwGraphSetYLimits(grf, 1, ymin, ymax); CwGraphSetYLimits(grf, 2, ymin, ymax); CwGraphSetTraceColor(grf, 0, 0xdd00aa); CwGraphSetTraceColor(grf, 1, 0x0000aa); CwGraphSetTraceColor(grf, 2, 0x00aa00); /* Create the traces for the new data plot. */ if(dband == "NONE") CwGraphAddXYPoints(grf, 0, make_CwGraph_points(xlist, xdist, t), make_CwGraph_points(ylist, ydist, nil)); else if(dband == "DB") CwGraphAddXYPoints(grf, 1, make_CwGraph_points(xlist, xdist, t), make_CwGraph_points(ylist, ydist, nil)); else if(dband == "DBP") CwGraphAddXYPoints(grf, 2, make_CwGraph_points(xlist, xdist, t), make_CwGraph_points(ylist, ydist, nil)); PtRealizeWidget(grf); } /******************************************************** * HISTORY WINDOW Code * ********************************************************/ /*-------------------------------------------------------------------- * Class: HistoryWindow * Description: Creates the History window using PhabAttachWidgets. *------------------------------------------------------------------*/ class HistoryWindow { window; int_set; } PhabAttachWidgets (HistoryWindow, anyos_assign("history_widgetfile")); /*-------------------------------------------------------------------- * Method: HistoryWindow.constructor * Returns: the root widget of a widget hierarchy * Description: Instantiates a HistoryWindow. *------------------------------------------------------------------*/ method HistoryWindow.constructor () { .window = PhabRoot(.PhabInstantiate (t)); } /*-------------------------------------------------------------------- * Method: PtText.set_sensitive * Returns: an integer * Description: Changes the sensitivity of a PtText widget. Called by * HistoryWindow.allow_entry_values. *------------------------------------------------------------------*/ method PtText.set_sensitive (val) { if (val != 0) { self.text_flags = Pt_EDITABLE; self.fill_color = 0xffffe5; } else { self.text_flags = cons(Pt_EDITABLE, nil); self.fill_color = 0xd0d0d0; } } /*-------------------------------------------------------------------- * Method: PtComboBox.set_sensitive * Returns: an integer * Description: Changes the fill color of a PtComboBox widget. Called * by HistoryWindow.allow_entry_values. *------------------------------------------------------------------*/ method PtComboBox.set_sensitive (val) { if (val != 0) { self.list_flags = cons (Pt_LIST_INACTIVE, nil); self.fill_color = 0xffffe5; } else { self.list_flags = Pt_LIST_INACTIVE; self.fill_color = 0xd0d0d0; } } /*-------------------------------------------------------------------- * Method: HistoryWindow.allow_entry_values * Returns: t or nil * Description: Sets the three specialized parameter entry widgets sensitive * or non-sensitive. Called by HistoryWindow.change_int(). *------------------------------------------------------------------*/ method HistoryWindow.allow_entry_values(e1, e2, e3) { .XHistEnt.set_sensitive(e1); .IntEnt.set_sensitive(e2); .GapEnt.set_sensitive(e3); } /*-------------------------------------------------------------------- * Method: HistoryWindow.change_int * Returns: t * Description: Responding to a click on a "Choose an Interpolator" radio * button, this method calls the allow_entry_values() function * on the active button. *------------------------------------------------------------------*/ method HistoryWindow.change_int(button, str) { if (button.switched_on()) { .int_set.fn = str; switch (str) { case "NoInterpolator": .allow_entry_values(0, 0, 0); case "Periodic": .allow_entry_values(0, 1, 1); case "Relative": .allow_entry_values(1, 0, 0); case "FixedRelative": .allow_entry_values(1, 1, 0); } } /* To allow for a slow processor */ usleep(10000); } /*-------------------------------------------------------------------- * Function: create_history * Returns: doesn't return * Description: Creates the History window. *------------------------------------------------------------------*/ function create_history () { local buttons, version_string; local hw = new (HistoryWindow); hw.GraphPane.anchor_flags = Pt_LEFT_ANCHORED_LEFT | Pt_RIGHT_ANCHORED_RIGHT | Pt_BOTTOM_ANCHORED_BOTTOM | Pt_TOP_ANCHORED_TOP; hw.int_set = new(InterpolatorSettings); hw.change_int(hw.NoIntBut, "NoInterpolator"); hw.SecsEnt.numeric_value = RECORD_TIME; hw.YHistEnt.text_string = hw.int_set.y_history; hw.StartEnt.text_string = hw.int_set.start; hw.DurEnt.text_string = hw.int_set.duration; hw.XHistEnt.text_string = hw.int_set.x_history; hw.IntEnt.text_string = hw.int_set.interval; hw.GapEnt.text_string = hw.int_set.max_gap; hw.YHistEnt.items = array ("MV_001", "PV_001"); hw.XHistEnt.items = array ("PV_001", "MV_001"); /*Attach message callbacks to buttons and entry widgets.*/ attach_msg(hw.PtHist, "6", "1"); attach_msg(hw.RecBut, "6.2", "6"); attach_msg(hw.DisplayBut, "6.3", "6"); attach_msg(hw.NoIntBut, "6.31", "6"); attach_msg(hw.PeriodBut, "6.32", "6"); attach_msg(hw.RelBut, "6.33", "6"); attach_msg(hw.FixRelBut, "6.34", "6"); attach_msg(hw.YHistEnt, "6.35", "6"); attach_msg(hw.StartEnt, "6.36", "6"); attach_msg(hw.DurEnt, "6.37", "6"); attach_msg(hw.XHistEnt, "6.35", "6"); attach_msg(hw.IntEnt, "6.38", "6"); attach_msg(hw.GapEnt, "6.39", "6"); attach_msg(hw.SetupBut, "6.5", "6"); attach_msg(hw.DBNoneBut, "6.51", "6"); attach_msg(hw.DBBut, "6.52", "6"); attach_msg(hw.DBPBut, "6.53", "6"); /* Display version info and start-up message.*/ display_hs_info(hw.Text); /* Callback for the PtComboBox entry, number of seconds to record.*/ PtAttachCallback(hw.SecsEnt, Pt_CB_NUMERIC_CHANGED, `(RECORD_TIME = (@hw).SecsEnt.numeric_value)); /* Callbacks for non-deadband buttons to send a query.*/ PtAttachCallback(hw.NoIntBut, Pt_CB_ACTIVATE, `query_refresh(@hw.NoIntBut, "NoInterpolator")); PtAttachCallback(hw.PeriodBut, Pt_CB_ACTIVATE, `query_refresh(@hw.PeriodBut, "Periodic")); PtAttachCallback(hw.RelBut, Pt_CB_ACTIVATE, `query_refresh(@hw.RelBut, "Relative")); PtAttachCallback(hw.FixRelBut, Pt_CB_ACTIVATE, `query_refresh(@hw.FixRelBut, "FixedRelative")); PtAttachCallback(hw.DisplayBut, Pt_CB_ACTIVATE, `query_refresh(@hw.DisplayBut, nil)); /* A callback to record data, which includes sending a query. */ PtAttachCallback(hw.RecBut, Pt_CB_ACTIVATE, `(record_data((@hw).RecBut, (@hw).DisplayBut, (@hw).int_set, (@hw).Text, (@hw).PtHist, (@hw).YHistEnt, (@hw).StartEnt, (@hw).DurEnt, (@hw).XHistEnt, (@hw).IntEnt, (@hw).GapEnt))); /* Callbacks to set the deadband flag.*/ PtAttachCallback(hw.DBNoneBut, Pt_CB_ACTIVATE, `((@hw).int_set.dbflag = "NONE")); PtAttachCallback(hw.DBBut, Pt_CB_ACTIVATE, `((@hw).int_set.dbflag = "DB")); PtAttachCallback(hw.DBPBut, Pt_CB_ACTIVATE, `((@hw).int_set.dbflag = "DBP")); /* A callback for deadband buttons to prepare for and send a query.*/ buttons = list(hw.DBNoneBut, hw.DBBut, hw.DBPBut); with b in buttons do { PtAttachCallback(b, Pt_CB_ACTIVATE, `db_prep_query(@b)); } /* Deadband setup.*/ 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); PtAttachCallback(hw.SetupBut, Pt_CB_ACTIVATE, `create_dbtype_win(@db_list, (@hw).SetupBut)); PtAttachCallback(hw.ExitBut, Pt_CB_ACTIVATE, #exit_program(-1)); hw.PtHist.SetPos(320, 250); PtRealizeWidget (hw.window); send_message("nsnames"); hw; /* Loop forever handling events. */ while(t) next_event(); } /******************************************************** * MAIN FUNCTION Code * ********************************************************/ /*-------------------------------------------------------------------- * Function: main * Returns: doesn't return * Description: Calls the common.g program_startup() function. *------------------------------------------------------------------*/ function main() { program_startup("history", "historyq", #create_history(), "6"); }
Copyright © 1995-2010 by Cogent Real-Time Systems, Inc. All rights reserved.