Custom Instrument Code - Manipulating Signal IO through a Script

Frozen Content

Input and output signals can be linked directly to the controls placed on the customized GUI for the instrument. For many cases, this direct use of the signals will be sufficient. However, to fully harness the power of the Custom Instrument and give you full control over the processing of signal IO, scripting is required.

Synchronous Read/Write of Signals

An event handler in the script is entered when the event to which it is linked is encountered, or 'fires'. When monitoring inputs or controlling outputs – wired to the Custom Instrument – we are dealing with not just a single control object on the instrument's panel, but rather the entire panel itself. The event we are interested in, and to which we will link code to read input signal values and write values onto output signal lines, is the OnReadWrite event. Figure 1 shows this event, along with shell procedure, for a panel possessing the default name DesignedAreaPanel.


Figure 1. Event handler for the OnReadWrite event, associated to the instrument panel.

The panel's OnReadWrite event is hard coded to 'fire' each time the instrument polls. Remember that the polling interval is 250ms by default, and can be changed in the Custom Instrument - Options dialog (provided the Options button has been enabled for inclusion on the panel).

Each time the instrument polls, the current value for each input signal is read into an internal storage structure. Similarly, the current value internally stored for each output signal is made available at the corresponding output pin of the instrument. The internal storage structure is transparent to the user and, as such, cannot be accessed in any way. The event handling code linked to the OnReadWrite event is essentially used to process the IO as required.


Figure 2. Use event handling code linked to the panel's OnReadWrite event to process signal IO each time the instrument polls.

Of course, the full script may well contain more than just this one event handling procedure, for example to react to buttons being clicked or check boxes being toggled. It may well be that your instrument does not even need to use this event – relying rather on 'asynchronous' events of other controls to process the signals – remember, the IO values are updated by nature of the polling, not by the OnReadWrite event. The latter is simply a method to synchronously call code which can process the signal values at each poll point.
 

If polling is turned off (by setting the Update value in the Custom Instrument - Options dialog to 0ms), the OnReadWrite event will not fire. It will, however, fire if the Synchronize button is available on the instrument's panel, and is pressed. This would essentially be a 'manual poll'.

Getting and Setting Signal Values

Access to the IO signals from within the code is made possible through use of the following global function:

      Function SignalManager : TSignalManager;

This function returns an instance of the TSignalManager class – a global object which provides access to signals within a given Custom Instrument.

Table 1 lists the methods available for the SignalManager object.

Table 1. Supported methods for the SignalManager global function.
Method
Description

Function GetInputSignalCount : Integer;

Returns the number of input signals defined for the instrument.

Function GetInputSignal(Index : Integer) : TSignal;

Returns a given input signal, based on the index value supplied. The index used depends on where the signal appears in the list of input signals, defined on the Signals tab of the Custom Instrument Configuration dialog. Index 0 corresponds to the signal at the top of the list.

Function GetOutputSignalCount : Integer;

Returns the number of output signals defined for the instrument.

Function GetOutputSignal(Index : Integer) : TSignal;

Returns a given output signal, based on the index value supplied. The index used depends on where the signal appears in the list of output signals, defined on the Signals tab of the Custom Instrument Configuration dialog. Index 0 corresponds to the signal at the top of the list.

Function GetSignalByName(Const ASignalName : TDynamicString) : TSignal;

Returns the signal that matches the supplied signal name string.

The main difference between these functions is when each is used:

  • GetSignalByName – use this function when you know the name of the signal that you want to process.
  • GetInputSignal, GetOutputSignal – use these functions, together with GetInputSignalCount and GetOutputSignalCount, when there is a need to iterate all input/output signals, irrespective of how many there are or what their names may be.

The TSignal class object has the following three properties:

  • Name – this read-only property allows you to obtain the name of the signal
  • Value – this read-write property allows you to get the current value for a signal, or to set the value for that signal
  • Width – this read-only property allows you to obtain the width of the signal (e.g. for a signal named Data_Out[7..0], the Width will be 8).

The following example code snippet shows use of this SignalManager function and the GetSignalByName method, to set the value for an output signal, Data_Out[7..0], based on the current value entered into a numeric panel control named LED_Control.

begin
      SignalManager.GetSignalByName('Data_Out[7..0]').Value := LED_Control.Value;
end;

When working with bussed input and output signals in a script, the full signal range must be declared when entering the signal name parameter for the GetSignalByName method, otherwise the script will fail. So for a 32-bit signal VOLTAGE_OUT[31..0], the following line of script will work:

      SignalManager.GetSignalByName('VOLTAGE_OUT[31..0]').Value := $00003500;

but this line of script will not:

      SignalManager.GetSignalByName('VOLTAGE_OUT[15..8]').Value := $35;

Of course, with scripting you can simply add a few extra lines of code to achieve the required result!

You are reporting an issue with the following selected text and/or image within the active document: