Skip to main content

Generate and Implement a CSI-to-CSI Message Transform

Tangram Pro™ provides a tool set for software and system engineers to rapidly integrate new components into their systems with confidence. In a perfect world, all the components we'd want to integrate would all speak the same language, operate on the same message protocols, but this isn't always the case. What if we want to integrate a new component that speaks Message Type B, but our existing components speak Message Type A?

Our engineers at Tangram Flex have written, and continue to add, many transforms that are built into Tangram Pro™. These transforms are automatically applied to your system when you connect components that contain different, compatible message types. In this tutorial we will utilize the built-in transform that converts a STANAG4586 InertialStates message into an LMCP AirVehicleState message. We'll test the generated transform app and visualize it in real-time with a simulated UAV.

You'll learn how to:

  • Design a system that includes a transform
  • Generate a complete "bump-in-the-line" CSI-to-CSI Message Transform
  • Run an end-to-end test of the transform app
  • Utilize the ZeroMQ transport
  • Visualize the system's behavior with OpenAMASE
tip

You can also define your own transforms (and messages) using the Flex authorship feature. Check out our Flex Docs to learn more. Flex enables accurate transform specification and can be transpiled into a variety of languages and output formats. When a transform is written in Flex, the author can be confident that the code will only do what it is intended to do because of the formal mathematical specification behind the language design.

Step 1: Design a System with a Built-in Transform

First, let's build out the components needed for our system. In this step you'll create a parent component and two subcomponents, and then connect the subcomponents together.

Create a parent component

  1. Navigate to the Component Library
  2. Click + New Component
    • Enter Component Name: Transform_Workspace
    • Select Category: System
    • Select your Team
  3. Click Create Component
  4. Click + Add Implementation
    • Enter Implementation Name: impl
  5. Click Create Implementation
  6. Lastly, click Open Workspace

Now that we're in the workspace, let's add two subcomponents to our system.

Create an LMCP subcomponent

  1. In the workspace, click the Component Library icon in the left menu
  2. Click + New Component
  3. Enter Component Name: Transform_LMCP
  4. Choose category System
  5. Select your Team
  6. Click Next
  7. Click Add Port and select:
    • Message Set: OpenUxAS::LMCP
    • Message: AirVehicleConfiguration
    • Direction: In/Out
    • Type: Data
  8. Click Add Port again and select:
    • Message Set: OpenUxAS::LMCP
    • Message: AirVehicleState
    • Direction: In/Out
    • Type: Data
  9. Click Next
  10. Enter Implementation Name: impl
  11. Click Create Implementation
  12. Drag and drop it into the workspace

Create a STANAG4586 subcomponent

  1. In the workspace, click the Component Library icon in the left menu
  2. Click + New Component
  3. Enter Component Name: Transform_STANAG4586
  4. Choose category System
  5. Select your Team
  6. Click Next
  7. Click Add Port and select:
    • Message Set: NATO::STANAG4586
    • Message: InertialStates
    • Direction: In/Out
    • Type: Data
  8. Click Next
  9. Enter Implementation Name: impl
  10. Click Create Implementation
  11. Drag and drop it into the workspace

Your system should look similar to this.

Components

Create a Connection

  1. Click the Make Connection circle in the middle of the Transform_STANAG4586.impl component block
  2. Then click the Make Connection circle in the middle of the Transform_LMCP.impl component block
  3. Click + New Connection
  4. Select the STANAG4586 Port: InertialStates
  5. Then select the LMCP Port: AirVehicleState
  6. A message should automatically appear that says Transform is available
  7. Click the Done button at the top

Connection

Step 2: Generate CSI-to-CSI Message Transform

Now that we have our system created, we're going run a specialized workflow that performs all the steps necessary for a complete "bump-in-the-line" transform. The result will be a build artifact that contains the 2 generated and built CSIs as well as a generated and built transform app. The transform app is a standalone executable. It starts up a loop that performs the following actions:

  • Read an incoming message.
  • Deserialize the message bytes received into a message object (C++ object).
  • Transform the message object into the desired destination type (another C++ object).
  • Serialize the message populated in the previous step.
  • Send the outgoing message.

Let's get started!

Create Workflow

  1. In the workspace, click the Workflows icon in the left menu
  2. Click + New Workflow
  3. Enter name: CSI Message Transform
  4. Click Create Workflow
  5. Click on the newly created workflow
  6. Click + Tasks
  7. Drag and drop the Available Transforms block (InertialStates | AirVehicleState) into the right area
  8. Click Save Changes
  9. Click the Close button at the top right
  10. Now click Run!

Transform Workflow

tip

This may take several minutes to complete. You can proceed to the next step, and the task will continue to run in the background.

Step 3: Generate LMCP CSI

In the previous step, the generated transform app will handle transforming a STANAG4586 InertialStates message into an LMCP AirVehicleState message. However, we'll also need a CSI that includes the LMCP AirVehicleConfiguration message in order to setup our UAV in OpenAMASE. Let's generate it!

Open the LMCP Component Workspace

  1. Return to the main workspace by clicking the back arrow in the top left of the Workflows panel
  2. Then click the three dots in the Transform_LMCP.impl component block and click Open New Tab

Create Workflow

  1. Click the Workflows icon in the left menu
  2. Click + New Workflow
  3. Enter name: LMCP CSI
  4. Click Create Workflow
  5. Click on the newly created workflow
  6. Click + Tasks
  7. Drag and drop the Code Gen 3.0 plugin into the right area
  8. Drag and drop the G++ plugin into the right area
  9. Click the gear icon in the G++ block
  10. Select Configuration: Makefile Compilation
  11. Click Done

Add Dependency

Now let's make a dependency between the two plugins to ensure the G++ task runs after Code Gen 3.0 completes.

  1. Click the connection icon in the Code Gen 3.0 block
  2. Then click anywhere in the G++ block
  3. You should now see line between the two plugins
  4. Click Save Changes
  5. Click the Close button at the top right
  6. Now click Run!

Code Gen Workflow

Step 4: Gather Code

Download Generated Artifacts

  1. When the LMCP CSI workflow completes, download the G++ artifact

    Code Gen Artifact

  2. When the CSI Message Transform workflow completes, the download the Transform artifact

    Transform Artifact

  3. Extract both files. You should have a code-gen-3 folder and out folder.

Download Additional Resources

To test the generated transform app, we'll need a C++ application that uses Tangram LMCP and STANAG4586 CSIs and associated transform to send data to OpenAMASE. As well as a ZeroMQ proxy.

  1. Go to our Tangram Flex transformer-app-demo repository on GitHub
  2. Click to green Code button, Download ZIP, and extract the ZIP file
  3. Update the name of the extracted folder to transformer-app-demo
  4. Go to our Tangram Flex ZeroMQProxy repository on GitHub and repeat
  5. Update the name of the extracted folder to ZeroMQProxy

Move Folders

  1. Create a new folder called TransformResources
  2. Move the ZeroMQProxy folder into TransformResources
  3. Move the transformer-app-demo folder into TransformResources
  4. Move the code-gen-3 folder into the transformer-app-demo folder
  5. And move the out folder into the transformer-app-demo folder

The result should be a folder structure similar to this:

- TransformResources - ZeroMQProxy - transformer-app-demo - code-gen-3 - out

Step 5: Setup your Testing Environment

Now that we have gathered all our code, let's setup a shared folder in the virtual machine to access it.

important

If you haven't already, follow this tutorial to create an Ubuntu 20.04 LTS virtual machine using VirtualBox, and install OpenAMASE and OpenUxAS. If you're already using a Linux machine you may skip the next Create Shared Folder & Move Folders steps.

Create Shared Folder

  1. In the OracleVMVirtualBox Manager select Tangram CSI Test
  2. Click the Settings icon
  3. Click the Shared Folders icon
  4. Click the Add new shared folder icon on the far right
  5. Click the Folder Path dropdown mend and select Other...
  6. Select your TransformResources folder and click Open
  7. Select Auto-mount
  8. Click OK
  9. Click OK again

Move Folders

  1. Launch the VM
  2. Open Files
  3. Click on the mounted folder sf_TransformResources
  4. Copy the transformer-app-demo folder
  5. Click Home and paste
  6. Return to the mounted folder sf_TransformResources
  7. Copy the ZeroMQProxy folder
  8. Click Home and paste

