Creating a New Device Type in Visual Logic

The DashBoard Visual Logic editor enables you to add several existing device types to the Devices and Parameters tree so you can control them. For more information, see Adding Devices.

You can also create completely new device types, to control other devices not available by default.

This section describes how to create new device types, including logic blocks.

Note: This is an advanced topic. Most users will never need to add new device types. Knowledge about authoring XML files is useful for understanding this section.

About Adding Devices

In the Visual Logic editor, you can add devices with which you want to work to the Devices and Parameters tree. To do so, you click + and select the type of device you want to add.

(Figure 1.5) shows a list of the device types available by default.

VL_newDevice_01.png 

Figure 1.5  - The Add Device List

When you add a device, it creates a new branch in the tree and you have an API sub-branch which contains logic blocks you can use in your ogScript code segments. For example, if you add an XPression device named myXpression, the tree would look similar to the one shown in (Figure 1.6):

VL_newDevice_02.png 

Figure 1.6  - Adding an XPression Device (myXpression)

Users can click and drag the API logic blocks into the Visual Logic workspace.

This section describes how to create new device types that appear in the Add Device list, and how to define API blocks for the new device types.

Creating a New Device Type

In order to create a new device type, you add a special XML file to the VisualLanguage\blocks\Devices sub-folder of your DashBoard installation (typically c:\DashBoard). The XML file defines the new device type.

(Figure 1.7) shows the XML file with only an empty device definition element (<deviceapi>).

VL00003.jpg

Figure 1.7  - Starting to Create an XML File that Defines a New Device Type

In (Figure 1.7), Line 1 is an XML header.

Lines 2 - 4 define a new device type named myDeviceType. The <deviceapi> element will contain the device definition. In theory, you could define more than one device type in a single XML file, but in practice we tend to only define one device type per file.

If all you have is the above in your file, when you click on the + button, you would see:

VL_newDevice_04.png 

Figure 1.8  - Device List Showing the New Device

Note that Add myDeviceType is now one of the options. When you click it, the following window appears, asking for a Name and a Block Color for the device.

VL_newDevice_05.png 

Figure 1.9  - Adding a Device to the Devices and Parameters Tree

Because we have not added any logic blocks to the new device, it has an empty API node, as shown in (Figure 1.10).

VL_newDevice_06.png 

Figure 1.10  - The Devices and Parameters Tree, Showing the New Device

We need to add API blocks to this device, but before we do that, we may need to collect more information from the user when they add the device.

Adding Connection Parameters to the Add Device Dialog Box

To communicate with a device, you often need to know several things about it. For example, you might need the IP Address and Port. Depending on the device, you may even need something else (such as a channel, or some other parameter).

You want to be able to ask the user for that information when they add the device. To specify what you’re asking the user for, add an <arguments> element within the <deviceapi> element. Inside the <arguments> element, you can add as many <argument> elements as you want. Each one has a name attribute and a variable attribute.

The name is what the user sees in the popup when she or he adds a device.

The variable attribute value will be used later when we define the API logic blocks.

For example, if we create and populate the <arguments> element as shown in (Figure 1.11).

VL00006.jpg

Figure 1.11  - Starting to Create an XML File that Defines a New Device Type

When a user clicks Add myDeviceType, they will see the following dialog box:

VL_newDevice_08.png 

Figure 1.12  - Adding a Device to the Devices and Parameters Tree (with Connection Parameters)

Note that users are now prompted for an IP address, port number and a channel. Users can specify either a fixed value or the value from a parameter in the panel. The values they specify in this dialog box can be used in the API blocks you will create.

Adding API Blocks to the New Device Type

Now that we have all the information needed to communicate with the device, we can create API blocks for it.

In order to do this, we need to add a <blocks> element within the <deviceapi> element. The code example in (Figure 1.13) includes a <blocks> element populated with a <block> element (lines 7 to 17).

VL00009.jpg

Figure 1.13  - Adding API Blocks to the New Device Type

Within the <blocks> element, you can have multiple <block> child elements. The preceding example contains only one. Each <block> element defines one API logic block.   Lines 8 to 16 define one logic block.

Each <block> element requires the following information:

Name of the block — Specify the name in the name attribute of the <block> element. In (Figure 1.13), line 8 defines the name as <block name="myDeviceType_command1">.

