dpConnect()

Calls a callback function whenever the passed data point values/attributes change.

Synopsis

int dpConnect([class object,] string|function_ptr work, [bool answer,] string dp1 [, string dp2 ...] | dyn_string dp_list);

Parameters

Parameter Meaning
object An object of a Control++ class.
work

Name of the callback function ("work function") that is called when data point values change.

Or

The name of a function pointer to the work function (callback function).

answer Specifies if the callback function should be executed the first time already when the dpConnect() is called or first every time a value changes. The default value is TRUE (first callback is executed when the dpConnect() is called)

dpe1, dpe2, ...

|

dp_list

Data point attributes or a data point list to be registered. If you pass a data point list, the DPEs and values in the work function are passed as a dyn_string dp-list and dyn_<type> Values. See examples below.

CAUTION: Do not use data points of different systems! The function dpConnect() only works for one system. If dpConnect() is used for at least two systems, it does not work and the following error message is shown: WCCOAui (1), 2006.09.26 14:11:19.266, PARAM,SEVERE, 175, this request cannot address more than one system, DP: dist_789:ExampleDP_Arg1.:_original.._value WCCOAui (1), 2006.09.26 14:11:19.266, CTRL, WARNING, 76, Invalid argument in function
CAUTION: If a config that is queried via a connect function, is changed afterwards via the PARA module, the connect function will not work anymore. Re-select the config via the script editor.

Return Value

dpConnect() returns 0, in the event of a failure returns -1.

Error

Use the function getLastError() to retrieve errors. The function throwError() can be used to write an error message to the PVSS_II.log log file.

Note that when using the function getLastError(), use it directly after the function call of the dpConnect() as shown in the example below since the function getLastError returns the errors of the last function call.

main()
{
  dyn_errClass err;
  int i;
  i = dpConnect("add", "System1:ExampleDP_Arg1.", "System1:ExampleDP_Arg2.");
  err = getLastError();
  if(dynlen(err) > 0)
  {
    DebugN("An error occurred:", err);
    int errC = throwError(err); //write an error message to the PVSS_II.log log file
  }
  else
    DebugN("Function executed:", i);
}

add(string dp1, float a, string dp2, float b)
{
  dpSet("System1:ExampleDP_Result.", a + b);
}

Description

If values of the data point attributes dpe1, dpe2 ... change a callback function is called (the work() function is registered and called when values are changed). This callback function (is also called work function) is executed spontaneous each time when some of the registered data point values /attributes (provided that all contained in the function call are passed) changes. An arbitrary number of DP attributes can be registered except some attributes of the "_alert_hdl" config. These attributes can be queried via the function alertConnect() (see the _alert_hdl table). Only the attributes "_prior", "_act_state_color", "_act_state_fore_color", "_act_state_font_style", "_text" and "panel" of the table are available for dpConnect().

The DP attribute _status calls the callback function only then, when the status has changed. The behavior differs to the _value attribute, where the callback function is called for each value input (regardless of whether the value has changed or not).

When dpConnect() is called the callback function is executed immediately once with the current data point values if the argument answer was not set to "false";. If a specified attribute is modified while the callback function is executed, the next callback function call is executed first when the preceding call has been completed. The registration (function is called when values are changed) is valid until the function dpDisconnect() stops the registration, the manager that executes is stopped or the panel is closed in the UI.

Note:

The registered callback function must contain the following parameters:

void work(string dpe1, <type1> var1 [, string dpe2, <type2> var2 ...])

In addition to the value (data type of the attribute) also the identifier of the data point attribute is returned as a string for each registered data point attribute.

The order of these pairs (identifier + value) has to correspond to the registration via dpConnect().

The name of the callback function can of course be assigned freely. Also the declaration within a library is possible.

When the function names are same the local definition in a script wins against the global panel and manager definitions. Via this hierarchy it is possible to use the same function name more often in the same process image (panel) in the different event scripts of the graphics objects. The local function definition wins.

