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 }