Using file I/O

Instead of using posix or OS specific functions, RTMaps has its own cross platform implementation for opening, reading files and writing into files.

Read from a file

MAPSFileReader allows to read from a file.

Example : read an entire file line by line :

MAPSFileReader file_reader;
bool cr = file_reader.Open("my_file.txt");
if (cr)
{
    MAPSString result;
    while (file_reader.NextLine(result))
    {
        // Process result
        MAPS::ReportInfo(result);
    }
    file_reader.Close();
}

Write to a file

MAPSFileWriter allows to write into a file. Example : write a simple text in a file

MAPSFileWriter file_writer;
bool cr = file_writer.Open("my_file.txt");
if (cr)
{
    MAPSString my_string("writing this content");
    file_writer.WriteText(my_string);
    file_writer.Close();
}

We can also write binary content :

// Binary buffer to write into a file
char buffer[1024];
for (unsigned int i = 0; i != 1024; i++)
{
    buffer[i] = i;
}
MAPSFileWriter file_writer;
bool cr = file_writer.Open("my_file.txt");
if (cr)
{
    file_writer.Write((void*) buffer, sizeof(buffer) );
    file_writer.Close();
}

 

 

SDK installation

Windows


On Windows, the SDK is installed with the installation wizard if you tick the SDK box.

If you own Microsoft Visual C++ Professional, the installation wizard will also install the RTMaps add-in.

Note that you can install or reinstall the add-in at anytime by running Windows Start / Intempora / RTMaps 4 / RTMaps SDK / (re)Install the add-ins for Visual studio

RTMaps development wizard

The RTMaps development wizard generates a ready-to-use basic component code!

With Visual C++ Professional

In that case, create an empty solution : [File] [New] [Project], then [Other Project types] [Visual Studio Solutions]. Once your solution is created, use [Tools] [RTMaps 4] [New RTMaps Package]. Give a name to your package, and then call [Tools] [RTMaps 4] [New RTMaps Module] for each new module you want to add in your package.

With Visual C++ Express

In that case, you will have to use the specific VC++ Express wizard. You have a full documentation here: Windows Start / Intempora / RTMaps 4 / RTMaps SDK / VC++ Express Wizard.

Linux

Under Linux there is a command line wizard. Type rtmaps_sdk_wizard --help to access to the wizard help.

To create a package, type :

# rtmaps_sdk_wizard --package my_package

This will create a package my_package.u in your user sdk directory (generally /home/your_name/rtmaps_sdk ).

To create a component, you have to specify your component's name and the package it should be put into. So :

# rtmaps_sdk_wizard --component my_package my_component

You will be asked for the type of component you want to create: simple component? Replay Record Method? Stream8 IO Component? In most cases a simple component is what you are looking for.

RTMaps containers

RTMaps has its own cross platform classic containers, like MAPSArray, MAPSList and MAPSHashTable.

Of course, you may prefer to use std::vector, std::list and std::map. But sometimes the platform your code will run into has not a sufficiently decent compiler. So why not use the RTMaps ones. They are pretty close to the STL ones, and guaranteed to run where RTMaps run.

Here are some of the available containers:

MAPSArray : This class implements a resizable one-dimensional array. If you know std::vector, then it won't take much effort to learn MAPS::Array. MAPSArray is actually a C++ array in a classic C++ style. MAPSArray is stored in contiguous memory and has random access possibility.

MAPSArray<int> vect;
vect.Push(10); // Add 10
vect.Push(11); // Add 11
vect.Push(12); // Add 12
vect.Pop(); // Removes 12
int count = 0;
for (int i = 0; i != vect.Size(); i++)
{
	count += vect[i];
}

MAPSList : This class is a double linked list. With MAPSList you can insert and remove elements inside with efficiency. MAPSList has a bidirectional access only, so you have better to use iterators when you must walk the entire container. Indeed, if you access the container with [], your code will walk through the list at each iteration, which is a solution with a huge overhead.

MAPSList<double> list;
list.PushBack(1.1); // Add 1.1 
list.PushBack(2.2); // Add 2.2
list.PushFront(0.4); // Add 0.4 at the front of the list
double item_to_find = 2.2; // Element to search for
MAPSList<double>::MAPSIterator pos;
for (MAPSList<double>::MAPSIterator iter(list); !iter.End(); ++iter)
{
	if (*iter == item_to_find) 
	{ // We found it !
		pos = iter;
	}
}
list.InsertAfter(pos, 3.3);