If the callback function of the dpConnect function contains default parameters, also the dpConnect call must contain these parameters. Otherwise the error message "WCCOAui (1), 2007.01.15 17:49:18.384, IMPL, WARNING, 54, Unexpected state, CtrlScript, dpVC, too less items in DpHLGroup, callback function myWork not started" is shown.

If the registered attributes are multilingual text elements these are returned to the control instance (Control manager, UI) only in the current language.

Usage

The function dpConnect() is used above all for displaying or processing current values and states. If, for example, a value should be shown in a process image the registration for the value changes in a dpConnect() is made within the Initialize(). See also GEDI and Control scripts. The associated callback function is executed each time a value changes. The function updates the value representation in the process image.

If a callback function is not yet completed when an event occurs again the event is added to a queue until all previous function calls have been executed. If the frequency of the events is higher than as these can be processed, the queue of pending events and with it the memory consumption of the CTRL Manager or UI Manager keeps on growing. If a callback function has more events to process than the number set in the config file, the following warning (or another error output) is displayed in the Log Viewer:

"Function has ... pending runs-> DISCARDING"

The default maximum amount of the queue (events that have to be executed) is 200. As soon as this amount is reached the system discards all calls except the youngest and processes only the last value. The queue can grow again. The maximum value can be set selective via the config entry [general] ctrlMaxPendings in the UI and CTRL Manager sections.

If the config + attribute are left out when the data point elements are registered (see addressing) the system handles this as if the online value (_online.._value) would be specified.

Normally a dpConnect() with several registered elements returns a callback function call for each value change of an attribute. Thereby all "registered" values are passed to the CB function. If a number of value and attribute changes are sent in a single dpSet() the registration returns only a single common callback function call. A single callback function call is also returned for common registrations for attributes that belong together (like value, time stamp and status (quality) of a single data point element). See the last example.

Calculate C = A+B. The name of the callback function is add(). The parameters passed are"Pipe_A.flow:_online.._value" and "Pipe_B.flow:_online.._value". The data point Pipe_C.flow is set via a dpSet() command.

main()
{
  int i;
  i = dpConnect("add", "Pipe_A.flow","Pipe_B.flow");
  DebugN("Function executed:", i);
}

add(string dp1, float a, string dp2, float b)
{
  dpSet("Pipe_C.flow", a + b);
}

In the last example the attribute identifiers _online.._value and _original.._value were left out (for example, "Pipe_B.flow:_online.._value"). If only the data point element is named the original value is automatically used for "set" operations and the online value for "read" operations.

A measured value that is displayed in the system via the data point element Drive014.speed should be visualized in a process image (panel). The value (display) should be formatted (decimal places) and the unit should be specified in a text field.

Solution

Add the following program to the Initialize script of the text field. The function dpValToString() formats the value according to the number format and engineer unit specified for the data point element. The option specified as comment would display the number without formatting and with an arbitrary number of decimal places in the text field.

main()
{
  int i;
  i = dpConnect("displayValue","Drive014.speed");
  DebugN("Function executed:", i);
}

displayValue(string dpe, float speed)
{
  this.text = dpValToString(dpe, speed, true);
}

Information about a drive should be shown in a device symbol. The data point type of the drive looks as follows:

Figure 1. Figure: Device symbol

The symbol should visualize the information On/Off (Drive014.speed > 0) and operational mode Hand Drive014.manual= TRUE). Furthermore the current message status color of alert handling on Drive014.fault should be shown in case of errors. Also the quality information (status: invalid, bad) of the actual .speed value is analyzed and displayed in the symbol.

Solution

Write the following program in the Initialize script of the drive symbol. The dpConnect() within the if query is executed first anyway. If the dpConnect cannot be executed (for example, configuration error: the data points do not exist at all) the symbol shows this via a color change (named color "_dpdoesnotexist"). This way erroneous and incomplete configurations are detected immediately.

dpConnect() executes two registrations for two online values, a virtual quality bit and the (in each case) valid color of the current alert range of a data point element. After evaluating which combination of On/Off is available at which status (quality information) all necessary graphics attributes are set at once. This prevents the flickering of display also when there is a large number of objects.

