Technical topic: C++ Components and AIR IO Partitions

From TASTE
Jump to: navigation, search

This section explains step by step how to create a generic C++ component that can be instantiated as an AIR IO Partition

Create a data view to cope with a device configuration

AIR-IOP-DEVICE-DATAVIEW DEFINITIONS ::=
BEGIN 

--  Define a buffer to receive data from devices
Data-Stream ::= OCTET STRING (SIZE (0..100))

--  Device configuration
IOP-Device-Identifier ::= CHOICE {
   eth     IOP-ETHn,
   grspw   IOP-GRSPWn,
   can     IOP-CANn,
   spwrtr  IOP-SPWRTR,
   mil     IOP-MILn
}

-- All types below give the detailed configuration for each
-- supported device.

IP-Address ::= SEQUENCE (SIZE (4)) OF INTEGER (0..255)
MAC-Address ::= SEQUENCE (SIZE(6)) OF INTEGER (0..255)

IOP-ETHn ::= SEQUENCE {
   n  INTEGER (0..7),   -- Max range not specified
   ip IP-Address,
   mac MAC-Address,
   routes SEQUENCE (SIZE (1..5)) OF Route -- Max size not specified
}

Route ::= SEQUENCE {
   route-ip IP-Address,
   route-mac MAC-Address,
   route-port INTEGER (0..65535)
}

IOP-GRSPWn ::= SEQUENCE {
   n INTEGER (0 .. 7),
   addr INTEGER (-1 .. 31),
   mask INTEGER (0 .. 255),
   retry INTEGER (-1 .. 50),
   rx-max INTEGER (4 .. 1520),
   pro BOOLEAN,
   routes SEQUENCE (SIZE (1 .. 5)) OF INTEGER (-1 .. 31)
}

IOP-CANn ::= SEQUENCE {
   n INTEGER (0 .. 7),
   baud INTEGER (0 .. 2048),
   code INTEGER (0 .. 4294967295),
   mask  INTEGER (0 .. 4294967295),
   selection INTEGER (0 .. 1),
   enable0 INTEGER (0 .. 1),
   enable1 INTEGER (0 .. 1),
   routes SEQUENCE (SIZE (1 .. 5)) OF Can-Route
}

Can-Route ::= SEQUENCE {
   extended BOOLEAN,
   rtr BOOLEAN,
   can-id INTEGER (0 .. 7) --  Max range not specified
}

IOP-MILn ::= SEQUENCE {
   major-frame INTEGER (0 .. 10000000),
   slots SEQUENCE (SIZE (1 .. 10)) OF MIL-Slot,   -- Range not specified
   routes SEQUENCE (SIZE (1 .. 5)) OF MIL-Route -- Range not specified
}

MIL-Slot ::= SEQUENCE {
   slot-bus ENUMERATED { bus-a, bus-b },
   slot-type ENUMERATED { rt-bc, bc-rt, rt-rt },
   slot-addr INTEGER (0 .. 31),
   slot-subAddr  INTEGER (0 .. 31),
   slot-wcmc INTEGER (0 .. 32),
   slot-time INTEGER (0 .. 1000000),
   slot-addrTx INTEGER (0 .. 30),
   slot-subAddrTx INTEGER (0 ..30)
}

MIL-Route ::= SEQUENCE {
   route-addr INTEGER (0 .. 31),
   route-subAddr INTEGER (0 .. 31)
}

IOP-SPWRTR ::= SEQUENCE {
   flags SPW-Flags,
   config SPW-Config,
   idd INTEGER (0 .. 2048),
   idiv INTEGER (0 .. 2048),
   prescaler INTEGER (0 .. 2048)   
}

SPW-Flags ::= SEQUENCE {
   timer-reload-register BOOLEAN,
   timer-prescaler-register BOOLEAN,
   clock-divisor-register BOOLEAN,
   instance-id-register BOOLEAN,
   config-register BOOLEAN
}

SPW-Config ::= SEQUENCE {
   spw-reset BOOLEAN,
   auto-disconnect BOOLEAN,
   link-start-on-request BOOLEAN,
   self-addressing-enable BOOLEAN,
   time-code-control-flag-mode BOOLEAN,
   memory-error BOOLEAN
}

END


Create a function type named "Air Device" and set the language to CPP

ClipCapIt-200701-170208.PNG

This function type will have a generic code that will be able to read and write from any supported device. To do that it will be using a context parameter that will allow the user to set the device configuration per instance.

Set the context parameter defining the configuration

Double click on the function type and add a context parameter of the ASN.1 type named "IOP-Device-Identifier" as defined above.

Set a default value as it is mandatory, however this will be overwritten per instance.

ClipCapIt-200701-171255.PNG

Now edit the C++ code and fill in the code for the device initialization, polling and writing. This is an example:

#include "air_device.h"

// Include Context Parameters (constants defined in the Interface View)
#include "Context-air-device.h"

void air_device::startup()
{
   // Follow this pattern and fill in the actual code:    
   switch (air_device_ctxt.device_config.kind) {
       case eth_PRESENT:
           // Use AIR API to setup the socket using air_device_ctxt.device_config
           air_setup_eth();
           break;
       case grspw_PRESENT:
           air_setup_grspw();
           break;
       case can_PRESENT:
           air_setup_can();
           break;
       case spwrtr_PRESENT: // etc.
       case mil_PRESENT:
       default: 
           break;
   }
}

void air_device::Poll_Device(void)
{
   // Follow this pattern and fill in the actual code. Use the required interface
   // to send the data to the other partition...
   switch (air_device_ctxt.device_config.kind) {
       case eth_PRESENT:
           // Use AIR API to setup the socket using air_device_ctxt.device_config
           if (air_poll_eth()) {
               RI_Received_Data(...);  // Expected parameter is of ASN.1 type Data-Stream
           }
           break;
       case grspw_PRESENT: // etc.
       case can_PRESENT:
       case spwrtr_PRESENT: 
       case mil_PRESENT:
       default: 
           break;
   }
}

}
void air_device::Write_to_Device
      (const asn1SccData_Stream *IN_stream) 

{
   // Use the same pattern as above to write on the selected device
}

Export the type

Once you have completed the function type implementation, go back to the interface view, right-click on the function and choose "Export type". The folder should be by default ~/tool-inst/share/SharedTypes

The function will *disappear from the diagram* and appear here:

ClipCapIt-200701-173145.PNG

Save this project and keep it in a safe place, because you may later want to reuse it to modify the shared component. To do so, you need in the GUI to select the menu New and select "Import Shared Type". Select Air_Device and it will appear back in your local folder. You can change the component type from there and re-export it afterwards.

Instantiate the type in a new system

Create a new TASTE system

$ taste

and you will be able to instantiate the shared type by doing a drag'n'drop from the left menu:

ClipCapIt-200701-173641.PNG

Rename it, connect it to another function, and *very important*, go to the context parameter and set your actual device configuration.

ClipCapIt-200701-173755.PNG

You may have as many instances as you like, each of them having their own configuration.

Deploy the instances of Air_Device in a dedicated partition, the IO Partition

ClipCapIt-200701-174247.PNG

(The configuration of the TSP properties is not in the scope of this tutorial)


Set the appropriate linker flags to link the IO partition with the AIR API (if needed)

In the main makefile you may add a path to the code of the AIR API if you want it compiled together with the code of the partition, or simply a linker option to link with the pre-built library.

export IOPARTITION_EXTERNAL_SOURCE_PATH=...
export IOPARTITION_USER_LDFLAGS=-lair_api
export IOPARTITION_USER_CFLAGS=...