Dynamic Object Oriented programming in ArchestrA

As with most developers using Wonderware products, I often have to get creative to compensate for the limitations in the development platform, scripting language, etc. Lately, I've been need to create "objects" (in the object oriented programming sense of the word, not the app server sense). That is I need collections of data describing some real world thing.

For example, I have been creating a callout feature for a client's SCADA host system. The callouts are stored in a SQL database and my scripts pull out a whole set at a time. Each callout has various attributes such as the callout type, the comparison operator (>, <, =, >=, <=), the setpoint, etc. This presents two issues. First, how do I keep all of these pieces of information together for each callout without creating & deploying App Server objects for each one. Second, at any given time, there will be a variable number of callouts.

I have used the following method (read complete hack) to address the issue. I have created several UDA arrays with an initial size of 1 (number of elements) and a naming convention which shows their relationship:

ConfiguredCallouts.Type
ConfiguredCallouts.ComparisonOperator
ConfiguredCallouts.Setpoints
etc.

The idea is that a given callout is stored at a given location in the arrays. So for example, when we load a callout from the database, it's type would be stored in ConfiguredCallouts.Type[1], it's comparison operator would be stored in ConfiguredCallouts.ComparisonOperator[1], etc. The next callout would store it's type in ConfiguredCallouts.Type[2], and so on. Then for any given callout, all of it's attributes are simply stored an a given array index. Like I said, it's a complete hack and one that makes programmers used to general purpose programming languages uneasy. But, such is life with Wonderware products. I have found no better solution.

So, that satisfies the first issue above (keeping information for each callout together). The second (handling a variable number of callouts) can be handled by growing the arrays as needed when populating them from the database. This can be accomplished by manipulating the array UDAs "Dimension1" property as follows:

'Reset array dimensions (clear the arrays)
Me.ConfiguredCallouts.Type.Dimension1 = 0;
Me.ConfiguredCallouts.ComparisonOperator.Dimension1 = 0;
Me.ConfiguredCallouts.Setpoint.Dimension1 = 0;

'Snipped code to connect to and query database

dim index as integer;
index = 1;

while reader.Read()
'Grow arrays to fit each new configured callout.
Me.ConfiguredCallouts.Type.Dimension1 = Me.ConfiguredCallouts.Type.Dimension1 + 1;
Me.ConfiguredCallouts.ComparisonOperator.Dimension1 = Me.ConfiguredCallouts.ComparisonOperator.Dimension1 + 1;
Me.ConfiguredCallouts.Setpoint.Dimension1 = Me.ConfiguredCallouts.Setpoint.Dimension1 + 1;

'Pull callouts from DB reader & put in the current index in the array.
Me.ConfiguredCallouts.Type[index] = reader("CalloutType");
Me.ConfiguredCallouts.ComparisonOperator[index] = reader("ComparisonOperator");
Me.ConfiguredCallouts.Setpoint[index] = reader("Setpoint");

index = index + 1;
endwhile;

So, by increasing the array dimensions by 1 for each new callout we can accomodate any number of callouts. If this were a general purpose programming language, there would of course be better ways of doing this, but given the restrictions of developing in ArchestrA, this will suffice.

Comments

Popular posts from this blog

Fixing Conan Lock Issues

Setting up Jenkins, GoogleTest, & Mercurial (with a local repository)

Making a standard ASP.NET listbox do multiselect without holding Ctrl