MakeArray.g

MakeArray.g — creates an array point from individual points.

Code

[Note]

The code for this and other example scripts can be found in the DataHub distribution archive, typically at one of these locations:

    C:\Program Files\Cogent\OPC DataHub\scripts\

    C:\Program Files\Cogent\Cascade DataHub\scripts\

Please refer to Section 3.1, “How to Run a Script” for more information on using scripts.

/* This script creates an output array point from an input set of individual 
 * points.  The array can be any reasonable length, though the algorithm is
 * not efficient for large arrays whose constituent points change quickly.
 * 
 * The only part of the code that you need to alter to create your own arrays
 * is the MakeArray.constructor method.
 *
 * If a change is made to any individual point, the array will be updated 
 * immediately.
 *
 * If a change is made to the array point, the change will not affect the
 * individual points that make up the array.  
 */

require ("Application");

/* Applications share the execution thread and the global name
 * space, so we create a class that contains all of the functions
 * and variables for the application.  This does two things:
 *   1) creates a private name space for the application, and
 *   2) allows you to re-load the application to create either
 *      a new unique instance or multiple instances without
 *      damaging an existing running instance.
 */
class MakeArray Application
{
}

/* Ensure that a point exists in the DataHub data store.  We do this because the
 * startup order of the DataHub vs. the data source is not necessarily predictable.
 * By creating the point now, we are sure that it exists even if the data source
 * starts later.
 */
method MakeArray.CreatePoint(pointname, type?=nil)
{
    datahub_command(format("(create \"%s\" 1)", pointname), 1);
    if (type)
        datahub_command(format("(set_canonical \"%s\" \"%s\" 1)", pointname, type), 1);
}

/* Write the array based on the input point list.  There are more efficient ways to
 * do this if the array is large or the data updates very frequently.  It may also be
 * reasonable to do it on a timer rather than every time any constituent point changes
 */
method MakeArray.EmitArray(arraypoint, inputpoints)
{
    local	val = make_array(0), i=0, tmp;
    with point in inputpoints do
    {
        val[i++] = undefined_p(tmp = eval(symbol(point))) ? 0 : number(tmp);
    }
    set (symbol(arraypoint), val);
}

/* This is a convenient function that declares an array point to create from a set of
 * input points.  You can create as many of these array points as you need, using any
 * number of input points.  Just put all of the input points into the argument list of
 * the call (see the call in the constructor below).
 * The arraytype is a VARIANT array type: I1, I2, I4, R4, R8, BSTR, UI1, UI2, UI4 
 * followed by a space and the word "array".  E.g., "R8 array" or "BSTR array".AddCustomMenuItem
 * BSTR means "string".
 */
method MakeArray.DeclareArray(arraypoint, arraytype, inputpoints...)
{
    .CreatePoint (arraypoint, arraytype);
    with point in inputpoints do
    {
        .CreatePoint(point);
        .OnChange(symbol(point), `(@self).EmitArray(#@arraypoint, #@inputpoints));
    }
	
    // After creating everything, call the EmitArray method once to initialize the
    // array.  We do this in case the constituent points are already present in the
    // data set when the script starts.  Otherwise we would have to wait until one
    // of the points changes before the array gets initialized.
    .EmitArray (arraypoint, inputpoints);
}

/* Write the 'main line' of the program here.  Call the .DeclareArray method one or 
 * more times to set up the event handling to construct an array from individual points
 */
method MakeArray.constructor ()
{
    .DeclareArray ("default:pointarray", "R8 array", "default:pointname1", "default:pointname2",
                   "default:pointname3");
}

/* Any code to be run when the program gets shut down. */
method MakeArray.destructor ()
{
}

/* Start the program by instantiating the class.  If your
 * constructor code does not create a persistent reference to
 * the instance (self), then it will be destroyed by the
 * garbage collector soon after creation.  If you do not want
 * this to happen, assign the instance to a global variable, or
 * create a static data member in your class to which you assign
 * 'self' during the construction process.  ApplicationSingleton()
 * does this for you automatically. */
ApplicationSingleton (MakeArray);