| /** |
| ******************************************************************************** |
| * 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.ros2.transformers.sw; |
| |
| import java.util.ArrayList; |
| import java.util.HashSet; |
| import java.util.LinkedHashSet; |
| import java.util.List; |
| |
| import org.eclipse.app4mc.amalthea.model.ActivityGraphItem; |
| import org.eclipse.app4mc.amalthea.model.BooleanObject; |
| import org.eclipse.app4mc.amalthea.model.Channel; |
| import org.eclipse.app4mc.amalthea.model.ChannelSend; |
| import org.eclipse.app4mc.amalthea.model.InterProcessStimulus; |
| import org.eclipse.app4mc.amalthea.model.InterProcessTrigger; |
| import org.eclipse.app4mc.amalthea.model.Runnable; |
| import org.eclipse.app4mc.slg.commons.m2t.transformers.SLGTranslationUnit; |
| import org.eclipse.app4mc.slg.commons.m2t.transformers.sw.RunnableTransformer; |
| import org.eclipse.app4mc.slg.ros2.generators.RosRunnableGenerator; |
| import org.eclipse.app4mc.slg.ros2.transformers.utils.Utils; |
| import org.eclipse.app4mc.transformation.util.OutputBuffer; |
| |
| import com.google.inject.Inject; |
| |
| public class RosRunnableTransformer extends RunnableTransformer { |
| |
| public static final String LIB_NAME = "RUNNABLES_LIB"; |
| public static final String BASE_PATH = "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 RosActivityGraphItemTransformer activityGraphItemTransformer; |
| @Inject private RosRunnableCache rosRunnableCache; |
| |
| @Override |
| public void genFiles(SLGTranslationUnit tu, Runnable runnable) { |
| 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 |
| |
| String param = ""; |
| String nodeParam = ""; |
| final List<String> publishers = new ArrayList<>(); |
| final List<String> clientDeclarations = new ArrayList<>(); |
| final List<String> clientInits = new ArrayList<>(); |
| |
| if (runnable != null && runnable.getActivityGraph() != null) { |
| for (ActivityGraphItem item : runnable.getActivityGraph().getItems()) { |
| |
| final SLGTranslationUnit graphItemTU = activityGraphItemTransformer.transform(item); |
| String graphItemIncFile = getIncFile(graphItemTU); |
| if (graphItemIncFile != null && !graphItemIncFile.isEmpty() && !getIncFile(tu).equals(graphItemIncFile)) { |
| includes.add(graphItemIncFile); |
| } |
| |
| // check if item is publisher |
| |
| if (item instanceof ChannelSend) { |
| ChannelSend cs = (ChannelSend) item; |
| Channel data = cs.getData(); |
| |
| publishers.add(data.getName() + "_publisher"); |
| |
| nodeParam = nodeParam + ((nodeParam.equals("")) ? "" : ";") + data.getName() + "_publisher"; |
| param = ((param.equals("")) ? "" : ";") + "rclcpp::Publisher<std_msgs::msg::String>::SharedPtr& " |
| + data.getName() + "_publisher"; |
| } |
| |
| if (item instanceof InterProcessTrigger) { |
| InterProcessTrigger trigger = (InterProcessTrigger) item; |
| InterProcessStimulus stimulus = trigger.getStimulus(); |
| |
| includes.add(stimulus.getName() + "_service/srv/" + stimulus.getName() + "_service" + ".hpp"); |
| clientDeclarations.add( |
| "rclcpp::Client<" + stimulus.getName() + "_service::srv::" |
| + Utils.toIdlCompliantName(stimulus.getName() + "_service") |
| + ">::SharedPtr " + stimulus.getName() + "_client"); |
| clientInits.add( |
| stimulus.getName() + "_client = this->create_client<" + stimulus.getName() + "_service::srv::" |
| + Utils.toIdlCompliantName(stimulus.getName() + "_service") + ">" |
| + "(\"" + stimulus.getName() + "_service\")"); |
| nodeParam = nodeParam + (nodeParam.equals("") ? "" : ";") + stimulus.getName() + "_client"; |
| param = (param.equals("") ? "" : ";") + "rclcpp::Client<" |
| + stimulus.getName() + "_service::srv::" + Utils.toIdlCompliantName(stimulus.getName() + "_service") |
| + ">::SharedPtr& " + stimulus.getName() + "_client"; |
| } |
| |
| final String call = graphItemTU.getCall(); |
| if (call != null && !call.isEmpty()) { |
| calls.add(call); |
| } |
| } |
| } |
| |
| // store characteristic values in runnable cache |
| rosRunnableCache.storeValues(tu, runnable, param, nodeParam, publishers, clientDeclarations, clientInits); |
| |
| String fullCall = "run_" + runnable.getName() + "(" + param + ")"; |
| |
| // write header |
| incAppend(tu, "\n//Runnable " + runnable.getName() + "----\n"); |
| toH(tu, includes, fullCall); |
| |
| // write body |
| srcAppend(tu, "\n//Runnable " + runnable.getName() + "----\n"); |
| toCpp(tu, runnable.getName(), fullCall, calls, measurePerformance); |
| } |
| |
| private void toH(SLGTranslationUnit tu, final HashSet<String> includes, final String fullCall) { |
| for (String include : includes) { |
| incAppend(tu, "#include \"" + include + "\"\n"); |
| } |
| incAppend(tu, "void " + fullCall + ";\n"); |
| } |
| |
| private void toCpp(SLGTranslationUnit tu, final String runnableName, final String fullCall, final List<String> calls, boolean measurePerformance) { |
| 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"); |
| } |
| |
| @Override |
| public boolean createCMake() { |
| return outputBuffer.appendTo( |
| "OTHER", MAKEFILE_PATH, RosRunnableGenerator.toCMake(LIB_NAME, getSrcFiles())); |
| } |
| |
| } |