main()
{
  if (dpConnect("visualizeDrive", "Drive014.speed", "Drive014.speed:_online.._bad", "Drive014.fault:_alert_hdl.._act_state_color", /* color of the alert handling */ "Drive014.manual") == -1)
    setValue("","backCol","_dpdoesnotexist");
    // this.backCol = "_dpedoesnotexist";
}
 
visualizeDrive( string dpe1, float speed, string dpe2, bool invalid, string dpe3, string alertCol, string dpe4, bool manmode)
{
  string symbolCol;
  if (speed > 0)
  {
    if (invalid)
      symbolCol = "STD_device_on_invalid"; /* create this color using the color editor or use some of the default colors like "STD_value_invalid" */
    else
      symbolCol = "STD_device_on"; //default color
  }
  else
  {
    if (invalid)
      symbolCol = "STD_device_off_invalid"; /* create this color using the color editor or use some of the default colors like "STD_value_invalid" */
    else
      symbolCol = "STD_device_off";
  }
  
  setMultiValue("DriveSymbol", "backCol", symbolCol, "DriveSymbol", "foreCol", alertCol, "InvalidIndicator", "visible", invalid, "ManualIndicator", "visible", manmode);
}
  • In the last example the data point identifier was specified absolute. If you would like to use the symbol more than once you would of course use $ parameters (a real reference).
  • A function iRet =dpConnect("me_Rahmen_Messung_setBackColor", $dpe+".Messwert.value:_alert_hdl.._act_state_color", $dpe+".Properties.Typ:_original.._value"); is not called if there is no alert handling available on the data point. The value 0 (function executed successfully) is, however, returned. In case of a redundancy switch the function is called but the return value of _act_state_color is an empty string. Additionally, the return value for Properties.Typ is 0 and not the value from the database.
  • Normally it is never necessary to execute a dpGet for single elements in the callback function ("work function") since the registration returns these when values change. You may, however, have to access the description texts, format and unit within the function. Since this a quick memory access the processing speed is not affected.

All set point changes of the drive, that was shown in the last example should be logged in the LogViewer during a test run. In addition to the actual value the time stamp, the user that changed the value (ID and user name) and the quality information "INVALID"; have to be printed.

Solution

The registration on the necessary attributes of the data point element can be executed via a single dpConnect(). Although also , for example, the source time (_stime) and maybe the user change when the value changes the callback function logSP is called only once in this case (each value change generates only a single row, see result). The attributes passed via the parameters of the callback function are formatted before printed via DebugN(). The last row of the command DebugN checks (via a condition operator) if the invalid attribute is set. The DebugN is only executed if the invalid attribute is set.

main()
{
 dpConnect("logSP", "Drive014.cmd.setpoint",
"Drive014.cmd.setpoint:_online.._stime", "Drive014.cmd.setpoint:_online.._user", "Drive014.cmd.setpoint:_online.._manager", "Drive014.cmd.setpoint:_online.._invalid");
}
logSP( string dpe1, float setpoint,
 string dpe2, time stime,
 string dpe3, int uid,
 string dpe4, int manNum,
 string dpe5, bool invalid)
{
 string valStr, managerString;
 sprintf(valStr, "%5.2f", setpoint); // formatting of the value
 convManIntToName(manNum, managerString); /* extraction of the manager identifier*/
 DebugN( formatTime("%c", stime, ",%03d") + " | " +
 "SP: " + valStr + " | " +
 getUserName(uid) + " " +
 "on " + managerString + " | " +
 (invalid?"Invalid!":""));
 } 

Result

["04.11.2003 16:56:48,629 | SP: 1250.00 | root on UI -num 2 | "]
["04.11.2003 16:57:08,638 | SP: 1500.00 | John Q. Public on UI -num 1 | "]
["04.11.2003 16:57:13,024 | SP: 1520.00 | John Q. Public on UI -num 1 | "]
["04.11.2003 16:57:21,556 | SP: 1200.00 | root on UI -num 2 | "]
["04.11.2003 16:57:34,545 | SP: 1190.00 | John Q. Public on UI -num 1 | "]
["04.11.2003 16:57:58,479 | SP: -5.00 | root on UI -num 2 | Invalid!"]