MAPSHashTable : This class stores associated key / content.

MAPSStringHashTable<int> HashTable(500);
HashTable.Insert("Hello",20);
HashTable.Insert("World",30);
HashTable.Insert("!",40);
int *res=HashTable.Lookup("Hello");
std::cout<<"res : "<<*res<<std::endl; // Prints 20
res=HashTable.Lookup("World");
std::cout<<"res : "<<*res<<std::endl; // Prints 30
HashTable.Remove("Hello");
res=HashTable.Lookup("Hello"); // Now res is NULL
MAPSHashTableIterator it(HashTable);
while (it)
{ // Print all the table, with key and content
	std::cout<<HashTable.Key(it)<<" = "<<HashTable.Content(it)<<std::endl;
	++it;
}

MAPSPair : This class stores a pair of elements that can be of different types.

MAPSPair<int, double> p;
p.Key() = 10;
p.Content() = 32.557;

MAPSCouple : This class stores two elements of the same type.

MAPSCouple<int> couple(2,3);

printf and std::cout, how to display the console in RTMaps ?

The simpler, the better. The best solution to show the console is to type in the parse input :

load Win32Console

for Windows, and

load UnixConsole

for Linux.

How to use OpenCV in a RTMaps component ?

OpenCV is a well known image library. This article covers how to use it in a RTMaps component.

Code include

You have to define the __IPL_H__ so that openCV does not define it twice. Indeed, RTMaps has already defined that structure.

#include "cv.h"
#define __IPL_H__
#include "maps.hpp" 
// Your code here

Catching exceptions

Like many C++ standard libraries, openCV throws an exception if something went wrong in your code. If an exception is thrown and you don't catch it, RTMaps will catch it for you but the component will be terminated, of course.

Here is a classic code showing how to catch exceptions:

void MyClass::my_function
{
    try
    {
        opencv_function(...); // exceptions can be thrown !!!
    }
    catch (const std::exception& e)
    {
        ReportInfo(e.what() );
    }
}

An exception should be caught with a const reference. As the openCV exception class inherits from std::exception, the upper code will definitely work, but you may prefer to use the native openCV class to have better error indications.

How to debug my RTMaps Component ?

This tutorial shows how to debug a freshly written component under Windows with Microsoft Visual C++.


With Microsoft Visual Studio

  • First of all, compile the project containing your RTMaps component in Debug mode. The .pck file will be generated in the .../packages/debug folder of your RTMaps SDK directory.

  • Make sure that this project is the active one (it appears in bold characters in the list of projects of the solution). Otherwise, right click on the project in the Solution explorer view, then choose “Set as StartUp project”.

  • Add breakpoints within your code where you want the debugger to pause the execution.

  • Start the debug session (F5). If you are asked to choose an executable, browse for rtmaps.exe in the bin folder of your RTMaps installation directory. (Do not pay attention if you are warned that RTMaps does not contain any debug information).

  • Register the previously compiled package file. (Make sure you register the Debug version and not the Release one).

  • Then run the diagram. When the execution reaches the first breakpoint, the debugger stops the execution and you can start step by step execution, but also watch at the variables, the call- stack, the memory state...

Under Linux, using DDD

  • Compile your package in debug mode: set the DEBUG environment variable to 1.
    export DEBUG=1

  • Launch ddd

  • In ddd, choose menu File | Open program..., then browse for the package.

  • In ddd, choose menu File | Open source..., then open your component source file and add breakpoints wherever you want to inside it.

  • Launch RTMaps independently from ddd.

  • Register your package in RTMaps (Make sure you register the Debug version and not the Release one).

  • In ddd, choose menu File | Attach to process..., then select rtmaps among the available processes.

  • Run the diagram. ddd should pause the execution when reaching one of your breakpoints.

Best practices

Use the RTMaps API !

In the today reality, good C++ compilers (standard compliant) are not available for all platforms, especially the embedded ones. In order to guarantee the code behavior on all platforms, RTMaps has its own cross-platform API. So if you want your code to be cross-platorm, we advise you to use it.

