How Do I ... ? |
Access a Device from a Script |
|
Often it can be easier to design complex actions and event handling using a script component. By creating a custom script function that can be called from a single Action, you can develop advanced features that are not possible to do using Actions alone.
Invariably, like Actions, script functions often need to access port or device properties. This example shows you how to access any property or method on any device.
Please note that this is an advanced topic and requires programming knowledge. If you have not used script components before, the following topics may be worth reviewing:
There is a multimedia walk-through of these techniques in the online Technical Resources.
If you have modified existing drivers or written your own, you may have seen the FindPortInstance function used before. This function is built into every port script.
In technical terms, it is a public member function of the BaseInPortInstance class, from which all port types are derived.
Within a port script, it is used to locate another port on the same device. For example, the script within a "Relay" port could locate the device's "Serial In" port to transmit a command string.
The FindPortInstance method, along with a few other helper functions, can be used to access:
a Port on the same Device,
a Port on any Device,
a Method or Property of any Port.
Because the FindPortInstance method is built into the port script, it is already aware of which product instance it belongs to. In this case, we simply need to tell it the type of port to find. Use the typeof function to specify the port type to find (to view the code sample, click here):
using Stardraw;
using Stardraw.Project;
using Stardraw.Control;
// requires a reference to Stardraw.Serial.dll
using Stardraw.Serial;
public class MyClass : BaseInPortInstance
{
public MyClass( ProductInstance productInstance, Port port ) : base( productInstance, port )
{
}
[Controllable]
public void Relay( bool state )
{
// locate the serial port
SerialInPortInstance port = FindPortInstance( typeof(SerialInPortInstance) ) as SerialInPortInstance;
// prepare the command string
string command = string.Format( "R{0}", (state ? "1" : "0") );
// write the command to the serial port
if( port != null )
port.Write( command );
}
}
The sample above is a scripted port that:
exposes a Relay method that accepts a boolean parameter,
uses the FindPortInstance method to locate the serial port, passing the type of SerialInPortInstance,
formats a basic command string and calls the serial port's Write method with the command.
Notes
The script block will probably require a using statement to ensure that the type being referenced is accessible to the script, and in turn may also require an Assembly Reference; refer to the Script Editor topic for instructions on how to do this.
This example can only access properties and methods of the base type, that is, only properties and methods of the SerialInPortInstance class can be called directly using the port variable. If the script for the port has derived properties and methods you wish to access, you need to use the ScriptHelper class, which is illustrated below.
If the port you need to access is on a different device, for example if you are accessing devices from a Script Component, you need to use the ScriptHelper class.
The ScriptHelper class also has a FindPortInstance method, however it takes a number of other parameters that identify the device, the name of the port and the port type. This enables your script to access any port on any device in your topology.
In the example below, the following parameters are required for the ScriptHelper's FindPortInstance method:
Parameter |
Description |
deviceName |
The name of the device in the Topology View. |
portName |
The name of the port in the Topology View. |
portTypeName |
The class name of the port, which can be either its base class or derived/custom class. |
To view the code sample, click here:
using Stardraw;
using Stardraw.Project;
using Stardraw.Control;
// requires a reference to Stardraw.Serial.dll
using Stardraw.Serial;
public class MyClass
{
[Controllable]
public void Relay( bool state )
{
// locate the serial port on the "Test(1)" device
ScriptHelper helper = new ScriptHelper();
SerialInPortInstance port = helper.FindPortInstance( "Test(1)", "Serial In", "SerialInPortInstance" ) as SerialInPortInstance;
// prepare the command string
string command = string.Format( "R{0}", (state ? "1" : "0") );
// write the command to the serial port
if( port != null )
port.Write( command );
}
}
The sample above is a script that:
exposes a Relay method like the first sample,
creates a ScriptHelper object and calls the FindPortInstance method to locate the serial port, passing:
the device name "Test(1)", port name "Serial In" and the port's type name "SerialInPortInstance",
formats a basic command string and calls the serial port's Write method with the command.
Note
It is not recommended to access a port on a device from within another device driver, as this creates hard-coded dependencies that are project-specific. You should instead create any inter-device functionality within a separate script component.
The two samples above work well because the class type being referenced (SerialInPortInstance) is accessible to the script, with a using statement or by adding an assembly reference. However this does not work for derived/custom classes whose type name cannot be referenced this way.
There are a number of additional methods that the ScriptHelper has that enable us to work around this.
Method |
Description |
Retrieves the value of any public property of a port. | |
Sets the value of any public property of a port. | |
Executes any public method of a port. |
Consider a device with a serial port that contains the following port script:
using Stardraw;
using Stardraw.Project;
using Stardraw.Control;
using Stardraw.Serial;
public class MySerialPort : SerialInPortInstance
{
public MySerialPort( ProductInstance productInstance, Port port ) : base( productInstance, port )
{
}
private int volume;
[Controllable]
public int Volume
{
get { return volume; }
set
{
volume = value;
// prepare the command string and write to the serial port
string command = string.Format( "V{0}", volume );
this.Write( command );
}
}
[Controllable]
public void SelectInput( int input )
{
// prepare the command string and write to the serial port
string command = string.Format( "I{0}", input );
this.Write( command );
}
}
The sample above is a scripted port class called MySerialPort that is derived from SerialInPortInstance:
exposes a Volume integer property which when set calls the serial port's Write method with a basic command string,
exposes a SelectInput method with an integer parameter, which calls the serial port's Write method with a basic command string
From within a separate script component, we can access the Volume property and SelectInput method of the MySerialPort class as follows (to view the code sample, click here):
using Stardraw;
using Stardraw.Project;
using Stardraw.Control;
public class MyClass
{
[Controllable]
public void VolumeUp()
{
// get a reference to the serial port
ScriptHelper helper = new ScriptHelper();
PortInstance port = FindSerialPort( helper );
// get the current volume setting
int volume = (int)helper.GetPortProperty( port, "Volume" );
// increment the volume and set the new value
volume++;
helper.SetPortProperty( port, "Volume", volume );
}
[Controllable]
public void SetInput( int input )
{
// get a reference to the serial port
ScriptHelper helper = new ScriptHelper();
PortInstance port = FindSerialPort( helper );
// call the SelectInput method passing the input parameter
helper.ExecutePortMethod( port, "SelectInput", input );
}
private PortInstance FindSerialPort( ScriptHelper helper )
{
// find the derived serial port on the "Test(1)" device
PortInstance port = helper.FindPortInstance( "Test(1)", "Serial In", "MySerialPort" );
}
}
The sample above is a script component that:
exposes a VolumeUp method which:
uses the GetPortProperty method to retrieve the Volume property of the MySerialPort object,
uses the SetPortProperty method to set the Volume property,
exposes a SetInput method which:
uses the ExecutePortMethod method to call the SelectInput method of the MySerialPort object, passing the input parameter.
Note
The return value from the GetPortProperty method is of type Object, and requires "casting" to the correct type. In the example above the return value is cast to a type of integer. This also applies to the ExecutePortMethod method.
Please refer to the Class Library section for full details of the ScriptHelper class.