blob: d319ce19bedebec53bbb1fdd9d54d9db1ba948ff [file] [log] [blame]
/**
********************************************************************************
* Copyright (c) 2020-2021 Robert Bosch GmbH.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Robert Bosch GmbH - initial API and implementation
* *******************************************************************************
*/
package org.eclipse.app4mc.slg.microros.transformers;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import org.eclipse.app4mc.amalthea.model.ActivityGraphItem;
import org.eclipse.app4mc.amalthea.model.AmaltheaFactory;
import org.eclipse.app4mc.amalthea.model.BooleanObject;
import org.eclipse.app4mc.amalthea.model.Channel;
import org.eclipse.app4mc.amalthea.model.ChannelReceive;
import org.eclipse.app4mc.amalthea.model.ChannelSend;
import org.eclipse.app4mc.amalthea.model.ConditionDisjunction;
import org.eclipse.app4mc.amalthea.model.ConditionDisjunctionEntry;
import org.eclipse.app4mc.amalthea.model.DataSize;
import org.eclipse.app4mc.amalthea.model.ILocalModeValueSource;
import org.eclipse.app4mc.amalthea.model.InterProcessStimulus;
import org.eclipse.app4mc.amalthea.model.InterProcessTrigger;
import org.eclipse.app4mc.amalthea.model.Label;
import org.eclipse.app4mc.amalthea.model.LocalModeCondition;
import org.eclipse.app4mc.amalthea.model.LocalModeLabel;
import org.eclipse.app4mc.amalthea.model.ModeLiteral;
import org.eclipse.app4mc.amalthea.model.ModeLiteralConst;
import org.eclipse.app4mc.amalthea.model.Runnable;
import org.eclipse.app4mc.amalthea.model.Switch;
import org.eclipse.app4mc.amalthea.model.SwitchEntry;
import org.eclipse.app4mc.amalthea.model.Tag;
import org.eclipse.app4mc.slg.commons.m2t.CustomObjectsStore;
import org.eclipse.app4mc.slg.commons.m2t.transformers.SLGTranslationUnit;
import org.eclipse.app4mc.slg.commons.m2t.transformers.sw.RunnableTransformer;
import org.eclipse.app4mc.slg.microros.generators.MicroRosRunnableGenerator;
import org.eclipse.app4mc.slg.ros2.generators.RosRunnableGenerator;
import org.eclipse.app4mc.slg.ros2.transformers.sw.RosLabelTransformer;
import org.eclipse.app4mc.slg.ros2.transformers.sw.RosRunnableCache;
import org.eclipse.app4mc.slg.ros2.transformers.utils.Utils;
import org.eclipse.app4mc.transformation.util.OutputBuffer;
import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EObject;
import com.google.inject.Inject;
public class MicroRosRunnableTransformer extends RunnableTransformer {
public static final String LIB_NAME = "RUNNABLES_LIB";
public static final String BASE_PATH = "MICROROS_SLG/synthetic_gen";
public static final String MODULE_NAME = "runnables";
public static final String MODULE_PATH = BASE_PATH + "/" + MODULE_NAME;
public static final String MAKEFILE_PATH = MODULE_PATH + "/CMakeLists.txt";
@Inject private OutputBuffer outputBuffer;
@Inject private MicroRosActivityGraphItemTransformer activityGraphItemTransformer;
@Inject private RosRunnableCache rosRunnableCache;
@Inject private MicroRosLabelTransformer microrosLabelTransformer;
@Inject private CustomObjectsStore customObjsStore; // model
@Override
protected SLGTranslationUnit createTranslationUnit(Runnable runnable) {
if ((runnable == null)) {
return new SLGTranslationUnit("UNSPECIFIED RUNNABLE");
} else {
String basePath = BASE_PATH;
String moduleName = MODULE_NAME;
String call = "run_" + runnable.getName() + "()";
return new SLGTranslationUnit(basePath, moduleName, call);
}
}
@Override
protected void genFiles(SLGTranslationUnit tu, Runnable runnable) {
customObjsStore.indexData(tu.getCall(), runnable);
final Map<SwitchEntry,List<String>> switchBasedCalls = new LinkedHashMap<SwitchEntry, List<String>>();
final Map<SwitchEntry,List<String>> switchBasedCallsOverwrite = new LinkedHashMap<SwitchEntry, List<String>>(); //overwrite codehook fct
final List<SwitchEntry> switchEntries=new ArrayList<SwitchEntry>();
final Map<SwitchEntry, Boolean> switchEntryOverwriteActivityGraph=new LinkedHashMap<SwitchEntry, Boolean>();
final EList<ActivityGraphItem> defaultActivityGraphItems=new BasicEList<ActivityGraphItem>();
if (isSrcFileEmpty(tu)) { // all stuff only required once regardless of runnable instance
srcAppend(tu, "#include \"" + getIncFile(tu) + "\"\n");
}
final HashSet<String> includes = new LinkedHashSet<>();
final List<String> calls = new ArrayList<>();
boolean measurePerformance = false;
if (runnable != null && runnable.getCustomProperties().get("measure_performance") instanceof BooleanObject) {
measurePerformance = ((BooleanObject) runnable.getCustomProperties().get("measure_performance")).isValue();
}
if (measurePerformance) {
includes.add("aml.h");
}
// Compute characteristic values of runnable
final List<String> params = new ArrayList<>();
final List<String> nodeParams = new ArrayList<>();
final List<String> publishers = new ArrayList<>();
final List<String> clientDeclarations = new ArrayList<>();
final List<String> clientInits = new ArrayList<>();
if (runnable != null && runnable.getActivityGraph() != null) {
EList<ActivityGraphItem> activityGraphItems = runnable.getActivityGraph().getItems();
for (ActivityGraphItem activityGraphItem : activityGraphItems) {
if(activityGraphItem instanceof Switch) {
for(SwitchEntry entry: ((Switch)activityGraphItem).getEntries()) {
switchBasedCalls.put(entry, new ArrayList<String>());
switchBasedCallsOverwrite.put(entry, new ArrayList<String>());
switchEntries.add(entry);
}
}else {
defaultActivityGraphItems.add(activityGraphItem);
}
}
}
extracted(tu, runnable, includes, calls, params, nodeParams, publishers, runnable.getActivityGraph(), defaultActivityGraphItems);
for(SwitchEntry switchEntry: switchEntries) {
extracted(tu, runnable, includes, switchBasedCalls.get(switchEntry), params, nodeParams, publishers, switchEntry, switchEntry.getItems());
}
String nodeParam = String.join(",", nodeParams);
String param = String.join(",", params);
// store characteristic values in runnable cache
rosRunnableCache.storeValues(tu, runnable, param, nodeParam, publishers, clientDeclarations, clientInits);
String fullCall = "run_" + runnable.getName() + "(" + param + ")";
String fullCall_with_context = "run_" + runnable.getName()+"_Context" + "(" + param + ","+getParamNames(runnable.getLocalLabels())+" )";
// write header
incAppend(tu, "\n//Runnable " + runnable.getName() + "----\n");
toH(tu, includes, fullCall,fullCall_with_context);
// write body
srcAppend(tu, "\n//Runnable " + runnable.getName() + "----\n");
toCpp(tu, runnable.getName(), fullCall, fullCall_with_context,calls, measurePerformance,switchEntries, switchBasedCalls, runnable);
}
private void extracted(SLGTranslationUnit tu, Runnable runnable, final HashSet<String> includes,
final List<String> calls, final List<String> params, final List<String> nodeParams,
final List<String> publishers, final EObject elementContainingCustomProps, final EList<ActivityGraphItem> activityGraphItems) {
for (ActivityGraphItem item : activityGraphItems) {
final SLGTranslationUnit graphItemTU = activityGraphItemTransformer.transform(item,tag);
String graphItemIncFile = getIncFile(graphItemTU);
if (graphItemIncFile != null && !graphItemIncFile.isEmpty() && !getIncFile(tu).equals(graphItemIncFile)) {
if (item instanceof ChannelReceive)
{
includes.add("labels.h");
}
else
{
includes.add(graphItemIncFile);
}
}
// check if item is publisher
if (item instanceof ChannelSend) {
ChannelSend cs = (ChannelSend) item;
Channel data = cs.getData();
publishers.add(tag.getName().toLowerCase()+"Node_"+data.getName().toLowerCase() + "_publisher");
//nodeParams.add("&"+tag.getName().toLowerCase()+"Node_"+data.getName().toLowerCase() + "_publisher");
//nodeParams.add("&"+tag.getName().toLowerCase()+"Node_"+data.getName().toLowerCase() + "_msg");
nodeParams.add(tag.getName().toLowerCase()+"Node_"+data.getName().toLowerCase() + "_msg");
// params.add(" rcl_publisher_t * " +tag.getName().toLowerCase()+"Node_"+data.getName().toLowerCase() + "_publisher");
params.add(" std_msgs__msg__String " +tag.getName().toLowerCase()+"Node_"+data.getName().toLowerCase() + "_msg");
//
// localParamNames.add("&"+tag.getName()+"Node_"+data.getName() + "_publisher");
// localParamNames.add("&"+tag.getName()+"Node_"+data.getName() + "_msg");
//
//
// localParamWithSignature.add(" rcl_publisher_t * " +tag.getName()+"Node_"+data.getName() + "_publisher");
// localParamWithSignature.add(" std_msgs__msg__String * " +tag.getName()+"Node_"+data.getName() + "_msg");
//
}
if (item instanceof InterProcessTrigger) {
/*-InterProcessTrigger trigger = (InterProcessTrigger) item;
InterProcessStimulus stimulus = trigger.getStimulus();
String stimName = stimulus.getName();
String idlName = Utils.toIdlCompliantName(stimName + "_service");
includes.add(stimName + "_service/srv/" + stimName + "_service" + ".hpp");
clientDeclarations.add("rclcpp::Client<" + stimName + "_service::srv::" + idlName + ">::SharedPtr " + stimName + "_client");
clientInits.add(stimName + "_client = this->create_client<" + stimName + "_service::srv::" + idlName + ">" + "(\"" + stimName + "_service\")");
nodeParams.add(stimName + "_client");
params.add("rclcpp::Client<" + stimName + "_service::srv::" + idlName + ">::SharedPtr& " + stimName + "_client");*/
}
if (item instanceof ChannelReceive) {
ChannelReceive cr = (ChannelReceive) item;
Channel data = cr.getData();
String subLabelName = data.getName()+ "_sub_label";
// check for the second channel receive
//AmaltheaIndex.getElements(context, name, targetClass)
// AmaltheaIndex.getElements((@NonNull Notifier) customObjsStore, subLabelName, customObjsStore.getInstance(RosLabelTransformer.class) );
Label temp = AmaltheaFactory.eINSTANCE.createLabel();
temp.setName(subLabelName);
DataSize value = data.getSize();
System.out.print(temp.getName()+": ");
System.out.print(value +"\n");
//temp.setSize(value); // transformation error
// with injection
microrosLabelTransformer.transform(temp);
calls.add("//ChannelReceiveCall"); // temporary
calls.add("read_"+temp.getName()+"("+value.getNumberBytes()+")");
nodeParams.add("msg");
params.add(" const std_msgs__msg__String * msg");
calls.add("printf("+"\"Callback: I heard: %s\\n\""+ ", msg->data.data)");
}
final String call = graphItemTU.getCall();
if (call != null && !call.isEmpty()) {
calls.add(call);
}
}
}
protected void toH(SLGTranslationUnit tu, final HashSet<String> includes, final String fullCall, String fullCall_with_context) {
for (String include : includes) {
incAppend(tu, "#include \"" + include + "\"\n");
}
incAppend(tu, "void " + fullCall + ";\n");
Runnable data = customObjsStore.getData(tu.getCall());
EList<LocalModeLabel> localLabels = ((Runnable)data).getLocalLabels();
if(localLabels.size()>0)
incAppend(tu, "void " +fullCall_with_context+" ;\n");
}
protected void toCpp(SLGTranslationUnit tu, final String runnableName, final String fullCall, String fullCall_with_context, final List<String> calls, boolean measurePerformance,List<SwitchEntry> switchEntries, Map<SwitchEntry, List<String>> switchBasedCalls , Runnable runnable) {
srcAppend(tu, "void " + fullCall + "{\n");
if (measurePerformance) {
srcAppend(tu,
"uint64_t event_list[] = {0x11, 0x13, 0x17}; //CPU CYCLES, MEM ACCESS, L2 Cache Refill\n"
+ "int total_events = sizeof(event_list)/sizeof(event_list[0]);\n"
+ "int fd = instrument_start(0,event_list, total_events);\n");
}
for (String call : calls) {
srcAppend(tu, "\t" + call + ";\n");
}
if (measurePerformance) {
srcAppend(tu, "instrument_stop(fd, \"" + runnableName + ".log\");\n");
}
srcAppend(tu, "}\n\n");
//Adding additional method
if(runnable.getLocalLabels().size()>0) {
srcAppend(tu, "void " + fullCall_with_context + "{\n"+ "\n");
if (measurePerformance) {
srcAppend(tu,
"uint64_t event_list[] = {0x11, 0x13, 0x17}; //CPU CYCLES, MEM ACCESS, L2 Cache Refill\n"
+ "int total_events = sizeof(event_list)/sizeof(event_list[0]);\n"
+ "int fd = instrument_start(0,event_list, total_events);\n");
}
for(SwitchEntry switchEntry: switchEntries) {
{
srcAppend(tu, "if("+getConditionString(switchEntry)+"){" + "\n");
for (String call : switchBasedCalls.get(switchEntry)) {
srcAppend(tu, call + ";" + "\n");
}
srcAppend(tu, "\n" + "}" + "\n");
}
}
if (measurePerformance) {
srcAppend(tu, "instrument_stop(fd, \"" + runnableName + "_context.log\");\n");
}
srcAppend(tu, "}\n\n");
}
}
@Override
public boolean createCMake() {
return outputBuffer.appendTo(
"OTHER", MAKEFILE_PATH, MicroRosRunnableGenerator.toCMake(LIB_NAME, getSrcFiles()));
}
private Tag tag;
public SLGTranslationUnit transform(Tag tag,Runnable runnable) {
this.tag=tag;
return super.transform(runnable);
}
private String getParamNames(EList<LocalModeLabel> localLabels) {
List<String> ls=new ArrayList<String>();
for (LocalModeLabel localModeLabel : localLabels) {
ls.add("char* "+localModeLabel.getName());
}
return String.join(",", ls);
}
private String getConditionString(SwitchEntry switchEntry) {
ConditionDisjunction condition = switchEntry.getCondition();
if(condition !=null) {
EList<ConditionDisjunctionEntry> entries = condition.getEntries();
for (ConditionDisjunctionEntry conditionDisjunctionEntry : entries) {
if(conditionDisjunctionEntry instanceof LocalModeCondition) {
LocalModeLabel localLabel = ((LocalModeCondition) conditionDisjunctionEntry).getLabel();
if(localLabel !=null) {
String localVariableName = localLabel.getName();
ILocalModeValueSource valueSource = ((LocalModeCondition) conditionDisjunctionEntry).getValueSource();
if(valueSource !=null && valueSource instanceof ModeLiteralConst) {
ModeLiteral value = ((ModeLiteralConst)valueSource).getValue();
String caseName= value.getName();
return "strcmp("+localVariableName+",\""+caseName+"\")==0";
}
}
}
}
}
return "false";
}
}