Here is a non exhaustive list of what you can find in the RTMaps API :

Container management

RTMaps has its own cross-platform containers like MAPSArray, MAPSList and so.

See RTMaps containers

File management

RTMaps provides easy ways to read from and into a file.

See Using file I/O

String management

RTMaps has its own string class that handles UTF-8 : MAPSString .

See Character strings in RTMaps

Thread management

RTMaps has its tools for creating threads (see Thread management ), synchronizing access between threads (see MAPSMutex - interthread synchronization) and inter-thread communication (see MAPSEvent - interthreads communication).

Always fill the Timestamp, never the Time of Issue !

The difference between the timestamp and the time of issue has been covered in the article Timestamp and Time of issue. While the timestamps has to be filled manually by the programmer, the time of issue is set automatically by RTMaps...

 

The timestamp of your MAPSIoElt is not filled automatically. The reason is simple, it can't be. There are lots of cases where RTMaps cannot guess what timestamp value to choose :

  • Multi inputs : you may want to choose a particular input and give that timestamp to the output.
  • Packets incoming : you may want to assign the same timestamp to all packets, or a different one for each elements inside the data packet.
  • etc.

In other words, this is your job to set the timestamp of your data ! This is very important because it carries the time origin of the data. Downstreams components may rely on your timestamp so don't forget to set it.

 

Example issued from the RTMaps SDK samples: this code reads an input and multiplies it by a factor stored in property.

void MAPSmultiplier1::Core() 
{
	//Request data on the input called "input".
	//This function will block until a new data is available on the input.
	//The MAPSIOElt class is the generic object that contains a piece of data 
	//(numbers, packets of bytes, images, etc...)
	MAPSIOElt* ioEltIn = StartReading(Input("input"));
	if (ioEltIn == NULL)
		return;

	//Get the integer contained in the MAPSIOElt object that has just been received.
	int valueIn = ioEltIn->Integer32();
	//Get the current value of the "factor" property (whose type is integer).
	int factor = (int)GetIntegerProperty("factor");
	//Compute the result.
	int result = valueIn *factor;

	//Output the result.
	//First get a MAPSIOElt object in which we can write the result to be output.
	//The StartWriting function is non-blocking.
	MAPSIOElt* ioEltOut = StartWriting(Output("output"));

	//Write the result in the MAPSIOElt object (MAPSIOElt::Integer32() returns a C++ 
	//reference to the contained integer).
	ioEltOut->Integer32() = result;

	//Transfer the timestamp (don't forget).
	ioEltOut->Timestamp() = ioEltIn->Timestamp();

	//Writing in the ioEltOut object is complete.
	//The only thing left is to release it and make it available 
	//to downstream components :
	StopWriting(ioEltOut);
}

In the line 28, the timestamp is just transfered from the input to the output !

Manipulating MAPSIOElt

Data is exchanged between the components through the one and only structure: MAPSIOElt. This structure can encapsulate any type of data and carry also additional information such as the Timestamp or the VectorSize.

Both the StartReading and the StartWriting functions return a pointer to a MAPSIOElt structure. You can read the data contained in a MAPSIOElt returned by a StartReading call, and you can write data into a MAPSIOElt returned by a StartWriting call.

Here are some useful methods of the MAPSIOElt class:

  • MAPSIOElt::Type: retrieves the type of data contained in the MAPSIOElt object. This function can be used in conjunction with MAPS::TypeFilter.
  • MAPSIOElt::Timestamp gets/sets the timestamp of the data. cf Timestamp and Time of issue
  • MAPSIOElt::TimeOfIssue: gets/sets the time of issue. cf Timestamp and Time of issue
  • MAPSIOElt::VectorSize: gets/sets the number of elements contained in the MAPSIOElt.
  • MAPSIOElt::BufferSize gets the maximum number of elements that can be contained in the MAPSIOElt.
  • Integer(int index=0), Integer64( int index=0), Float32(int index=0), Float64(int index=0), Stream8(), IplImage(), MAPSImage(),CANFrame( int index=0), ...: access to the data itself.
  • MAPSIOElt::Frequency: for sampled signals, you can set/get the sampling frequency using this field. This frequency is expressed in mHz.
  • MAPSIOElt::Quality, Misc: use this fi eld to get/set additional information for particular data.

 