The name must be unique within all of Visual Logic. We suggest that you give it a name based on the device type and the function this block will have, for example, myDeviceType_command1.

Title — The text that will be displayed at the top of the block. Specify the title in a <title> element within the <block> element. Line 9 in (Figure 1.13) defines the title as <title>run command1</title>.

Help — The help message that appears when a user clicks the Help (?) button on the logic block. Specify the help message in a <help> element within the <block> element. Line 10 in (Figure 1.13) defines the help message as <help>executes command 1</help>.

Arguments — These define what inputs are required from the user to run this logic block. In (Figure 1.13), Line 11 specifies that this block has no arguments.

More information about arguments appears in the section, Adding Data Input to Your API Blocks.

Output — This element specifies whether this logic block has an output. Outputs can be used as data inputs for other blocks.

If you set the <output> element to true (<output>true</output>), the logic block will have an output connection point on its right side.

If you set the <output> element to false (<output>false</output>), it will have no output.

In (Figure 1.13), line 12 specifies that this block does not have an output.

Top and Bottom flow — The <top_flow> and <bottom_flow> elements specify whether the logic block will have connection points to allow users to specify the execution order of the blocks.

Typically, if a block has an output connector, it should not also have top and bottom connectors (and vice versa).

If your block has a top connector, it should also have a bottom connector.

In (Figure 1.13), lines 13 and 14 specify that this block will have both a top and bottom connector.

Translation — The translation element specifies the text to use when translating this block to ogScript.

Any variable that is present on the line between tide (~) characters will be replaced by the value the user specifies when adding the block.

In (Figure 1.13), line 15 specifies that the translation is "rosstalk.sendMessage(~HOST~, ~PORT~, "cmd1 on ~CHANNEL~");"s

When translating this line, Visual Logic would replace ~HOST~, ~PORT~ and ~CHANNEL~ with the values the user specified when they added the device. More information on this is appears in later sections.

 

For example, the block definition in (Figure 1.14)

VL00012.jpg

Figure 1.14  - A Block Definition

produces a logic block that looks like the one in (Figure 1.15).

VL_newDevice_11.png 

Figure 1.15  - A Logic Block with Top and Bottom Connectors, but no Output Connector

A block definition that has the output turned on and the top and bottom flows turned off as shown in (Figure 1.16)

VL00015.jpg

Figure 1.16  - A Block Definition

would look like (Figure 1.17).

VL_newDevice_13.png 

Figure 1.17  - A Logic Block with an Output but no Top or Bottom Connectors

Adding Data Input to Your API Blocks

Some blocks require additional data to run the command. Adding arguments to a block enables it to collect the required data.

For example, if you are creating a block that sends a message, the block needs the message data. The data is collected as an argument value. The argument value can be provided to the block through a data input, or through a widget on the block that collects the data from the user.

Arguments can either be internal or external. Internal arguments have widgets that allow the user to specify the value. Internal arguments may also have a data input that accepts a value from another block. External arguments receive data only from other blocks.

To add an argument to a block, add one of the following elements as a child of the <arguments> element:

<internal> — Use this element to create an argument that has a widget that allows users to specify a value.

An argument created via the <internal> element also has a data input that allows the panel designer to connect a value from another block. If the data input is connected, the value selection widget is not shown.

<internal_only> — Use this element to create an argument that accepts user input only, via a widget that allows users to specify a value. This argument does not have a data input and cannot accept data from other blocks.

<external> — Use this element to create an argument that has a data input only. This argument does not include a value selection widget.

The XML code in (Figure 1.18) defines an internal argument that has a text box widget for specifying the argument value:

VL00018.jpg

Figure 1.18  - An Internal Argument Definition

 

Arguments require the following:

name — The argument elements (<internal>, <internal_only>, and <external>) require a name attribute. In (Figure 1.18), Line 2 specifies the argument name as "ARG1" The name must be unique within this block definition.

type — For <internal> arguments only. The type specifies what kind of widget to use in the block. It can be one of "WIDGET_TEXTBOX", "WIDGET_SPINNER", "WIDGET_COMBO" or "WIDGET_CHECKBOX". In (Figure 1.18), Line 3 specifies the type as "WIDGET_TEXTBOX".

