blob: 223cf131d54f7c63296956214ef34b3c9ff654c8 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011 Draeger Medical GmbH (http://www.draeger.com).
* 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:
* Peter Karlitschek (initial contribution)
*
*******************************************************************************/
package org.eclipse.etrice.generator.cpp.gen
import com.google.inject.Inject
import com.google.inject.Singleton
import java.util.List
import org.eclipse.etrice.core.genmodel.etricegen.Root
import org.eclipse.etrice.core.genmodel.fsm.base.ILogger
import org.eclipse.etrice.core.room.CommunicationType
import org.eclipse.etrice.core.room.InterfaceItem
import org.eclipse.etrice.core.room.Message
import org.eclipse.etrice.core.room.Port
import org.eclipse.etrice.core.room.PortClass
import org.eclipse.etrice.core.room.ProtocolClass
import org.eclipse.etrice.core.room.SAP
import org.eclipse.etrice.core.room.SPP
import org.eclipse.etrice.generator.cpp.Main
import org.eclipse.etrice.generator.fsm.base.FileSystemHelpers
import org.eclipse.etrice.generator.fsm.base.IGeneratorFileIo
import org.eclipse.etrice.generator.generic.GenericProtocolClassGenerator
import org.eclipse.etrice.generator.generic.ProcedureHelpers
import org.eclipse.etrice.generator.generic.RoomExtensions
import org.eclipse.etrice.generator.generic.TypeHelpers
@Singleton
class ProtocolClassGen extends GenericProtocolClassGenerator {
@Inject IGeneratorFileIo fileIO
@Inject extension CppExtensions stdExt
@Inject extension RoomExtensions roomExt
@Inject extension ProcedureHelpers helpers
@Inject extension TypeHelpers
@Inject extension FileSystemHelpers
@Inject Initialization initHelper
@Inject ILogger logger
def doGenerate(Root root) {
for (pc: root.usedProtocolClasses.filter(cl|cl.isValidGenerationLocation)) {
val path = pc.generationTargetPath+pc.getPath
val infopath = pc.generationInfoPath+pc.getPath
switch (pc.commType) {
case CommunicationType::EVENT_DRIVEN:{
fileIO.generateFile("generating ProtocolClass declaration", path, infopath, pc.cppHeaderFileName, root.generateHeaderFile(pc))
fileIO.generateFile("generating ProtocolClass implementation", path, infopath, pc.cppSourceFileName, root.generateSourceFile(pc))
}
case CommunicationType::DATA_DRIVEN:{
fileIO.generateFile("generating ProtocolClass declaration", path, infopath, pc.cppHeaderFileName, root.generateDataDrivenHeaderFile(pc))
fileIO.generateFile("generating ProtocolClass implementation", path, infopath, pc.cppSourceFileName, root.generateDataDrivenSourceFile(pc))
}
case CommunicationType::SYNCHRONOUS:
logger.logError("synchronous protocols not supported yet", pc)
}
}
}
def protected generateHeaderFile(Root root, ProtocolClass pc) {'''
/**
* @author generated by eTrice
*
* Header File of ProtocolClass «pc.name»
*
*/
«generateIncludeGuardBegin(pc, '')»
#include "common/modelbase/InterfaceItemBase.h"
#include "common/modelbase/PortBase.h"
#include "common/modelbase/ReplicatedInterfaceItemBase.h"
#include "common/modelbase/ReplicatedPortBase.h"
#include "common/etDatatypesCpp.hpp"
«FOR dataClass : root.getReferencedDataClasses(pc)»
#include "«dataClass.path»«dataClass.name».h"
«ENDFOR»
«pc.userCode1.userCode»
«pc.generateNamespaceBegin»
class «pc.name» {
public:
/* message IDs */
«genMessageIDs(pc)»
«pc.userCode(2)»
static bool isValidEvtID(int evtId) {
return ((MSG_MIN < evtId) && (evtId < MSG_MAX));
}
static bool isValidOutgoingEvtID(int evtId) {
return ((MSG_MIN < evtId) && (evtId < «IF pc.incomingMessages.size == 0»MSG_MAX«ELSE»IN_«pc.incomingMessages.get(0).name»«ENDIF»));
}
static bool isValidIncomingEvtID(int evtId) {
return ((«IF pc.incomingMessages.size == 0»MSG_MAX«ELSE»IN_«pc.incomingMessages.get(0).name»«ENDIF» <= evtId) && (evtId < MSG_MAX));
}
static const etRuntime::String& getMessageString(int msg_id);
private:
static const etRuntime::String s_messageStrings[];
};
«portClassDeclaration(pc, false)»
«portClassDeclaration(pc, true)»
«pc.generateNamespaceEnd»
«generateIncludeGuardEnd(pc, '')»
'''
}
def protected portClassDeclaration(ProtocolClass pc, boolean conj) {
var pclass = pc.getPortClass(conj)
var portClassName = pc.getPortClassName(conj)
var replPortClassName = pc.getPortClassName(conj, true)
'''
//------------------------------------------------------------------------------------------------------------
// «IF conj»conjugated «ENDIF»port class
//------------------------------------------------------------------------------------------------------------
class «portClassName» : public etRuntime::PortBase {
«IF pclass!=null»
«pclass.userCode.userCode»
«ENDIF»
public:
«portClassName»(etRuntime::IInterfaceItemOwner* actor, const etRuntime::String& name, int localId);
«portClassName»(etRuntime::IInterfaceItemOwner* actor, const etRuntime::String& name, int localId, int idx);
«IF Main::settings.generateMSCInstrumentation»
virtual void destroy();
«ENDIF»
virtual void receive(const etRuntime::Message* m);
«IF pclass!=null»
«pclass.attributes.attributes»
«pclass.operations.operationsDeclaration(portClassName)»
«ENDIF»
// sent messages
«FOR m : pc.getAllMessages(conj)»
«messageSignature(m, false)»;
«messageSignature(m, true)»;
«ENDFOR»
};
//------------------------------------------------------------------------------------------------------------
// «IF conj»conjugated «ENDIF»replicated port class
//------------------------------------------------------------------------------------------------------------
class «replPortClassName» : public etRuntime::ReplicatedPortBase {
public:
«replPortClassName»(etRuntime::IInterfaceItemOwner* actor, const etRuntime::String& name, int localId);
int getReplication() const { return getNInterfaceItems(); }
int getIndexOf(const etRuntime::InterfaceItemBase& ifitem) const { return ifitem.getIdx(); }
«portClassName»& get(int idx) const { return *dynamic_cast<«portClassName»*>(getInterfaceItem(idx)); }
«IF conj»
// incoming messages
«FOR m : pc.getAllIncomingMessages()»
«messageSignature(m, false)»;
«ENDFOR»
«ELSE»
// outgoing messages
«FOR m : pc.getAllOutgoingMessages()»
«messageSignature(m, false)»;
«ENDFOR»
«ENDIF»
protected:
virtual etRuntime::InterfaceItemBase* createInterfaceItem(etRuntime::IInterfaceItemOwner* rcv, const etRuntime::String& name, int lid, int idx) {
return new «portClassName»(rcv, name, lid, idx);
}
};
'''
}
def protected generateSourceFile(Root root, ProtocolClass pc) {'''
/**
* @author generated by eTrice
*
* Source File of ProtocolClass «pc.name»
*
*/
#include "«pc.getCppHeaderFileName»"
#include "common/debugging/DebuggingService.h"
#include "common/debugging/MSCFunctionObject.h"
#include "common/messaging/AbstractMessageReceiver.h"
#include "common/messaging/Address.h"
#include "common/messaging/Message.h"
#include "common/modelbase/IEventReceiver.h"
using namespace etRuntime;
«pc.generateNamespaceBegin»
«pc.userCode(3)»
/* message names as strings for debugging (generate MSC) */
const String «pc.name»::s_messageStrings[] = {"MIN", «FOR m : pc.getAllOutgoingMessages()»"«m.name»",«ENDFOR» «FOR m : pc.getAllIncomingMessages()»"«m.name»",«ENDFOR»"MAX"};
const String& «pc.name»::getMessageString(int msg_id) {
if ((MSG_MIN < msg_id ) && ( msg_id < MSG_MAX )) {
return s_messageStrings[msg_id];
} else {
// id out of range
static const String errorMsg = "Message ID out of range";
return errorMsg;
}
}
«portClassImplementation(pc, false)»
«portClassImplementation(pc, true)»
«pc.generateNamespaceEnd»
'''
}
def protected portClassImplementation(ProtocolClass pc, boolean conj) {
var pclass = pc.getPortClass(conj)
var portClassName = pc.getPortClassName(conj)
var replPortClassName = pc.getPortClassName(conj, true)
'''
//------------------------------------------------------------------------------------------------------------
// «IF conj»conjugated «ENDIF»port class
//------------------------------------------------------------------------------------------------------------
«portClassName»::«portClassName»(IInterfaceItemOwner* actor, const String& name, int localId)
«pclass.generateConstructorInitalizerList('0')»
{
}
«portClassName»::«portClassName»(IInterfaceItemOwner* actor, const String& name, int localId, int idx)
«pclass.generateConstructorInitalizerList('idx')»
{
«IF pclass != null»«initHelper.genExtraInitializers(pclass.attributes)»«ENDIF»
}
«IF Main::settings.generateMSCInstrumentation»
void «portClassName»::destroy() {
DebuggingService::getInstance().removePortInstance(*this);
PortBase::destroy();
}
«ENDIF»
void «portClassName»::receive(const Message* msg) {
// TODO JH further
if (! «pc.name»::«IF conj»isValidOutgoingEvtID«ELSE»isValidIncomingEvtID«ENDIF»(msg->getEvtId())) {
//std::cout << "unknown" << std::endl;
}
«IF Main::settings.generateMSCInstrumentation»
DebuggingService::getInstance().addMessageAsyncIn(getPeerAddress(), getAddress(), «pc.name»::getMessageString(msg->getEvtId()).c_str());
«ENDIF»
«IF pc.handlesReceive(conj)»
switch (msg->getEvtId()) {
«FOR hdlr : pc.getReceiveHandlers(conj)»
case «pc.name»::«hdlr.msg.getCodeName()»:
{
«FOR command : hdlr.detailCode.lines»
«command»
«ENDFOR»
}
break;
«ENDFOR»
default:
«ENDIF»
getActor()->receiveEvent(this, msg->getEvtId(), msg->getData());
«IF pc.handlesReceive(conj)»
break;
}
«ENDIF»
}
«IF pclass!=null»
«pclass.operations.operationsImplementation(portClassName)»
«ENDIF»
// sent messages
«FOR m : pc.getAllMessages(conj)»
«sendMessage(m, pc.name, portClassName, conj)»
«ENDFOR»
//------------------------------------------------------------------------------------------------------------
// «IF conj»conjugated «ENDIF»replicated port class
//------------------------------------------------------------------------------------------------------------
«replPortClassName»::«replPortClassName»(IInterfaceItemOwner* actor, const String& name, int localId) :
ReplicatedPortBase(actor, name, localId)
{
}
«IF conj»
// incoming messages
«FOR m : pc.getAllIncomingMessages()»
«messageSignatureDefinition(m, replPortClassName, false)»{
for (Vector<etRuntime::InterfaceItemBase*>::iterator it = getItems().begin(); it != getItems().end(); ++it) {
(dynamic_cast<«portClassName»*>(*it))->«messageCall(m, false)»;
}
}
«ENDFOR»
«ELSE»
// outgoing messages
«FOR m : pc.getAllOutgoingMessages()»
«messageSignatureDefinition(m, replPortClassName, false)»{
for (Vector<etRuntime::InterfaceItemBase*>::iterator it = getItems().begin(); it != getItems().end(); ++it) {
(dynamic_cast<«portClassName»*>(*it))->«messageCall(m, false)»;
}
}
«ENDFOR»
«ENDIF»
'''
}
def private generateConstructorInitalizerList(PortClass pc, String index) {
val extension initHelper = initHelper
val List<CharSequence> initList = newArrayList
initList += '''PortBase(actor, name, localId, «index»)'''
if(pc != null)
initList += pc.attributes.map['''«name»(«initializerListValue»)''']
initList.generateCtorInitializerList
}
def protected messageCall(Message m, boolean impl) {
'''«m.name»«IF impl»_impl«ENDIF»(«IF m.data!=null» «m.data.name»«ENDIF»)'''
}
def protected messageSignature(Message m, boolean impl) {
'''«IF m.priv||impl»private:«ELSE»public:«ENDIF» void «m.name»«IF impl»_impl«ENDIF»(«IF m.data!=null»«m.data.refType.signatureString» «m.data.name»«ENDIF»)'''
}
def protected messageSignatureDefinition(Message m, String classPrefix, boolean impl) {
'''void «classPrefix»::«m.name»«IF impl»_impl«ENDIF»(«IF m.data!=null»«m.data.refType.signatureString» «m.data.name»«ENDIF»)'''
}
def protected sendMessage(Message m, String portClassName, String classPrefix, boolean conj) {
var dir = if (conj) "IN" else "OUT"
var hdlr = m.getSendHandler(conj)
val dataArg = if(m.data != null) ''', «m.data.name»'''
val messageType = if(m.data != null && !m.data.refType.ref) '''DataMessage<«m.data.refType.type.typeName»>''' else '''Message'''
val message = '''new (buffer) «messageType»(getPeerAddress(), «portClassName»::«dir»_«m.name»«dataArg?:''»)'''
'''
«messageSignatureDefinition(m, classPrefix, false)» {
«IF hdlr!=null»
«FOR command : hdlr.detailCode.lines» «command»
«ENDFOR»
«ELSE»
«messageCall(m, true)»;
«ENDIF»
}
«messageSignatureDefinition(m, classPrefix, true)» {
«IF Main::settings.generateMSCInstrumentation»
DebuggingService::getInstance().addMessageAsyncOut(getAddress(), getPeerAddress(),
«portClassName»::getMessageString(«portClassName»::«dir»_«m.name»).c_str());
«ENDIF»
if (getPeerAddress().isValid()) {
««« we have to use a dynamic cast here because we have a virtual base class
Message* buffer = dynamic_cast<IMessageService*>(getPeerMsgReceiver())->getMessageBuffer(sizeof(«messageType»));
««« // TODO JB: Handle buffer == NULL
if (buffer) {
getPeerMsgReceiver()->receive(«message»);
}
}
}
'''
}
def protected generateDataDrivenHeaderFile(Root root, ProtocolClass pc) {
val sentMsgs = pc.allIncomingMessages.filter(m|m.data!=null)
'''
/**
* @author generated by eTrice
*
* Header File of ProtocolClass «pc.name»
*
*/
«pc.generateIncludeGuardBegin('')»
#include "common/etDatatypesCpp.hpp"
#include "common/modelbase/DataPort.h"
«FOR dataClass : root.getReferencedDataClasses(pc)»
#include "«dataClass.path»«dataClass.name».h"
«ENDFOR»
«pc.userCode1.userCode»
«pc.generateNamespaceBegin»
class «pc.name» {
«pc.userCode2.userCode»
};
// send port holds data
class «pc.getPortClassName(true)» : public etRuntime::DataSendPort {
public:
«pc.getPortClassName(true)»(etRuntime::IRTObject* parent, const etRuntime::String& name, int localId);
// getters and setters
«FOR msg : sentMsgs»
void «msg.name»(«msg.data.refType.type.typeName» «msg.name») {
m_«msg.name» = «msg.name»;
}
«msg.data.refType.type.typeName» «msg.name»() const {
return m_«msg.name»;
}
«ENDFOR»
private:
«FOR msg : sentMsgs»
«msg.data.refType.type.typeName» m_«msg.name»;
«ENDFOR»
};
// receive port accesses send port
class «pc.getPortClassName(false)» : public etRuntime::DataReceivePort {
public:
«pc.getPortClassName(false)»(etRuntime::IRTObject* parent, const etRuntime::String& name, int localId);
// getters
«FOR msg : sentMsgs»
«msg.data.refType.type.typeName» «msg.name»() const;
«ENDFOR»
protected:
virtual void connect(etRuntime::DataSendPort* dataSendPort);
private:
«pc.getPortClassName(true)»* m_peer;
};
«pc.generateNamespaceEnd»
«pc.generateIncludeGuardEnd('')»
'''
}
def protected generateDataDrivenSourceFile(Root root, ProtocolClass pc) {
val sentMsgs = pc.allIncomingMessages.filter(m|m.data!=null)
'''
/**
* @author generated by eTrice
*
* Source File of ProtocolClass «pc.name»
*
*/
#include "«pc.getCppHeaderFileName»"
using namespace etRuntime;
«pc.generateNamespaceBegin»
«pc.userCode3.userCode»
««« «FOR model : models»
««« import «model.name».*;
««« «ENDFOR»
// send port holds data
// constructor
«pc.getPortClassName(true)»::«pc.getPortClassName(true)»(IRTObject* parent, const String& name, int localId) :
DataSendPort(parent, name, localId)
{
}
// receive port accesses send port
// constructor
«pc.getPortClassName(false)»::«pc.getPortClassName(false)»(IRTObject* parent, const String& name, int localId) :
DataReceivePort(parent, name, localId),
m_peer(0)
{
}
// getters
«FOR msg : sentMsgs»
«msg.data.refType.type.typeName» «pc.getPortClassName(false)»::«msg.name»() const {
// TODO needs default value
//if (m_peer == 0)
/* return «msg.data.refType.type.defaultValue»; */
return m_peer->«msg.name»();
}
«ENDFOR»
void «pc.getPortClassName(false)»::connect(DataSendPort* dataSendPort) {
«pc.getPortClassName(true)»* peer = dynamic_cast<«pc.getPortClassName(true)»*>(dataSendPort);
if (peer != 0)
m_peer = peer;
}
«pc.generateNamespaceEnd»
'''
}
override getMessageID(Message msg, InterfaceItem item) {
if (item instanceof Port) {
var p = item as Port;
var direction = if (p.isConjugated())"OUT_" else "IN_"
return enumInUse(p.getProtocol().getName(), direction+msg.getName())
}
else if (item instanceof SAP) {
var sap = item as SAP;
return enumInUse(sap.getProtocol().getName(), "OUT_"+msg.getName())
}
else if (item instanceof SPP) {
var spp = item as SPP;
return enumInUse(spp.getProtocol().getName(), "IN_"+msg.getName())
}
return "unknown interface item";
}
def protected String enumInUse(String namespace, String member) {
return namespace+"::"+member
}
}