Child Tag Sample Code

The example included below is the source code for a lift station where child tags are launched to accommodate the lift station's I/O.

 

{========================= Station ==============================}
{ A VTScada Station Tag. Launches off child tags with Inputs    }
{ associated with the station.                                  }
{================================================================}

When structuring a parent and child tags, it is good practice to configure the parent with only those parameters that are necessary to define what is unique for the station (i.e. the parent should have enough parameters to cover variants in the children). The child tags will then have the common parameters defined.


(
  Name                  { Tag Name                            };
  Area                  { Tag area                            };
  Description           { Tag Description                     };
  StationNumber         { Station number for Poll Group         };
  NumberPumps           { Number of pumps                       };
)

[
  Constant DrawLabel = "StationPointLabel";

  Root                  { Instance of this module               };
  Value(5);
  Refresh      Module;
  ConfigFolder Module;
  Common       Module;

  [(GRAPHICS)
    Draw       Module;
    Shared Number;
  ]

Below, the child tag modules are defined. The same children are present for each and every lift station in this system.


  [(CHILDREN)
    PollDriver;
    StationIODevice;
    Pump1Status;
    Pump2Status;
    Pump3Status;
  ]

  [(GROUPS)
    Shared Numeric;
  ]
   { Parameter Constants }
  CONSTANT #StationNumber = 3;
  CONSTANT #NumberPumps   = 4;
]

Init [

  If 1 Main;
  [
    Root = Self;
    Refresh();
  ]
]

Main [

  Value = PollDriver\Value;
]

<
{========================== Refresh ========================}
{ This subroutine called whenever the point's parameters    }
{ change and startup                                        }
{===========================================================}
Refresh
(
  Parm         { Array for parameters prior to their change };
)

As with standard tags, the Refresh subroutine must be called whenever a tag is launched or whenever its parameters have changed.


Refresh [

  If watch(1);
  [
    \StartTag(ParentObject(Self),
              1                    { Conditional Launch expression },
              "PollDriver"         { Name of tag type              },
              "Name", "PollDriver" { Parameter name & value pairs  },
              "Area",         Area,
              "Description",  PickValid(Description, Name),
              "DeviceTag",    Concat(Name,"\StationIODevice"),
              "PollGroup",    Invalid,
              "Sequence",     StationNumber,
              "Interval",     10,
              "Offset",       0,
              "PollDisabled", 0,
              "HelpKey",      Invalid);

   \StartTag(ParentObject(Self),
              1              { Conditional Launch expression },
              "PMC1000"      { Name of tag type },
              "Name",   "StationIODevice" { Name and value pairs },
              "Area",        Area,
              "Description", Concat(PickValid(Description, Name),
                                     " Driver"),
              "ReadDelay",   1,
              "HelpKey",     Invalid);

    \StartTag(ParentObject(Self),
              1               { Conditional Launch expression },
              "Pump"          { Name of tag type },
              "Name",    "Pump1Status" { Name and value pairs },
              "Area",         Area,
              "Description",  "Pump 1 Status",
              "DeviceTag",    Concat(Name, "\PollDriver"),
              "Bit0Address",  "B0DI0",
              "Bit1Address",  Invalid,
              "ScanRate",     Invalid,
              "InvertInput",  0,
              "OffText",      "Off",
              "OnText",       "On",
              "AlarmState",   Invalid,
              "AlarmDelay",   Invalid,
              "Trip",         0,
              "Priority",     0,
              "Inhibit",      1,
              "AlarmSound",   Invalid,
              "ManualValue",  Invalid,
              "Questionable", 0,
              "Quality",      Invalid,
              "DisplayOrder", 1,
              "HelpKey",      Invalid);

    \StartTag(ParentObject(Self),
              NumberPumps > 1 { Conditional Launch expression },
              "Pump"          { Name of tag type },
              "Name",    "Pump2Status" { Name and value pairs },
              "Area",         Area,
              "Description",  "Pump 2 Status",
              "DeviceTag",    Concat(Name, "\PollDriver"),
              "Bit0Address",  "B1DI0",
              "Bit1Address",  Invalid,
              "ScanRate",     Invalid,
              "InvertInput",  0,
              "OffText",      "Off",
              "OnText",       "On",
              "AlarmState",   Invalid,
              "AlarmDelay",   Invalid,
              "Trip",         0,
              "Priority",     0,
              "Inhibit",      1,
              "AlarmSound",   Invalid,
              "ManualValue",  Invalid,
              "Questionable", 0,
              "Quality",      Invalid,
              "DisplayOrder", 2,
              "HelpKey",      Invalid);

    \StartTag(ParentObject(Self),
              NumberPumps > 2 { Conditional Launch expression },
              "Pump"          { Name of tag type },
              "Name",       "Pump3Status" { Name and value pairs },
              "Area",         Area,
              "Description",  "Pump 3 Status",
              "DeviceTag",    Concat(Name, "\PollDriver"),
              "Bit0Address",  "B2DI0",
              "Bit1Address",  Invalid,
              "ScanRate",     Invalid,
              "InvertInput",  0,
              "OffText",      "Off",
              "OnText",       "On",
              "AlarmState",   Invalid,
              "AlarmDelay",   Invalid,
              "Trip",         0,
              "Priority",     0,
              "Inhibit",      1,
              "AlarmSound",   Invalid,
              "ManualValue",  Invalid,
              "Questionable", 0,
              "Quality",      Invalid,
              "DisplayOrder", 3,
              "HelpKey",      Invalid);

    Return(0);
  ]
]
>

As with standard tag code, the ConfigFolder module is called when the tag's properties are displayed.


<
{==================== ConfigFolder ===========================}
{ This is the shell of an editable ConfigFolder for a tag    }
{ where the ConfigFolder is created and maintained by the    }
{ ConfigFolder Wizard.                                       }
{ Manual editing of the code is allowed as long as the state }
{ structure is maintained.                                   }
{=============================================================}
ConfigFolder
(
  Parms              { Pointer to array of parameters              };
  Current            { Currently selected tab (starts at 0)        };
  PtrWaitClose       { Pointer to FLAG - True when any watching module should wait to close.
                         Caller must default to 0.                 };
  OKPressed          { OKPressed from PropertiesDialog             };
)

[
  Constant #WIDTH = 500;

  [(1)
    IDTabLabel      = "ID";
    ConfigTabLabel  = "Config";
  ]
]

Switch [

  If Current == 0 ID;
  If Current == 1 Config;
]

ID [
    { If page changes, change states }
  If Current != 0 Switch;

    { Name of the point }
  GUITransform(30, 105, #Width - 30, 60,
               1, 1, 1, 1, 1     { No scaling                     },
               0, 0, 1, 0        { No movement; visible; reserved },
               0, 0, 0           { Not selectable                 },
               \DialogLibrary\PEditField(0, \NameLabel, 4 { text }, 1 { ID }));

    { Area that the point belongs to }
  GUITransform(30, 160 { btm at 90 }, #Width  - 30, 115,
               1, 1, 1, 1, 1     { No scaling                     },
               0, 0, 1, 0        { No movement; visible; reserved },
               0, 0, 0           { Not selectable                 },
               \DialogLibrary\PAreaSelect(1 { can edit }, 2 { ID }));

    { Description of the site }
  GUITransform(30, 215, #Width - 30, 170,
               1, 1, 1, 1, 1    { No scaling                     },
               0, 0, 1, 0       { No movement; visible; reserved },
               0, 0, 0          { Not selectable                 },
               \DialogLibrary\PEditField(2, \DescriptionLabel,
                                        4 { text },    3 { ID }));
]

Config [

  If Current != 1 Switch;

    { Station number }
  GUITransform(30, 105, #Width - 30, 60,
               1, 1, 1, 1, 1     { No scaling                     },
               0, 0, 1, 0        { No movement; visible; reserved },
               0, 0, 0           { Not selectable                 },
               \DialogLibrary\PEditField(#StationNumber,
                                        "Station Number",
                                        2 { Long }, 1 { ID }));

    { Number of Pumps }
  GUITransform(40, 160 { btm at 90 }, #Width  - 30, 125,
               1, 1, 1, 1, 1     { No scaling                     },
               0, 0, 1, 0        { No movement; visible; reserved },
               0, 0, 0           { Not selectable                 },
               \DialogLibrary\PSpinBox(#NumberPumps,
                                      "Number of Pumps",
                                      1 {Left}, 0, 3 {Limit},
                                      0 {Alignment}, 1 {NumChars},
                                      0 {CanEdit},
                                      2 {ID}));
]
{ End of ConfigFolder }
>

<
{=========================== Draw ==============================}
{ A Drawing method for this tag                                                }
{===============================================================}
Draw

DrawMain [

  GUITransform(8, 40, 108, 10,
               1, 1, 1, 1, 1 { Scaling              },
               0, 0          { Movement             },
               1, 0          { Visibility, scaling  },
               0, 0, 0       { Selectability        },
               PollDriver\Fast_Scan("Fast", "Fast", 2, 1,
                                    600, 1, 1, 1));
  GUITransform(20, 188, 126, 132,
               1, 1, 1, 1, 1 { Scaling              },
               0, 0          { Movement             },
               1, 0          { Visibility, scaling  },
               0, 0, 0       { Selectability        },
               Pump1Status\ImageChange("Bitmaps\Pumps\pump37.bmp", "Bitmaps\Pumps\pump37.bmp", "Bitmaps\Pumps\pump37.bmp", "Bitmaps\Pumps\pump37.bmp", 12, 10, 11, 7, 0, "Bitmaps\Pumps\pump37.bmp"));

  GUITransform(682, 188, 788, 132,
               1, 1, 1, 1, 1 { Scaling              },
               0, 0          { Movement             },
               1, 0          { Visibility, scaling  },
               0, 0, 0       { Selectability        },
               Pump2Status\ImageChange("Bitmaps\Pumps\pump38.bmp", "Bitmaps\Pumps\pump38.bmp", "Bitmaps\Pumps\pump38.bmp", "Bitmaps\Pumps\pump38.bmp", 12, 10, 11, 7, 0, "Bitmaps\Pumps\pump38.bmp"));

  GUITransform(682, 216, 788, 272,
               1, 1, 1, 1, 1 { Scaling              },
               0, 0          { Movement             },
               1, 0          { Visibility, scaling  },
               0, 0, 0       { Selectability        },
               Pump3Status\ImageChange("Bitmaps\Pumps\pump38.bmp", "Bitmaps\Pumps\pump38.bmp", "Bitmaps\Pumps\pump38.bmp", "Bitmaps\Pumps\pump38.bmp", 12, 10, 11, 7, 0, "Bitmaps\Pumps\pump38.bmp"));
]
{ End of Draw }
>

As with standard tag code, the Common module is called by the tag's drawing methods, and is responsible for each tag's tool tips and shortcut menu (or navigator) options.


<
{========================= Common ==============================}
{ This module handles the common actions associated with all   }
{ drawing modules for this point.  It will be called by all    }
{ external drawing modules.                                    }
{===============================================================}
Common
(
  Left          { Area occupied by the drawing object         };
  Bottom;
  Right;
  Top;
)

Common [
  \PostIt(Left, Bottom, Right, Top, \Name, \Description,
          ! \GetUserSession()\NavActive);

  \Navigator(1 { Opening condition for the folder },
             Left, Bottom, Right, Top    { Target area for opening –
                                          same as the GUI statement
                                          area.          },
             { Menu line 1 } \PropertiesLabel, Invalid, 0, Invalid);
]
{ End of Common }
>
{ End of Station }