When replacing the arguments in the translation with their value, by default Visual Logic adds quotes around any string (but not numbers). If you do not want the quotes, append _unquoted to the argument type. For example, if you use "WIDGET_TEXTBOX_unquoted" as the type for "ARG1", quotes will never be added to ARG1 when doing the translation.

tag — The <tag> element specifies what words appear beside the widget for this argument. In (Figure 1.18), Line 4 specifies the tag text as "Arg1". The <tag> element is optional. If no tag is specified, there will be no text beside the widget.

default value — The <default> element specifies the default value of the widget when the block is created. In (Figure 1.18), Line 5 specifies the type as "hello". The <default> element is optional.

value choices — Applies only to arguments of the "WIDGET_COMBO" type. The <choices> element specifies a comma-separated list of possible values from which the user can choose.

The block defined by the code in (Figure 1.19) includes one argument of each type.

VL00021.jpg

Figure 1.19  - A Block Definition that Includes Each Type of Argument

The code shown in (Figure 1.19) produces a block that looks like (Figure 1.20).

VL_newDevice_16.png 

Figure 1.20  - A Block with Each Type of Argument

Once you have defined the arguments you want, you can use them in your translation the same way you used the variables. Any strings in the translation that is formatted with ~ARGNAME~ will be replaced with the argument value when the block is translated.

If the user specified the values shown (Figure 1.21) in when adding the device to the Devices and Parameters tree,

VL_newDevice_17.png 

Figure 1.21  - Specifying Connection Parameters

then a translation of the following:

rosstalk.sendMessage(~HOST~, ~PORT~,  "cmd3 " + ~ARG1~ + ~ARG2~ + " " + ~ARG3~ + " " + ~ARG4~ + "on ~CHANNEL~");

would translate to:

rosstalk.sendMessage("10.3.2.1", 1023, "cmd3 " + "hello" + 0 + " " + "one" + " true on 4");

Example XML File

Below is the full example XML file that was used to create the myDeviceType device type.

<?xml version="1.0" encoding="UTF-8"?>

<deviceapi name="myDeviceType">

 <arguments>

  <argument name="IP Address" variable="HOST"/>

  <argument name="Port Number" variable="PORT"/>

  <argument name="Channel" variable="CHANNEL"/>

 </arguments>

 

 <blocks>

  <block name="myDeviceType_command1" editable="true">

   <title>run command 1</title>

   <help>Executes command 1.</help>

   <arguments></arguments>

   <output>false</output>

   <top_flow>true</top_flow>

   <bottom_flow>true</bottom_flow>

   <translation>rosstalk.sendMessage(~HOST~, ~PORT~, "cmd1 on ~CHANNEL~");

   </translation>

  </block>

 

  <block name="myDeviceType_command2" editable="true">

   <title>run command 2</title>

   <help>Executes command 1.</help>

   <arguments></arguments>

   <output>true</output>

   <top_flow>false</top_flow>

   <bottom_flow>false</bottom_flow>

   <translation>rosstalk.sendMessage(~HOST~, ~PORT~, "cmd2 on ~CHANNEL~")

   </translation>

  </block>

 

  <block name="myDeviceType_command3" editable="true">

   <title>run command 3</title>

   <help>Executes command 3.</help>

   <arguments>

    <internal name="ARG1">

     <type>WIDGET_TEXTBOX</type>

     <tag>Arg 1</tag>

     <default>hello</default>

    </internal>

    <internal name="ARG2">

     <type>WIDGET_SPINNER</type>

     <tag>Arg 2</tag>

     <default>0</default>

    </internal>

    <internal name="ARG3">

     <type>WIDGET_COMBO</type>

     <tag>Arg 3</tag>

     <default>one</default>

     <choices>one,two,three</choices>

     </internal>

    <internal name="ARG4">

     <type>WIDGET_CHECKBOX</type>

     <tag>Arg 4</tag>

     <default>true</default>

    </internal>

    <external name="ARG5">

     <tag>Ext Arg</tag>

    </external>

   </arguments>

   <output>false</output>

   <top_flow>true</top_flow>

   <bottom_flow>true</bottom_flow>

   <translation>rosstalk.sendMessage(~HOST~, ~PORT~, "cmd3 " + ~ARG1~ + ~ARG2~ + " " + ~ARG3~ + " ~ARG4~ on ~CHANNEL~");</translation>

  </block>

 </blocks>

</deviceapi>