/*--------------------------------------------------------------------
 * File:        phmonitor.g
 *
 * Description: Monitors and controls the PID Emulator.
 *
 * Functions:
 *                toggle_sym
 *                slider_callback
 *                accumulate_trends
 *                update_trends
 *                create_monitor
 *                main
 *------------------------------------------------------------------*/

/*--------------------------------------------------------------------
 * Function:    toggle_sym
 * Returns:     t or nil
 * Description: Toggles a database point between 0 and 1 when a button
 *              is pressed.
 *------------------------------------------------------------------*/
function toggle_sym(sym)
{
  set (sym, eval(sym) == 0 ? 1 : 0);
  write_point (sym, eval(sym));
}

/*--------------------------------------------------------------------
 * Function:    slider_callback
 * Returns:     t or nil
 * Description: Attaches a callback and adds and exception function to
 *              a slider widget.  The callback writes a value to the
 *              datahub point specified, and the exception function
 *              assigns the value of the datahub point to the slider
 *              widget whenever the value of the point changes in the
 *              datahub.
 *------------------------------------------------------------------*/
function slider_callback(sld, !pnt)
{
  PtAttachCallback(sld, Pt_CB_SLIDER_MOVE,
                   `write_point(@pnt, ((@eval(sld)).gauge_value)));
  add_exception_function(eval(pnt),
                         `(@eval(sld)).gauge_value = (@eval(pnt)));
}
  
/* Assign each DataHub point a property value, which in this case is an
 * array.  These arrays will be used to hold a short history of each point,
 * allowing them to be plotted by the trend widget.
 */
setprop (#SP_001, #tdata, make_array (0));
setprop (#MV_001, #tdata, make_array (0));
setprop (#PV_001, #tdata, make_array (0));

/*--------------------------------------------------------------------
 * Function:    accumulate_trends
 * Returns:     t or nil
 * Description: Adds new data to property value arrays.  These arrays
 *              are property values for the variables that correspond
 *              to the DataHub points, and are used to update the trend
 *              widget.
 *------------------------------------------------------------------*/
function accumulate_trends (syms...)
{
  local data;
        with sym in syms do
        {
                data = getprop (sym, #tdata);
                data[length(data)] = eval (sym);
        }
}

/*--------------------------------------------------------------------
 * Function:    update_trends
 * Returns:     t or nil
 * Description: Assigns the most recent arrays to the trend widget.
 *------------------------------------------------------------------*/
function update_trends (widget, syms...)
{
  local        tarray = make_array (length(syms)), i = 0, sym;

  with sym in syms do
    tarray[i++] = getprop (sym, #tdata);
  widget.put_data(tarray);
  with sym in syms do
    shorten_array (getprop (sym, #tdata), 0);
}

/*--------------------------------------------------------------------
 * Function:    create_monitor
 * Returns:     doesnt' return
 * Description: Creates the Monitor window.
 *------------------------------------------------------------------*/
function create_monitor ()
{
  local wfile, window, monitor_win, slidesp, progmv, progpv;
  local slideauto, slidedp, numkp, numki, numkd, numprop, numint;
  local butam, butgood, butpoor, butosc, butout, butx;
  
  wfile = PhabReadWidgetFile(anyos_assign("monitor_widgetfile"));
  window = PhabCreateWidgets(wfile, nil, nil);
  monitor_win = PhabLookupWidget(window, #Ptmonitor, nil);
  slidesp = PhabLookupWidget(window, #PtSliderSP, nil);
  slideclr = PhabLookupWidget(window, #RtProgressColor, nil);

  butam = PhabLookupWidget(window, #PtOnOffButtonAutomode, nil);
  numfreq = PhabLookupWidget(window, #PtNum1, nil);
  numkp = PhabLookupWidget(window, #PtNum2, nil);
  numki = PhabLookupWidget(window, #PtNum3, nil);
  numkd = PhabLookupWidget(window, #PtNum4, nil);
  numprop = PhabLookupWidget(window, #PtNum5, nil);
  numint = PhabLookupWidget(window, #PtNum6, nil);
  
  butgood = PhabLookupWidget(window, #PtToggleGood, nil);
  butpoor = PhabLookupWidget(window, #PtTogglePoor, nil);
  butosc = PhabLookupWidget(window, #PtToggleOscillating, nil);
  butout = PhabLookupWidget(window, #PtToggleOOC, nil);
  labprop = PhabLookupWidget(window, #PtLabelPropVal, nil);
  progmv = PhabLookupWidget(window, #ProgressMV, nil);
  progpv = PhabLookupWidget(window, #ProgressPV, nil);
  trend1 = PhabLookupWidget(window, #Trend1, nil);

  slidesp.gauge_value = read_point(#SP_001);
  slideclr.gauge_value = read_point(#SP_001);
  progmv.gauge_value = read_point(#MV_001);
  progpv.gauge_value = read_point(#PV_001);
  butam.onoff_state = read_point(#AUTO_001);

  numfreq.numeric_value = read_point(#FREQ_001);

  anyver_numeric_assign(numkp, numki, numkd, numprop, numint);

  add_exception_function(#AUTO_001, `(@butam).onoff_state = AUTO_001);
  add_exception_function(#SP_001, `(@slideclr).gauge_value = SP_001);
  add_echo_function(#SP_001, `(@slideclr).gauge_value = SP_001);
  add_exception_function(#MV_001, `(@progmv).gauge_value = MV_001);
  add_exception_function(#PV_001, `(@progpv).gauge_value = PV_001);

  slider_callback (slidesp, #SP_001);

  attach_msg(monitor_win, "3", "1");
  attach_msg(slidesp, "3.1a", "3");
  attach_msg(butam, "3.1", "3");
  attach_msg(numfreq, "3.2", "3");
  attach_msg(numkp, "3.3", "3");
  attach_msg(numki, "3.4", "3");
  attach_msg(numkd, "3.5", "3");
  attach_msg(numprop, "3.6", "3");
  attach_msg(numint, "3.7", "3");
  attach_msg(butgood, "3.8", "3");
  attach_msg(butpoor, "3.9", "3");
  attach_msg(butosc, "3.10", "3");
  attach_msg(butout, "3.11", "3");
  
  anyver_num_callback (numfreq, #FREQ_001);
  anyver_num_callback (numkp, #PID1_Kp);
  anyver_num_callback (numki, #PID1_Ki);
  anyver_num_callback (numkd, #PID1_Kd);
  anyver_num_callback (numprop, #PROP_001);
  anyver_num_callback (numint, #INT_001);

  PtAttachCallback(butgood, Pt_CB_ACTIVATE,
                   `anyos_change_settings(t, @numfreq, 4, @numkp, .05,
                                          @numki, .45, @numkd, .05,
                                          @numprop, .7, @numint, 1.0,
                                          3.8, @butam));

  PtAttachCallback(butpoor, Pt_CB_ACTIVATE,
                   `anyos_change_settings(t, @numfreq, 10, @numkp, .05,
                                          @numki, .70, @numkd, .05,
                                          @numprop, .7, @numint, 5.0,
                                          3.8, @butam));

  PtAttachCallback(butosc, Pt_CB_ACTIVATE,
                   `anyos_change_settings(nil, @numfreq, 10, @numkp, .05,
                                          @numki, 1.37, @numkd, .05,
                                          @numprop, .7, @numint, .54,
                                          3.8, @butam));

  PtAttachCallback(butout, Pt_CB_ACTIVATE,
                   `anyos_change_settings(nil, @numfreq, 10, @numkp, .05,
                                          @numki, .45, @numkd, 1.00,
                                          @numprop, .7, @numint, .54,
                                          3.8, @butam));
  
  PtAttachCallback(butam, Pt_CB_ONOFF_NEW_VALUE, `toggle_sym(#AUTO_001));
  
  butx = PhabLookupWidget(window, #Ptxbut, nil);
  PtAttachCallback(butx, Pt_CB_ACTIVATE, #exit_program(-1));

  /* Set up the trend widget.  We must set the trend resources in the
   * order below to ensure that the trend widget knows what to do with
   * the line colors.  We want 3 traces, in the same colors that the
   * designer set when creating the slider and progress bars in the
   * Photon App Builder.
   */
  trend1.trend_count = 3;
  trend1.trend_color_list = array (slideclr.progress_bar_color,
                                   progmv.progress_bar_color,
                                   progpv.progress_bar_color);
  trend1.trend_attributes = array (1, 2, 3);
  
  /* Animate trends every tenth of a second.  The trend data arrays are
   * stored in the property lists of the associated database variables.
   * We can accumulate trend data faster than we display it by changing
   * the rates of accumulation and update.  It does not make sense to display
   * trend data faster than about 27Hz, because the eye cannot distinguish
   * anything beyond that from smooth motion.  In reality, 10Hz is plenty.
   */
  every (0.1, #accumulate_trends (#SP_001, #MV_001, #PV_001));
  every (0.1, #update_trends (trend1, #SP_001, #MV_001, #PV_001));
  
  monitor_win.SetPos(360, 10);
    PtRealizeWidget(monitor_win);
  send_message("nsnames");
  
//  PtMainLoop();
  while(t) next_event();
  
}

/*--------------------------------------------------------------------
 * Function:    main
 * Returns:     
 * Description: 
 *------------------------------------------------------------------*/
function main()
{
  /* Get access to the library of common functions. */
  require("lib/common.g");

  program_startup("monitor", "monq", #create_monitor(), "3");
}


