top of page
Search

Applying a SCL script to a resource over the API

Writer: Ivaylo FizievIvaylo Fiziev

Scripting is nice. I think we all agree with this statement. It would be even nicer if we can automate the process of creating scripts. e.g. generate and assign scripts to resources over the official API of Process Simulate. Is this really possible? Yes it is.

The SCL editor does exactly this. It uses the API to assign a script to a resource.

It can also set default values for variables as well as connect signals to them.

Let's see how this works.

Every resource that can have a script assigned implements the following interfaces:

1. ITxPlcSclResource - provides access to the entity containing the SCL script, metadata etc. for a given resource. We call it SCL container.

2. ITxPlcSclCreation - allows this entity to be created (if missing)


To assign a script to a resource first you should use the first interface to check if the container exists, and if not - create it. Of course the component should be in modeling scope first.

The container implements the ITxPlcSclContainer interface. In v2502 it allows you to:

1. Get/Set the text of the main script for the component

2. Get/Set the variable metadata (connected signals, default values)

3. Get/Set the execution priority of the script (relative to other scripts in the study)

4. Get/Set the active state of the main script. (should it execute or not)


Here is some sample code (.Net viewer):

using System;
using System.IO;
using Tecnomatix.Engineering;
using Tecnomatix.Engineering.Plc;
using System.Collections.Generic;

namespace ApplySclScript {

public static class App {

public static void MainWithOutput(ref StringWriter output) {
var selectedResources = TxApplication.ActiveSelection.GetFilteredItems(new TxTypeFilter(typeof(ITxPlcSclCreation)));
if (selectedResources.Count != 1)
 	return;

var component = selectedResources[0] as ITxComponent;
if (!component.IsOpenForModeling)
	component.SetModelingScope();

var logicResource = selectedResources[0] as ITxPlcSclResource;
if (logicResource.SclContainer == null) {
	ITxPlcSclCreation resource = selectedResources[0] as 	ITxPlcSclCreation;            	
	using (var creationData = new    			TxPlcSclContainerCreationData(resource.Name)) {
		if (resource.CanCreateSclContainer(creationData)) {
			resource.CreateSclContainer(creationData);
		}	
		else {
			output.WriteLine("Error");
			return;
		}
	}
}
var variablesMetadata = new List<TxPlcSclVariableMetaData>(); 
 
var varMetaData = new TxPlcSclVariableMetaData("956F7874-B4C3-4A7F-9F66-088C8483BCD5"); // variable ID in the script
// Set the default value 
var instanceAttributes = new List<TxPlcSclVariableMetaDataAttribute>();            instanceAttributes.Add(new TxPlcSclVariableMetaDataAttribute("defaultValue", "0.0"));            varMetaData.InstanceAttributes = instanceAttributes;
// Set the connected signal 
varMetaData.ConnectedSignals = new TxObjectList<ITxPlcSignal>() { /* some signal*/ };
variablesMetadata.Add(varMetaData);

varMetaData = new TxPlcSclVariableMetaData("45AA75B5-807D-44A3-A781-26AA655CAF23"); // variable ID in the script
// Set the default value 
instanceAttributes = new List<TxPlcSclVariableMetaDataAttribute>();            instanceAttributes.Add(new TxPlcSclVariableMetaDataAttribute("defaultValue", "1.0"));            varMetaData.InstanceAttributes = instanceAttributes;
// Set the connected signal 
varMetaData.ConnectedSignals = new TxObjectList<ITxPlcSignal>() { /* some signal*/ };
variablesMetadata.Add(varMetaData);

// Apply the script text            logicResource.SclContainer.MainProgramText = "FUNCTION_BLOCK \"MAIN\" VAR_INPUT in {ID='956F7874-B4C3-4A7F-9F66-088C8483BCD5'}:LREAL; END_VAR VAR_OUTPUT out {ID='45AA75B5-807D-44A3-A781-26AA655CAF23'}:LREAL; END_VAR BEGIN  #out:=#in ** 2; END_FUNCTION_BLOCK";

// Assign the variables meta data             logicResource.SclContainer.VariablesMetaData = variablesMetadata;
logicResource.SclContainer.ExecutionPriority = 10; // raise the execution priority
logicResource.SclContainer.Active = true; // run the script during simulation

output.WriteLine("Done!");
}
}
}

This looks like quite a hassle for such a small script, isn't it? I agree with you but this is the current situation.

Regardless of the complexity here are the main points to consider:


1. The script is just text based on the SCL syntax. It could be a function block (FB) or a function (FC). The SCL editor however expects a FB. Why? Because FBs can have static variables and as we already know static variables hold the state during simulation. The script becomes part of the prototype data of the component that has it.


2. Every input/output variable in the script should have a unique identifier as one of its system attributes. In this example we use GUIDs for the identifiers (SCL editor does the same) but you are not obliged to do so. You can use any string that is unique within the script. Based on the identifier, metadata is associated with the variable. It is important to provide an identifier for every variable otherwise the UI for connecting signals to the variables won't work!

Why not use the variable names instead?

The names can change ... and when they change you loose the metadata.


3. The metadata holds instance attributes of the variable as well as signals connected to it. Attributes are just name-value pairs with predefined meaning. Currently the only one is the 'defaultValue'. Both are part of the instance data for the component that has the script.


4. The metadata provides prototype attributes as well but these are still not used. Default values can become part of the prototype data only if they are provided in the script.

in {ID='956F7874-B4C3-4A7F-9F66-088C8483BCD5'}:LREAL := 0.0;

Signals have no place in the prototype data since they are study specific.


5. If you need to change a single attribute or signal you'll have to rebuild the whole thing once again. This really sucks.


6. Execution priority is just an integer that can be used to give precedence of a script over other scripts in the study. By default all scripts have execution priority of zero. Bigger values make the script execute first. Lower values make it execute last.


We have plans to simplify the API in the future (still under discussion). One of the ideas is to expose a new method in the SCL container that will hide the boilerplate code and make your life easier.

Example:

/// <summary>
/// Applies a script to the SCL container.
/// </summary>
/// <param name="script">The script code.</param>
/// <param name="signals">Var ID to signal<param>
/// <param name="defaultValues">Var ID to default value.<param>
void ApplyScript(
	string script,
	Dictionary<string, ITxSignal> signals,
	Dictionary<string, string> defaultValues);

Until then you'll have to fight with the metadata.


Script authoring is not planned! You'll have to format it yourself.

If the script uses subscripts it is your responsibility to import the subscripts in the SCL vault first!

 
 
 

Comments

Rated 0 out of 5 stars.
No ratings yet

Add a rating

Subscribe Form

Thanks for submitting!

bottom of page