RTMaps macros: inputs, outputs and properties (part I)

Let's recall in this tutorial how to define component inputs, outputs and properties with RTMaps macros.

Inputs

The inputs are declared between the macros MAPS_BEGIN_INPUTS_DEFINITION and MAPS_END_INPUTS_DEFINITION. Each input should be declared with this macro:

MAPS_INPUT(NAME, FILTER_TYPE, FIFO_TYPE)

where:

  • NAME: name of the input, with quotes. Example: "input".
  • FILTER_TYPE: this is a filter! It specifies what data types this input accepts. The input has the capacity to filter either a single type (integer 32 bit for example), a large set of types (number types: float, int, 32 or 64 bit) or even all types. Filters can be combined using the | symbol (see example below).
  • FIFO_TYPE: type of the fifo (Fifo reader, sampling reader...). See Reader types.

Let's see an example of an 32 bit integer input declaration, named "input":

MAPS_BEGIN_INPUTS_DEFINITION(MAPSmultiplier1)
    MAPS_INPUT("input",MAPS::FilterInteger32|FilterInteger64,MAPS::FifoReader)
MAPS_END_INPUTS_DEFINITION

Here is a list of the main filters available:

  • FilterIntegers32
  • FilterIntegers64
  • FilterFloats32
  • FilterFloats64 | FilterDoubles: they are completely equivalent
  • FilterNumbers: any number (float, int, 32 or 64 bit)
  • FilterTextUTF8: text (FilterTextAscii in RTMaps version 3)
  • FilterIplImage
  • FilterCANFrame
  • FilterStream8: raw data (char*)

 

Outputs

The outputs are declared between the macros MAPS_BEGIN_OUTPUTS_DEFINITION and MAPS_END_OUTPUTS_DEFINITION. Each output is declared using this macro:

MAPS_OUTPUT(NAME, TYPE, NULL, NULL, SIZE)

where:

  • NAME: name of the output.
  • TYPE: the output type must be specified.
  • SIZE: number of elements in the vector.

Here is an example of a integer 32 bit output, named "output".

MAPS_BEGIN_OUTPUTS_DEFINITION(MAPSmultiplier1)
    MAPS_OUTPUT("output",MAPS::Integer32,NULL,NULL,1)
MAPS_END_OUTPUTS_DEFINITION

 

Here is a list of the main output types available:

  • Integer32
  • Integer64
  • Float32
  • Float64
  • TextUTF8
  • IplImage
  • CANFrame
  • Stream8

 

Properties

Properties are declared between the macros MAPS_BEGIN_PROPERTIES_DEFINITION and MAPS_END_PROPERTIES_DEFINITION. There are two kinds of properties: standard properties offer a text box where the user types the required value, and enumerated properties offer a limited set of choices in a drop-down list. Enumerated properties will be covered by a specific article, and the following describes standard properties only.

Each standard property is declared using:

MAPS_PROPERTY(
    NAME, 
    DEFAULT_VALUE, 
    NEEDS_TO_BE_INITIALIZED, 
    CAN_BE_CHANGED_DURING_EXECUTION)

where:

  • NAME: name of the property
  • DEFAULT_VALUE: the default value of the property. Correctly setting this value is very important because RTMaps infers the type of the property from this default value. Examples:
    • 2: the property will be an integer
    • 2.0: the property will be a double (there is no float32 in properties, for simplicity)
    • false: the property will be a boolean.
    • "hello": the property will be a text. Warning: if you use a character
  • NEEDS_TO_BE_INITIALIZED: boolean. True if the user must set a value before running the diagram (if the user tries to run the diagram before setting this property, the diagram will not run and a warning window will pop). Most of the time, this should be "false".
  • CAN_BE_CHANGED_DURING_EXECUTION: boolean. True if the property can be changed when the diagram is running. False otherwise.

Here is an example of a integer property, named "factor".

MAPS_BEGIN_PROPERTIES_DEFINITION(MAPSmultiplier1)
    MAPS_PROPERTY("factor",2,false,true)
MAPS_END_PROPERTIES_DEFINITION