Examples for correct and incorrect addressing of data point elements

ret = dpConnect("ReportEvent1", TRUE, "TestReport"); //this call reports ret=0 which is success, but the callback fails
ret = dpConnect("ReportEvent1", TRUE, "TestReport."); //this call also reports ret=0 and the callback works
ret = dpConnect("ReportEvent1", TRUE, "TestReport:_online.._value"); //this call fails ret=-1 and the script "dies"
ret = dpConnect("ReportEvent1", TRUE, "TestReport.:_online.._value"); //this call also works fine and the callback works

Information about dpConnects()

Information about dpConnects can be queried using the attributes _dpids, _manids and _mancount.

  • _dpIds = which data point elements belong to this connect group
  • _manids = which managers query this data point element
  • _mancount = how oft does a manager query this data point element

The following example shows you how to use these attributes:

Several dpConnects are executed and the attributes are queried.

main()
{
  dpConnect("add", "testDp1.:_online.._value", "testDp2.:_online.._value");
  DebugN("zweites Mal dpconnect");
  dpConnect("add", "ExampleDP_Arg1.:_online.._value", "ExampleDP_Arg2.:_online.._value");
}
add(string dp1, float a, string dp2, float b)
{
  dpSet("testDp3.:_original.._value", a + b);
}

Query the information:

main()
{
  dyn_dyn_string ds;
  dyn_dyn_string as;
  dyn_dyn_int dui;
  dyn_dyn_int hui;
  dyn_dyn_int di;
  dyn_dyn_int fi;
// Which managers query this data point element?

dpGet( "ExampleDP_Arg2.:_connect.._manids", dui,
// Which data point element belongs to this Connect group?

"ExampleDP_Arg2.:_connect.._dpids", ds,
//How oft does a manager query this data point element?

"ExampleDP_Arg1.:_connect.._mancount", di,

                "testDp1.:_connect.._dpids", as,
                "testDp1.:_connect.._manids", hui,
                "testDp1.:_connect.._mancount", fi);

  DebugN("ExampleDP_Arg1.:_connect.._dpids", ds,
         "ExampleDP_Arg2.:_connect.._manids", dui,
         "ExampleDP_Arg1.:_connect.._mancount", di);
  DebugN("testDp1.:_connect.._dpids", as,
         "testDp1.:_connect.._dpids", hui,
         "testDp1.:_connect.._mancount", fi);
 }

This example uses a Control++ class and an object of a Control++ class to output values that are set for specific data points via the PARA module. The scope lib of a panel contains the class DpCon and the work function that outputs the values set for specific data points via PARA. The data points are specified via dpConnect().

ScopeLib of a panel:

class DpCon
{
  public void work(dyn_string dp, dyn_float value)
  {
    DebugTN(value);
  }
};

DpCon dpCon;

Below you see a code for e.g. a button. In the code dpConnect uses the object dpCon of the class DpCon and the function pointer dpCon.work that points to the work (callback) function. dpConnect connects to the data points ExampleDP_Arg1. and ExampleDP_Arg2. The values set to the data points are output via the class DpCon and the DebugTN() of the work function.

void main(mapping event)
{
  dyn_string dpList = makeDynString("ExampleDP_Arg1.", "ExampleDP_Arg2.");
  dpConnect(dpCon, dpCon.work, TRUE, dpList);
}

The example outputs the values set to the data points ExampleDP_Arg1. and ExampleDP_Arg2. via PARA, e.g.:

WCCOAui1:2017.07.11 15:43:11.695[dyn_float 2 items
WCCOAui1: 1: 80
WCCOAui1: 2: 100
WCCOAui1:]

Assignment

Data point function, Waiting Control function

Availability

UI, CTRL