blob: 62e63a0b67825788680428df68f37dfb7f9a0e1a [file] [log] [blame]
[comment encoding = UTF-8 /]
[comment]
/*****************************************************************************
* Copyright (c) 2013 INTEMPORA S.A.
*
* This software is a computer program whose purpose is to transform RobotML models
* into RTMaps diagrams and RTMaps components via source code generation techniques.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Nicolas DU LAC (INTEMPORA) - Initial API and implementation
*
*****************************************************************************/
[/comment]
[module generate_rtmaps_component_cpp('http://www.eclipse.org/uml2/3.0.0/UML', 'http://Papyrus/RobotML/1')]
[import org::eclipse::papyrus::robotml::generators::common::mmqueries::GeneralQueries /]
[import org::eclipse::papyrus::robotml::generators::common::mmqueries::ArchitectureQueries /]
[import org::eclipse::papyrus::robotml::generators::common::mmqueries::DataTypeQueries /]
[import org::eclipse::papyrus::robotml::generators::intempora::rtmaps::RTMapsDataTypeQueries /]
[template public generateRTMapsComponentCpp(c : Class, root_model : Model)]
[file ('user_sdk/' + root_model.name + '.u/src/maps_' + c.name + '.cpp', false, 'UTF-8')]
#include "maps_[c.name/].h"
// [protected ('Additional includes')]
// [/protected]
// Use the macros to declare the inputs
MAPS_BEGIN_INPUTS_DEFINITION(MAPS[c.name/])
[let elt : Element = c.oclAsType(Element)]
[for (port : Port | getInputPortsForElement(elt))]
[if (isPrimitiveType(port.type))]
[getRTMapsInputDefForPrimitiveType(port.name, port.type.name)/]
[else]
MAPS_INPUT("[port.name/]",MAPSFilter[port.type.name/],MAPS::FifoReader)
[/if]
[/for]
[/let]
// [protected ('Additional input definitions')]
// [/protected]
MAPS_END_INPUTS_DEFINITION
// Use the macros to declare the outputs
MAPS_BEGIN_OUTPUTS_DEFINITION(MAPS[c.name/])
[let elt : Element = c.oclAsType(Element)]
[for (port : Port | getOutputPortsForElement(elt))]
[if (isPrimitiveType(port.type))]
[getRTMapsOutputDefForPrimitiveType(port.name, port.type.name, port.upper)/]
[else]
//Declare a vector of max 0 elements in order to be able to handle the output buffers
//allocation "manually" later (in ::Birth()).
MAPS_OUTPUT_USER_STRUCTURES_VECTOR("[port.name/]",[port.type.name/], 0)
[/if]
[/for]
[/let]
// [protected ('Additional output definitions')]
// [/protected]
MAPS_END_OUTPUTS_DEFINITION
// Use the macros to declare the properties
MAPS_BEGIN_PROPERTIES_DEFINITION(MAPS[c.name/])
// [protected ('Additional property definitions')]
// [/protected]
MAPS_END_PROPERTIES_DEFINITION
// Use the macros to declare the actions
MAPS_BEGIN_ACTIONS_DEFINITION(MAPS[c.name/])
// [protected ('Additional action definitions')]
// [/protected]
MAPS_END_ACTIONS_DEFINITION
// Use the macros to declare this component ([c.name/]) behaviour
MAPS_COMPONENT_DEFINITION(MAPS[c.name/],"[c.name/]","1.0",128,
MAPS::Threaded,MAPS::Threaded,
-1, // Nb of inputs. Leave -1 to use the number of declared input definitions
-1, // Nb of outputs. Leave -1 to use the number of declared output definitions
-1, // Nb of properties. Leave -1 to use the number of declared property definitions
-1) // Nb of actions. Leave -1 to use the number of declared action definitions
// [protected ('Overloaded methods from MAPSComponent (Dynamic, Set...')]
// [/protected]
//***********************************************
// INITIALIZATION FUNCTION.
// CALLED ONCE AT DIAGRAM EXECUTION START.
//***********************************************
void MAPS[c.name/]::Birth()
{
[if getOutputPortsForElement(c.oclAsType(Element))->size() > 0]
//********************************************************************
//Output buffers allocation
//Performed "by hand" (the code is quite ugly but it is
//the only way for the most generic cases we have to deal with
//in RobotML).
//********************************************************************
[for (port : Port | getOutputPortsForElement(c.oclAsType(Element)))]
[if (isPrimitiveType(port.type) = false)]
_[port.name/]_buffers.Clear();
MAPSIOMonitor &monitor_[port.name/]=Output([i-1/]).Monitor();
MAPSFastIOHandle it_[port.name/];
it_[port.name/]=monitor_[port.name/].InitBegin();
while (it_[port.name/]) {
MAPSIOElt &IOElt_[port.name/]=monitor_[port.name/]['['/]it_[port.name/][']'/];
IOElt_[port.name/].Data() = (void*) new [port.type.name/]['[1]'/]; //TODO: replace 1 by port.upper.
if (IOElt_[port.name/].Data() == NULL)
Error("Not enough memory.");
_[port.name/]_buffers.Append(([port.type.name/]*)IOElt_[port.name/].Data());
monitor_[port.name/].InitNext(it_[port.name/]);
}
[/if]
[/for]
[/if]
[if getInputPortsForElement(c.oclAsType(Element))->size() > 0]
//Initialize a member array containing pointers to the component inputs for
//use in the Core() function with the asynchronous StartReading.
_nb_inputs = [getInputPortsForElement(c.oclAsType(Element))->size()/];
_inputs = new MAPSInput*['[_nb_inputs]'/];
for (int i=0; i<_nb_inputs; i++) {
_inputs['[i]'/] = &Input(i);
}
[/if]
// [protected ('User-specific initalizations')]
// [/protected]
}
//****************************************************************************
// Core() IS THE MAIN EXECUTION LOOP FUNCTION.
// THE ONE AND ONLY BLOCKING CALL IN HERE SHALL BE THE StartReading function.
//****************************************************************************
void MAPS[c.name/]::Core()
{
[if getInputPortsForElement(c.oclAsType(Element))->size() > 0]
//Without specification of reading policies, let's implement the most generic case:
//an asynchronous blocking read on all the inputs.
int input_that_answered;
MAPSIOElt* ioelt_in = StartReading(_nb_inputs, _inputs, &input_that_answered);
if (ioelt_in == NULL)
return;
MAPSTimestamp timestamp_in = ioelt_in->Timestamp();
switch (input_that_answered) {
[for (port : Port | getInputPortsForElement(c.oclAsType(Element)))]
case [i-1/]: //We received an element from port [port.name/].
{
[getNbElementsInVector(port.type.name,'ioelt_in','count')/]
[getMAPSIOEltAccessFunction(port.type.name,'ioelt_in','data_in')/]
[port.type.name/]_Received_on_[port.name/]_InPort(data_in,count, ioelt_in->Timestamp());
}
break;
[/for]
default:
Error("Unknown input.");
}
// [protected ('Core processing')]
// [/protected]
[else]
//There are no inputs to read from in this component.
//Make sure you have one and only blocking function (Rest, Wait, MAPS::Sleep, select, whatever...)
//inside Core().
// [protected ('Core processing with no inputs')]
Wait4Event(isDyingEvent); //Pause the current thread until shutdown.
// [/protected]
[/if]
}
[if getInputPortsForElement(c.oclAsType(Element))->size() > 0]
//**********************************************************************************************
// INPUT METHODS CALLED FROM THE Core() METHOD WHENEVER A SAMPLE IS RECEIVED ON AN INPUT PORT
// NOTE THAT IN CORE, OTHER SAMPLING STRATEGIES COULD BE AVAILABE (SYNCHRONIZED, TRIGGERED, RESAMPLING...)
// BUT ARE NOT IMPLEMENTED YET.
//**********************************************************************************************
[for (port : Port | getInputPortsForElement(c.oclAsType(Element)))]
//This callback will be called each time a new sample is received on the corresponding input port.
void MAPS[c.name/]::[port.type.name/]_Received_on_[port.name/]_InPort([port.type.name/]* data_in, int count, MAPSTimestamp t)
{
// [protected ('Processing code for samples received on ' + port.type.name)]
// [/protected]
}
[/for]
[/if]
[if getOutputPortsForElement(c.oclAsType(Element))->size() > 0]
//**********************************************************************************************
// OUTPUT METHODS TO BE CALLED BY THE PROGRAMMER FOR EMITTING A SAMPLE ON AN OUTPUT PORT.
//**********************************************************************************************
[for (port : Port | getOutputPortsForElement(c.oclAsType(Element)))]
//To be completed by programmer, then called by programmer whenever necessary in order to
//output a data sample on output port [port.name/]
void MAPS[c.name/]::Output_[port.name/](MAPSTimestamp t)
{
MAPSIOElt* ioeltout = StartWriting(Output("[port.name/]"));
// [protected ('Output on ' + port.name + ' implementation')]
int count_[port.type.name/]_out = 1; //changed it to the number of samples to write in output MAPSIOElt
//(but never more than the max vector size allocated on the output).
[getMAPSIOEltAccessFunction(port.type.name,'ioeltout','data_out')/]
//Fill in data_out here.
//....
[if (isPrimitiveType(port.type) = false)]
ioeltout->VectorSize() = count_[port.type.name/]_out * sizeof([port.type.name/]); //For non-standard datatypes, by convention,
[else]
ioeltout->VectorSize() = count_[port.type.name/]_out; //Number of elements in output vector (not number of bytes).
[/if]
// [/protected]
ioeltout->Timestamp() = t;
StopWriting(ioeltout);
}
[/for]
[/if]
//**********************************************************************************************
// RELEASE FUNCTION.
// CALLED ONCE WHEN DIAGRAMS STOPS EXECUTING OR AFTER A CALL TO Error("..."); IN Birth OR Core.
//**********************************************************************************************
void MAPS[c.name/]::Death()
{
// [protected ('Death implementation')]
// [/protected]
}
[if getOutputPortsForElement(c.oclAsType(Element))->size() > 0]
//*******************************************************************************************************************
// OVERLOADED METHOD: WILL BE CALLED AT DIAGRAM EXECUTION SHUTDOWN ONCE ALL THE COMPONENTS HAVE GONE THROUGH Death().
// THIS IS THE PLACE WHERE TO RELEASE BUFFERS THAT WERE DYNAMICALLY ALLOCATED BY THE PROGRAMMER IN BIRTH.
//*******************************************************************************************************************
void MAPS[c.name/]::FreeBuffers()
{
//Let's release the memory we allocated on the output buffers.
[let elt : Element = c.oclAsType(Element)]
[for (port : Port | getOutputPortsForElement(elt))]
[if (isPrimitiveType(port.type) = false)]
MAPSListIterator it_[port.name/];
MAPSForallItems(it_[port.name/],_[port.name/]_buffers) {
delete ['[]'/] _[port.name/]_buffers['['/]it_[port.name/] [']'/];
}
_[port.name/]_buffers.Clear();
[/if]
[/for]
[/let]
MAPSComponent::FreeBuffers();
}
[/if]
// [protected ('Additional methods for MAPS' + c.name)]
// [/protected]
[/file]
[/template]