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:

 

Online Resources

There is a multimedia walk-through of these techniques in the online Technical Resources.

 

The FindPortInstance Method

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:

 

Accessing a Port on the same Device

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:

 

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.

 

Accessing a Port on a different Device

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:

the device name "Test(1)", port name "Serial In" and the port's type name "SerialInPortInstance",

 

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.

 

Accessing a Method or Property of a Derived Class

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

GetPortProperty

Retrieves the value of any public property of a port.

SetPortProperty

Sets the value of any public property of a port.

ExecutePortMethod

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:

 

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:

uses the GetPortProperty method to retrieve the Volume property of the MySerialPort object,

uses the SetPortProperty method to set the Volume property,

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.

 

See Also

Script Component

Design Patterns Index

Class Library