Install ZeroMQ

  1. Open Terminal
  2. Enter this command to install ZeroMQ
bash
sudo apt-get install libzmq3-dev
  1. Enter your VM user password if prompted

Build ZeroMQProxy

  1. Change directory to ZeroMQProxy
bash
cd ~/ZeroMQProxy
  1. Build the app
bash
make

Build the Receiver App

  1. Change directory to the transformer-app-demo
bash
cd ~/transformer-app-demo
  1. Create the following symbolic links:
bash
ln -s code-gen-3 lmcp
ln -s out/stanag4586/ stanag4586
  1. Build the receiver app
bash
make
  1. You should now see a receiver binary, in addition to the receiver.cpp file
important

There is a "Provider" class that temporarily needs to be modified in order to run the transform. Follow the steps below to prevent this error from occurring.

*** ERROR: Contextual parameters not populated in file Provider_Stanag4586InertialStatesToLmcpAirVehicleState_AirVehicleStateInfo.hpp! Aborted (core dumped)
  1. Open Files
  2. Navigate to transformer-app-demo > out > transform
  3. Open the file called Provider_Stanag4586InertialStatesToLmcpAirVehicleState_AirVehicleStateInfo.hpp in an IDE or Text Editor
  4. Comment out lines 16 and 17. The result should look similar to this:
// fprintf(stderr, "*** ERROR: Contextual parameters not populated in file Provider_Stanag4586InertialStatesToLmcpAirVehicleState_AirVehicleStateInfo.hpp!\n"); // abort();
  1. Save the changes
  2. Open Terminal
  3. Change directory to transformer-app-demo/out/transform
bash
cd ~/transformer-app-demo/out/transform
  1. Re-build the transform app
bash
make

Step 6: Test your CSI-to-CSI Message Transform

Now that we have the necessary files in place and built, let's test it out!

Start OpenAMASE and Select a Scenario

  1. Enter the following commands in Terminal to launch OpenAMASE
bash
cd ~/OpenAMASE/OpenAMASE/run/linux
sh Common.sh "--config" "config/amase"
  1. Then, in OpenAMASE, go to File > Open Scenario
  2. At the top, select the home/< your username > folder
  3. Double click OpenUxAS/
  4. Double click examples/
  5. Double click 02_Example_WaterwaySearch/
  6. On the right, select Scenario_WaterwaySearch then click OK
  7. Click the play button to start the scenario

Start ZeroMQProxy

  1. Click the + icon to open an additional Terminal tab
  2. Change directory to ZeroMQProxy
bash
cd ~/ZeroMQProxy
  1. Run the proxy
bash
./zmq_proxy tcp://*:6667 tcp://*:6668

Start Transform App

  1. Open an additional Terminal tab
  2. Change directory to transformer-app-demo/out/transform
bash
cd ~/transformer-app-demo/out/transform
  1. Run the transform app
bash
LD_LIBRARY_PATH=../lmcp/pkg_deps/genericapi/pkg_deps/transports-cpp/build/libs/ZeroMQ/ ./transform

Start Receiver App

  1. Open an additional Terminal tab
  2. Change directory to transformer-app-demo
bash
cd ~/transformer-app-demo
  1. Run the receiver app
bash
LD_LIBRARY_PATH=out/lmcp/pkg_deps/genericapi/pkg_deps/transports-cpp/build/libs/ZeroMQ/ ./receiver

You should start seeing message data output here. Back in OpenAMASE you should now see a Tangram UAV appear and fly around!

Transform UAV

Cheers!

By completing this tutorial, you've learned to implement the transform and CSIs generated by Tangram Pro™ in a local testing environment! OpenAMASE is only able to fly a simulated UAV when it receives properly formatted and serialized LMCP AirVehicleState messages. So we know the transformation from STANAG4586 InertialStates to LMCP AirVehicleState was successful.

Check out what you accomplished:

  • Designed a system using a built-in transform
  • Leveraged the transform app and CSIs generated by Tangram Pro™ to convert STANAG4586 InertialStates to LMCP AirVehicleState
  • Utilized the ZeroMQ transport
  • Ran an end-to-end test of the transform app
  • Visualized the behavior of your system using OpenAMASE
note

Check out Discuss, our Tangram Flex community and find out more about generating CSIs with a CSIP.