/**
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*/
package org.thingml.compilers.c;
import org.sintef.thingml.*;
import org.sintef.thingml.constraints.ThingMLHelpers;
import org.sintef.thingml.helpers.AnnotatedElementHelper;
import org.sintef.thingml.helpers.CompositeStateHelper;
import org.sintef.thingml.helpers.StateHelper;
import org.sintef.thingml.helpers.ThingMLElementHelper;
import org.thingml.compilers.Context;
import org.thingml.compilers.DebugProfile;
import org.thingml.compilers.interfaces.c.ICThingImpEventHandlerStrategy;
import org.thingml.compilers.thing.common.FSMBasedThingImplCompiler;
import org.thingml.compilers.c.arduino.ArduinoThingCepCompiler;
import org.thingml.compilers.c.cepHelper.CCepHelper;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.sintef.thingml.helpers.RegionHelper;
import org.sintef.thingml.helpers.ThingHelper;
import static org.thingml.compilers.c.cepHelper.CCepHelper.handlerShouldTrigger;
import static org.thingml.compilers.c.cepHelper.CCepHelper.shouldTriggerOnInputNumber;
/**
* Created by ffl on 17.06.15.
*/
public class CThingImplCompiler extends FSMBasedThingImplCompiler {
protected Set<ICThingImpEventHandlerStrategy> eventHandlerStrategies;
public CThingImplCompiler() {
eventHandlerStrategies = new HashSet<ICThingImpEventHandlerStrategy>();
}
public void addEventHandlerStrategy(ICThingImpEventHandlerStrategy strategy) {
eventHandlerStrategies.add(strategy);
}
@Override
public void generateImplementation(Thing thing, Context ctx) {
generateCImpl(thing, (CCompilerContext) ctx);
}
public boolean isGeneratingCpp() {
return false;
}
public String getCppNameScope() {
return "";
}
protected void generateCImpl(Thing thing, CCompilerContext ctx) {
if (isGeneratingCpp()) {
// GENERATE C++ INIT CODE FOR THING
String cppinittemplate = ctx.getThingImplInitTemplate();
StringBuilder builder = new StringBuilder();
generateCppMessageSendingInit(thing, builder, ctx);
cppinittemplate = cppinittemplate.replace("/*CODE*/", builder.toString());
ctx.getBuilder(thing.getName() + "_init.c").append(cppinittemplate);
}
StringBuilder builder = new StringBuilder();
builder.append("/*****************************************************************************\n");
builder.append(" * Implementation for type : " + thing.getName() + "\n");
builder.append(" *****************************************************************************/\n\n");
generateCGlobalAnnotation(thing, builder, ctx);
builder.append("// Declaration of prototypes:\n");
//FIXME: If we need these cpp directives, they should be added in the specific compilers which needs them
//builder.append("#ifdef __cplusplus\n");
//builder.append("extern \"C\" {\n");
//builder.append("#endif\n");
if (!isGeneratingCpp()) { // Private prototypes will be generated as part of header for C++
generatePrivateCPrototypes(thing, builder, ctx);
}
//builder.append("#ifdef __cplusplus\n");
//builder.append("}\n");
//builder.append("#endif\n");
//builder.append("\n");
DebugProfile debugProfile = ctx.getCompiler().getDebugProfiles().get(thing);
//if(ctx.containsDebug(ctx.getCurrentConfiguration(), thing)) {
if (debugProfile.isActive()) {
builder.append("//Debug fonction\n");
builder.append("void " + thing.getName() + "_print_debug(");
builder.append("struct " + ctx.getInstanceStructName(thing) + " * _instance");
builder.append(", char * str) {\n");
builder.append("if(_instance->debug) {\n");
if (ctx.getCompiler().getID().compareTo("arduino") == 0) {
if (AnnotatedElementHelper.hasAnnotation(ctx.getCurrentConfiguration(), "arduino_stdout")) {
String stdout = AnnotatedElementHelper.annotation(ctx.getCurrentConfiguration(), "arduino_stdout").iterator().next();
builder.append(stdout + ".print(_instance->name);\n");
builder.append(stdout + ".print(str);\n");
} else {
builder.append("// PRINT: (" + thing.getName() + ") str");
}
} else {
builder.append("printf(\"%s%s\", _instance->name, str);\n");
}
builder.append("}\n");
builder.append("}\n\n");
}
generateCFunctions(thing, builder, ctx, debugProfile);
builder.append("// Sessions functionss:\n");
generateSessionForks(thing, builder, ctx, debugProfile);
builder.append("\n");
generateSessionTerminate(thing, builder, ctx, debugProfile);
builder.append("\n");
builder.append("// On Entry Actions:\n");
generateEntryActions(thing, builder, ctx, debugProfile);
builder.append("\n");
builder.append("// On Exit Actions:\n");
generateExitActions(thing, builder, ctx, debugProfile);
builder.append("\n");
builder.append("// Event Handlers for incoming messages:\n");
generateEventHandlers(thing, builder, ctx, debugProfile);
builder.append("\n");
builder.append("// Observers for outgoing messages:\n");
generatePrivateMessageSendingOperations(thing, builder, ctx, debugProfile);
builder.append("\n");
//FIXME: should call getCompiler
if (!CCepHelper.getStreamWithBuffer(thing).isEmpty())
ArduinoThingCepCompiler.generateCEPLibImpl(thing, builder, ctx);
// Get the template and replace the values
String itemplate = ctx.getThingImplTemplate();
itemplate = itemplate.replace("/*NAME*/", thing.getName());
itemplate = itemplate.replace("/*CODE*/", builder.toString());
// Save the result in the context with the right file name
ctx.getBuilder(ctx.getPrefix() + thing.getName() + ".c").append(itemplate);
}
protected void generatePrototypeforThingDirect(Function func, StringBuilder builder, CCompilerContext ctx, Thing thing, boolean isPrototype) {
//TODO sdalgard - Added c++ support
if (AnnotatedElementHelper.hasAnnotation(func, "c_prototype")) {
// generateMainAndInit the given prototype. Any parameters are ignored.
String c_proto = AnnotatedElementHelper.annotation(func, "c_prototype").iterator().next();
builder.append(c_proto);
} else {
// Generate the normal prototype
if (func.getType() != null) {
builder.append(ctx.getCType(func.getType()));
if (func.getCardinality() != null) builder.append("*");
} else builder.append("void");
if (!isPrototype) {
builder.append(" " + getCppNameScope() + ctx.getCName(func, thing) + "(");
} else {
builder.append(" " + ctx.getCName(func, thing) + "(");
}
builder.append("struct " + ctx.getInstanceStructName(thing) + " *" + ctx.getInstanceVarName());
for (Parameter p : func.getParameters()) {
builder.append(", ");
builder.append(ctx.getCType(p.getType()));
if (p.getCardinality() != null || p.isIsArray()) builder.append("*");
builder.append(" " + p.getName());
}
builder.append(")");
}
}
protected void generateCGlobalAnnotation(Thing thing, StringBuilder builder, CCompilerContext ctx) {
//TODO sdalgard - Check if C++ rework is needed
if (AnnotatedElementHelper.hasAnnotation(thing, "c_global")) {
builder.append("\n// BEGIN: Code from the c_global annotation " + thing.getName());
for (String code : AnnotatedElementHelper.annotation(thing, "c_global")) {
builder.append("\n");
builder.append(code);
}
builder.append("\n// END: Code from the c_global annotation " + thing.getName() + "\n\n");
}
}
protected void generateStateMachineOnExitCPrototypes(Thing thing, StringBuilder builder, CCompilerContext ctx) {
if (ThingMLHelpers.allStateMachines(thing).size() > 0) {// There should be only one if there is one
StateMachine sm = ThingMLHelpers.allStateMachines(thing).get(0);
builder.append("void " + ThingMLElementHelper.qname(sm, "_") + "_OnExit(int state, ");
//fix for empty statechart
builder.append("struct " + ctx.getInstanceStructName(thing) + " *" + ctx.getInstanceVarName() + ");\n"); // sdalgard moved inside if-statement
}
}
protected void generatePrivateCPrototypes(Thing thing, StringBuilder builder, CCompilerContext ctx) {
// NB sdalgard - ** Reference to be removed ** This function is duplicated in generatePrivateCppPrototypes in class CThingApiCompiler
// Exit actions
StringBuilder cppHeaderBuilder = ctx.getCppHeaderCode();
builder.append("//Prototypes: State Machine\n");
generateStateMachineOnExitCPrototypes(thing, builder, ctx);
//fix for empty statechart
//builder.append("struct " + ctx.getInstanceStructName(thing) + " *" + ctx.getInstanceVarName() + ");\n");
// Message Sending
builder.append("//Prototypes: Message Sending\n");
for (Port port : ThingMLHelpers.allPorts(thing)) {
for (Message msg : port.getSends()) {
builder.append("void " + ctx.getSenderName(thing, port, msg));
ctx.appendFormalParameters(thing, builder, msg);
builder.append(";\n");
}
}
builder.append("//Prototypes: Function\n");
for (Function f : ThingMLHelpers.allFunctions(thing)) {
if (!AnnotatedElementHelper.isDefined(f, "abstract", "true")) {
generatePrototypeforThingDirect(f, builder, ctx, thing, true);
builder.append(";\n");
if (isGeneratingCpp()) {
generatePrototypeforThingDirect(f, cppHeaderBuilder, ctx, thing, true);
cppHeaderBuilder.append(";\n");
}
}
}
}
protected void generateCFunctions(Thing thing, StringBuilder builder, CCompilerContext ctx, DebugProfile debugProfile) {
builder.append("// Declaration of functions:\n");
for (Function f : ThingMLHelpers.allFunctions(thing)) {
if (!AnnotatedElementHelper.isDefined(f, "abstract", "true")) { // Generate only for concrete functions
generateCFunction(f, thing, builder, ctx, debugProfile);
}
}
builder.append("\n");
}
protected void generateCFunction(Function func, Thing thing, StringBuilder builder, CCompilerContext ctx, DebugProfile debugProfile) {
// Test for any special function
if (AnnotatedElementHelper.isDefined(func, "fork_linux_thread", "true") || AnnotatedElementHelper.isDefined(func, "fork_thread", "true")) {
generateCforThingLinuxThread(func, thing, builder, ctx, debugProfile);
} else { // Use the default function generator
generateCforThingDirect(func, thing, builder, ctx, debugProfile);
}
}
protected void generateCforThingDirect(Function func, Thing thing, StringBuilder builder, CCompilerContext ctx, DebugProfile debugProfile) {
StringBuilder cppHeaderBuilder = ctx.getCppHeaderCode();
if (isGeneratingCpp()) {
generatePrototypeforThingDirect(func, cppHeaderBuilder, ctx, thing, true);
cppHeaderBuilder.append(";\n");
}
builder.append("// Definition of function " + func.getName() + "\n");
generatePrototypeforThingDirect(func, builder, ctx, thing, false);
builder.append(" {\n");
if (AnnotatedElementHelper.hasAnnotation(func, "c_instance_var_name")) {
// generateMainAndInit the given prototype. Any parameters are ignored.
String nname = AnnotatedElementHelper.annotation(func, "c_instance_var_name").iterator().next();
ctx.changeInstanceVarName(nname);
}
//if(ctx.isToBeDebugged(ctx.getCurrentConfiguration(), thing, func)) {
if (debugProfile.getDebugFunctions().contains(func)) {
builder.append(thing.getName() + "_print_debug(" + ctx.getInstanceVarName() + ", \""
+ ctx.traceFunctionBegin(thing, func) + "\\n\");\n");
}
ctx.getCompiler().getThingActionCompiler().generate(func.getBody(), builder, ctx);
if (debugProfile.getDebugFunctions().contains(func)) {
builder.append(thing.getName() + "_print_debug(" + ctx.getInstanceVarName() + ", \""
+ ctx.traceFunctionDone(thing, func) + "\\n\");\n");
}
ctx.clearInstanceVarName();
builder.append("}\n");
}
protected void generateCforThingLinuxThread(Function func, Thing thing, StringBuilder builder, CCompilerContext ctx, DebugProfile debugProfile) {
if (func.getType() != null) {
System.err.println("WARNING: function with annotation fork_linux_thread must return void");
}
String template = ctx.getTemplateByID("ctemplates/fork.c");
template = template.replace("/*NAME*/", ctx.getCName(func, thing));
StringBuilder b_code = new StringBuilder();
if (debugProfile.getDebugFunctions().contains(func)) {
b_code.append(thing.getName() + "_print_debug(" + ctx.getInstanceVarName() + ", \""
+ ctx.traceFunctionBegin(thing, func) + "\\n\");\n");
}
ctx.getCompiler().getThingActionCompiler().generate(func.getBody(), b_code, ctx);
if (debugProfile.getDebugFunctions().contains(func)) {
b_code.append(thing.getName() + "_print_debug(" + ctx.getInstanceVarName() + ", \""
+ ctx.traceFunctionDone(thing, func) + "\\n\");\n");
}
template = template.replace("/*CODE*/", b_code.toString());
StringBuilder b_params = new StringBuilder();
b_params.append("struct " + ctx.getInstanceStructName(thing) + " *" + ctx.getInstanceVarName());
for (Parameter p : func.getParameters()) {
b_params.append(", ");
b_params.append(ctx.getCType(p.getType()));
if (p.getCardinality() != null) builder.append("*");
b_params.append(" " + p.getName());
}
template = template.replace("/*PARAMS*/", b_params.toString());
String struct_params = b_params.toString().replace(",", ";\n ") + ";\n";
template = template.replace("/*STRUCT_PARAMS*/", struct_params);
StringBuilder a_params = new StringBuilder();
a_params.append("params." + ctx.getInstanceVarName());
for (Parameter p : func.getParameters()) {
a_params.append(", ");
a_params.append("params." + p.getName());
}
template = template.replace("/*ACTUAL_PARAMS*/", a_params.toString());
StringBuilder s_params = new StringBuilder();
s_params.append("params." + ctx.getInstanceVarName() + " = " + ctx.getInstanceVarName() + ";\n");
for (Parameter p : func.getParameters()) {
s_params.append(" params." + p.getName() + " = " + p.getName() + ";\n");
}
template = template.replace("/*STORE_PARAMS*/", s_params.toString());
builder.append(template);
}
protected void generateEntryActions(Thing thing, StringBuilder builder, CCompilerContext ctx, DebugProfile debugProfile) {
if (ThingMLHelpers.allStateMachines(thing).isEmpty()) return;
StringBuilder cppHeaderBuilder = ctx.getCppHeaderCode();
StateMachine sm = ThingMLHelpers.allStateMachines(thing).get(0); // There has to be one and only one state machine here
// steffend - This is commented out because it is already generated as part of the API
//if (isGeneratingCpp()) {
// cppHeaderBuilder.append("// generateEntryActions \nvoid " + ThingMLElementHelper.qname(sm, "_") + "_OnEntry(int state, ");
// cppHeaderBuilder.append("struct " + ctx.getInstanceStructName(thing) + " *" + ctx.getInstanceVarName() + ");\n");
//}
builder.append("void " + getCppNameScope() + ThingMLElementHelper.qname(sm, "_") + "_OnEntry(int state, ");
builder.append("struct " + ctx.getInstanceStructName(thing) + " *" + ctx.getInstanceVarName() + ") {\n");
builder.append("switch(state) {\n");
for (CompositeState cs : CompositeStateHelper.allContainedCompositeStatesIncludingSessions(sm)) {
builder.append("case " + ctx.getStateID(cs) + ":{\n");
if (debugProfile.isDebugBehavior()) {
builder.append(thing.getName() + "_print_debug(" + ctx.getInstanceVarName() + ", \""
+ ctx.traceOnEntry(thing, sm) + "\\n\");\n");
}
ArrayList<Region> regions = new ArrayList<Region>();
regions.add(cs);
regions.addAll(cs.getRegion());
// Init state
for (Region r : regions) {
if (!r.isHistory()) {
builder.append(ctx.getInstanceVarName() + "->" + ctx.getStateVarName(r) + " = " + ctx.getStateID(r.getInitial()) + ";\n");
}
}
// Execute Entry actions
if (cs.getEntry() != null) ctx.getCompiler().getThingActionCompiler().generate(cs.getEntry(), builder, ctx);
// Recurse on contained states
for (Region r : regions) {
builder.append(ThingMLElementHelper.qname(sm, "_") + "_OnEntry(" + ctx.getInstanceVarName() + "->" + ctx.getStateVarName(r) + ", " + ctx.getInstanceVarName() + ");\n");
}
builder.append("break;\n}\n");
}
for (State s : CompositeStateHelper.allContainedSimpleStatesIncludingSessions(sm)) {
builder.append("case " + ctx.getStateID(s) + ":{\n");
//if(ctx.isToBeDebugged(ctx.getCurrentConfiguration(), thing, s)) {
if (debugProfile.isDebugBehavior()) {
builder.append(thing.getName() + "_print_debug(" + ctx.getInstanceVarName() + ", \""
+ ctx.traceOnEntry(thing, sm, s) + "\\n\");\n");
}
if (s.getEntry() != null) ctx.getCompiler().getThingActionCompiler().generate(s.getEntry(), builder, ctx);
if(s instanceof FinalState) {
builder.append("_instance->active = false;\n");
generateKillChildren(thing, builder);
}
builder.append("break;\n}\n");
}
builder.append("default: break;\n");
builder.append("}\n");
builder.append("}\n");
}
protected void generateExitActions(Thing thing, StringBuilder builder, CCompilerContext ctx, DebugProfile debugProfile) {
if (ThingMLHelpers.allStateMachines(thing).isEmpty()) return;
StringBuilder cppHeaderBuilder = ctx.getCppHeaderCode();
StateMachine sm = ThingMLHelpers.allStateMachines(thing).get(0); // There has to be one and only one state machine here
if (isGeneratingCpp()) {
cppHeaderBuilder.append("// generateExitActions\nvoid " + ThingMLElementHelper.qname(sm, "_") + "_OnExit(int state, ");
cppHeaderBuilder.append("struct " + ctx.getInstanceStructName(thing) + " *" + ctx.getInstanceVarName() + ");\n");
}
builder.append("void " + getCppNameScope() + ThingMLElementHelper.qname(sm, "_") + "_OnExit(int state, ");
builder.append("struct " + ctx.getInstanceStructName(thing) + " *" + ctx.getInstanceVarName() + ") {\n");
builder.append("switch(state) {\n");
for (CompositeState cs : CompositeStateHelper.allContainedCompositeStatesIncludingSessions(sm)) {
builder.append("case " + ctx.getStateID(cs) + ":{\n");
ArrayList<Region> regions = new ArrayList<Region>();
regions.add(cs);
regions.addAll(cs.getRegion());
// Init state
for (Region r : regions) {
builder.append(ThingMLElementHelper.qname(sm, "_") + "_OnExit(" + ctx.getInstanceVarName() + "->" + ctx.getStateVarName(r) + ", " + ctx.getInstanceVarName() + ");\n");
}
// Execute Exit actions
if (cs.getExit() != null) ctx.getCompiler().getThingActionCompiler().generate(cs.getExit(), builder, ctx);
builder.append("break;}\n");
}
for (State s : CompositeStateHelper.allContainedSimpleStatesIncludingSessions(sm)) {
builder.append("case " + ctx.getStateID(s) + ":{\n");
if (s.getExit() != null) ctx.getCompiler().getThingActionCompiler().generate(s.getExit(), builder, ctx);
if (debugProfile.isDebugBehavior()) {
builder.append(thing.getName() + "_print_debug(" + ctx.getInstanceVarName() + ", \""
+ ctx.traceOnExit(thing, sm, s) + "\\n\");\n");
}
builder.append("break;}\n");
}
builder.append("default: break;\n");
builder.append("}\n");
builder.append("}\n");
}
protected void generateEventHandlers(Thing thing, StringBuilder builder, CCompilerContext ctx, DebugProfile debugProfile) {
if (ThingMLHelpers.allStateMachines(thing).isEmpty()) return;
StringBuilder cppHeaderBuilder = ctx.getCppHeaderCode();
StateMachine sm = ThingMLHelpers.allStateMachines(thing).get(0); // There has to be one and only one state machine here
Map<Port, Map<Message, List<Handler>>> handlers = StateHelper.allMessageHandlersIncludingSessions(sm);
for (Port port : handlers.keySet()) {
for (Message msg : handlers.get(port).keySet()) {
// steffend - This is commented out because it is already generated as part of the API
//if (isGeneratingCpp()) {
// cppHeaderBuilder.append("// generateEventHandlers\nvoid " + ctx.getHandlerName(thing, port, msg));
// ctx.appendFormalParameters(thing, cppHeaderBuilder, msg);
// cppHeaderBuilder.append(";\n");
//}
builder.append("void " + getCppNameScope() + ctx.getHandlerName(thing, port, msg));
ctx.appendFormalParameters(thing, builder, msg);
builder.append(" {\n");
generateSessionHandlerCalls(thing, port, msg, ctx, builder);
//if(ctx.isToBeDebugged(ctx.getCurrentConfiguration(), thing, port, msg)) {
if (debugProfile.getDebugMessages().containsKey(port)) {
if (debugProfile.getDebugMessages().get(port).contains(msg)) {
builder.append(thing.getName() + "_print_debug(" + ctx.getInstanceVarName() + ", \""
+ ctx.traceReceiveMessage(thing, port, msg) + "\\n\");\n");
}
}
//FIXME: Implement the message debug in the context
/*
if (ctx.debug_message_receive(msg)) {
builder.append(ctx.print_debug_message("<- " + handler_name(port, msg)) + "\n");
}
*/
// dispatch the current message to sub-regions
dispatchToSubRegions(thing, builder, sm, port, msg, ctx, debugProfile);
dispatchToSessions(thing, builder, sm, port, msg, ctx, debugProfile);
// If the state machine itself has a handler
if (StateHelper.canHandle(sm, port, msg)) {
// it can only be an internal handler so the last param can be null (in theory)
generateMessageHandlers(thing, sm, port, msg, builder, null, sm, ctx, debugProfile);
}
generateStreamDispatch(thing, port, msg, ctx, builder);
builder.append("}\n");
}
}
// Add handler for empty transitions if needed
if (StateHelper.hasEmptyHandlersIncludingSessions(sm)) {
if (isGeneratingCpp()) {
cppHeaderBuilder.append("// generateEventHandlers2\nint " + ctx.getEmptyHandlerName(thing));
ctx.appendFormalParametersEmptyHandler(thing, cppHeaderBuilder);
cppHeaderBuilder.append(";\n");
}
//New Empty Event Method
builder.append("int " + getCppNameScope() + ctx.getEmptyHandlerName(thing));
//builder.append("int " + ctx.getEmptyHandlerName(thing));
//builder.append("void " + getCppNameScope() + ctx.getEmptyHandlerName(thing));
//builder.append("void " + ctx.getEmptyHandlerName(thing));
ctx.appendFormalParametersEmptyHandler(thing, builder);
builder.append(" {\n");
builder.append(" uint8_t empty_event_consumed = 0;\n");
generateSessionEmptyHandlerCalls(thing, ctx, builder);
// dispatch the current message to sub-regions
dispatchEmptyToSubRegions(thing, builder, sm, ctx, debugProfile);
builder.append("//begin dispatchEmptyToSession\n");
dispatchEmptyToSessions(thing, builder, sm, ctx, debugProfile);
builder.append("//end dispatchEmptyToSession\n");
// If the state machine itself has a handler
if (StateHelper.hasEmptyHandlersIncludingSessions(sm)) {
// it can only be an internal handler so the last param can be null (in theory)
generateEmptyHandlers(thing, sm, builder, null, sm, ctx, debugProfile);
}
//New Empty Event Method
builder.append("return empty_event_consumed;\n");
builder.append("}\n");
}
for(ICThingImpEventHandlerStrategy strategy : eventHandlerStrategies)
strategy.generateEventHandlers(thing, builder, ctx, debugProfile);
}
/**
* Dispatch message to concerned stream, by enqueing, or do all the needed stuff if there is no need for a buffer.
*
* @param thing Thing instance
* @param port Port receiving the message
* @param msg Message concerned
* @param ctx Compiler context
* @param builder StringBuilder, should come from handle_port_msg
*/
private void generateStreamDispatch(Thing thing, Port port, Message msg, CCompilerContext ctx, StringBuilder builder) {
for (Stream s : thing.getStreams()) {
Source source = s.getInput();
// Gather all the sources
Map<SimpleSource, String> sourceMap = CCepHelper.gatherSourcesOfStream(source);
for (SimpleSource sc : sourceMap.keySet()) {
if (sourceMap.get(sc).equals(msg.getName())) {
builder.append("//begin stream dispatch\n");
for (Parameter p : msg.getParameters())
ctx.putCepMsgParam(msg.getName(), p.getName(), s.getName());
int nbCondition = 0;
// guard
for (ViewSource vs : sc.getOperators()) {
if (vs instanceof Filter) {
builder.append("if (");
ctx.getCompiler().getThingActionCompiler().generate(((Filter) vs).getGuard(), builder, ctx);
nbCondition++;
builder.append(") {\n");
}
}
boolean shouldProduce = handlerShouldTrigger(s, ctx);
// produce the action or propagate the event
if (source instanceof SimpleSource && shouldProduce) {
for (LocalVariable lv : s.getSelection()) {
lv.setName(ThingMLElementHelper.qname(lv, "_"));
ctx.getCompiler().getThingActionCompiler().generate(lv, builder, ctx);
}
ctx.getCompiler().getThingActionCompiler().generate(s.getOutput(), builder, ctx);
} else if (source instanceof MergeSources && shouldProduce) {
Message rMsg = ((MergeSources) source).getResultMessage();
// since we don't call the checkTrigger we need to check the source guard as well
List<String> guardsList = new ArrayList<>();
for (ViewSource vs : source.getOperators()) {
if (vs instanceof Filter) {
StringBuilder sourceGuard = new StringBuilder();
ctx.getCompiler().getThingActionCompiler().generate(((Filter) vs).getGuard(), sourceGuard, ctx);
guardsList.add(sourceGuard.toString());
}
}
if (guardsList.size() > 0)
builder.append("if (" + String.join(" && ", guardsList) + ") {\n");
int paramIndex = 0;
for (Parameter p : rMsg.getParameters()) {
builder.append(ctx.getCType(p.getType()) + " " + p.getName() + " = " + msg.getParameters().get(paramIndex).getName() + ";\n");
paramIndex++;
}
for (LocalVariable lv : s.getSelection()) {
lv.setName(source.getName() + "_" + lv.getName());
ctx.getCompiler().getThingActionCompiler().generate(lv, builder, ctx);
}
ctx.getCompiler().getThingActionCompiler().generate(s.getOutput(), builder, ctx);
if (guardsList.size() > 0)
builder.append("}\n");
} else {
builder.append("_instance->cep_" + s.getName() + "->" + msg.getName() + "_queueEvent");
ctx.appendActualParameters(thing, builder, msg, "_instance");
builder.append(";\n");
}
// Length Window
if (shouldTriggerOnInputNumber(s, ctx))
builder.append(" _instance->cep_" + s.getName() + "->checkTrigger(_instance);\n");
// closing braces, see guards
for (int i = 0; i < nbCondition; i++) {
builder.append("}\n");
}
builder.append("//End stream dispatch\n");
ctx.resetCepMsgContext();
}
}
}
}
protected void dispatchEmptyToSubRegions(Thing thing, StringBuilder builder, CompositeState cs, CCompilerContext ctx, DebugProfile debugProfile) {
if (cs instanceof Session) return;
for (Region r : CompositeStateHelper.directSubRegions(cs)) {
builder.append("//Region " + r.getName() + "\n");
ArrayList<State> states = new ArrayList<State>();
for (State s : r.getSubstate()) if (StateHelper.hasEmptyHandlersIncludingSessions(s)) states.add(s);
for (State s : states) {
if (states.get(0) != s) builder.append("else ");
builder.append("if (" + ctx.getInstanceVarName() + "->" + ctx.getStateVarName(r) + " == " + ctx.getStateID(s) + ") {\n"); // s is the current state
// dispatch to sub-regions if it is a composite
if (s instanceof CompositeState) {
dispatchEmptyToSubRegions(thing, builder, (CompositeState) s, ctx, debugProfile);
}
// handle message locally
generateEmptyHandlers(thing, s, builder, cs, r, ctx, debugProfile);
builder.append("}\n");
}
}
}
protected void dispatchEmptyToSessions(Thing thing, StringBuilder builder, CompositeState cs, CCompilerContext ctx, DebugProfile debugProfile) {
//for (Region r : CompositeStateHelper.directSubSessions(cs)) {
for (Region r : CompositeStateHelper.allContainedSessions(cs)) {
builder.append("//Session " + r.getName() + "\n");
ArrayList<State> states = new ArrayList<State>();
for (State s : r.getSubstate()) if (StateHelper.hasEmptyHandlersIncludingSessions(s)) states.add(s);
for (State s : states) {
if (states.get(0) != s) builder.append("else ");
builder.append("if (" + ctx.getInstanceVarName() + "->" + ctx.getStateVarName(r) + " == " + ctx.getStateID(s) + ") {\n"); // s is the current state
// dispatch to sub-regions if it is a composite
if (s instanceof CompositeState) {
dispatchEmptyToSubRegions(thing, builder, (CompositeState) s, ctx, debugProfile);
}
// handle message locally
generateEmptyHandlers(thing, s, builder, cs, r, ctx, debugProfile);
builder.append("}\n");
}
}
}
public void generateEmptyHandlers(Thing thing, State s, StringBuilder builder, CompositeState cs, Region r, CCompilerContext ctx, DebugProfile debugProfile) {
boolean first = true;
// Gather all the empty transitions
ArrayList<Handler> transitions = new ArrayList<Handler>();
for (Transition t : s.getOutgoing()) if (t.getEvent().isEmpty()) transitions.add(t);
for (InternalTransition t : s.getInternal()) if (t.getEvent().isEmpty()) transitions.add(t);
for (Handler h : transitions) {
if (first) first = false;
else builder.append("else ");
builder.append("if (");
if (h.getGuard() != null) ctx.getCompiler().getThingActionCompiler().generate(h.getGuard(), builder, ctx);
else builder.append("1");
builder.append(") {\n");
if (h instanceof InternalTransition) {
InternalTransition it = (InternalTransition) h;
if (debugProfile.isDebugBehavior()) {
builder.append(thing.getName() + "_print_debug(" + ctx.getInstanceVarName() + ", \""
+ ctx.traceInternal(thing) + "\\n\");\n");
}
ctx.getCompiler().getThingActionCompiler().generate(it.getAction(), builder, ctx);
builder.append("return 1;\n");
} else if (h instanceof Transition) {
Transition et = (Transition) h;
if (debugProfile.isDebugBehavior()) {
builder.append(thing.getName() + "_print_debug(" + ctx.getInstanceVarName() + ", \""
+ ctx.traceTransition(thing, et) + "\\n\");\n");
}
// Execute the exit actions for current states (starting at the deepest)
builder.append(ThingMLElementHelper.qname(ThingMLHelpers.allStateMachines(thing).get(0), "_") + "_OnExit(" + ctx.getStateID(et.getSource()) + ", " + ctx.getInstanceVarName() + ");\n");
// Set the new current state
builder.append(ctx.getInstanceVarName() + "->" + ctx.getStateVarName(r) + " = " + ctx.getStateID(et.getTarget()) + ";\n");
// Do the action
ctx.getCompiler().getThingActionCompiler().generate(et.getAction(), builder, ctx);
// Enter the target state and initialize its children
builder.append(ThingMLElementHelper.qname(ThingMLHelpers.allStateMachines(thing).get(0), "_") + "_OnEntry(" + ctx.getStateID(et.getTarget()) + ", " + ctx.getInstanceVarName() + ");\n");
//New Empty Event Method
builder.append("return 1;\n");
}
builder.append("}\n");
}
}
protected void dispatchToSessions(Thing thing, StringBuilder builder, CompositeState cs, Port port, Message msg, CCompilerContext ctx, DebugProfile debugProfile) {
builder.append("//Session list: ");
for (Region r : CompositeStateHelper.allContainedSessions(cs)) {
builder.append(r.getName() + " ");
}
builder.append("\n");
for (Region r : CompositeStateHelper.allContainedSessions(cs)) {
builder.append("//Session " + r.getName() + "\n");
builder.append("uint8_t " + ctx.getStateVarName(r) + "_event_consumed = 0;\n");
// for all states of the region, if the state can handle the message and that state is active we forward the message
/*if (CompositeStateHelper.allContainedSessions(cs).get(0) == r) {
builder.append("uint8_t " + ctx.getStateVarName(r) + "_event_consumed = 0;\n");
}*/
ArrayList<State> states = new ArrayList<State>();
for (State s : r.getSubstate()) if (StateHelper.canHandleIncludingSessions(s, port, msg)) states.add(s);
for (State s : states) {
if (states.get(0) != s) builder.append("else ");
builder.append("if (" + ctx.getInstanceVarName() + "->" + ctx.getStateVarName(r) + " == " + ctx.getStateID(s) + ") {\n"); // s is the current state
if (s instanceof CompositeState) {
dispatchToSubRegions(thing, builder, (CompositeState) s, port, msg, ctx, debugProfile);
}
generateMessageHandlers(thing, s, port, msg, builder, cs, r, ctx, debugProfile);
builder.append("}\n");
}
builder.append("//End Session " + r.getName() + "\n");
}
/*if (cs.eContainer() instanceof Region) {
builder.append(ctx.getStateVarName((Region) cs.eContainer()) + "_event_consumed = 0 ");
for (Region r : CompositeStateHelper.directSubRegions(cs)) {
// for all states of the region, if the state can handle the message and that state is active we forward the message
builder.append("| " + ctx.getStateVarName(r) + "_event_consumed ");
}
builder.append(";\n");
}*/
}
protected void dispatchToSubRegions(Thing thing, StringBuilder builder, CompositeState cs, Port port, Message msg, CCompilerContext ctx, DebugProfile debugProfile) {
/* builder.append("//Region list: " );
for (Region r : CompositeStateHelper.directSubRegions(cs)) {
builder.append(r.getName() + " ");
}
builder.append("\n");*/
for (Region r : CompositeStateHelper.directSubRegions(cs)) {
if (!(r instanceof Session)) {
builder.append("//Region " + r.getName() + "\n");
// for all states of the region, if the state can handle the message and that state is active we forward the message
builder.append("uint8_t " + ctx.getStateVarName(r) + "_event_consumed = 0;\n");
ArrayList<State> states = new ArrayList<State>();
for (State s : r.getSubstate()) if (StateHelper.canHandle(s, port, msg)) states.add(s);
for (State s : states) {
if (states.get(0) != s) builder.append("else ");
builder.append("if (" + ctx.getInstanceVarName() + "->" + ctx.getStateVarName(r) + " == " + ctx.getStateID(s) + ") {\n"); // s is the current state
if (s instanceof CompositeState) {
dispatchToSubRegions(thing, builder, (CompositeState) s, port, msg, ctx, debugProfile);
}
generateMessageHandlers(thing, s, port, msg, builder, cs, r, ctx, debugProfile);
builder.append("}\n");
}
builder.append("//End Region " + r.getName() + "\n");
}
}
if ((cs.eContainer() instanceof Region) && (!(cs.eContainer() instanceof Session))) {
builder.append(ctx.getStateVarName((Region) cs.eContainer()) + "_event_consumed = 0 ");
for (Region r : CompositeStateHelper.directSubRegions(cs)) {
// for all states of the region, if the state can handle the message and that state is active we forward the message
builder.append("| " + ctx.getStateVarName(r) + "_event_consumed ");
}
builder.append(";\n");
}
builder.append("//End dsregion " + cs.getName() + "\n");
}
protected void generateMessageHandlers(Thing thing, State s, Port port, Message msg, StringBuilder builder, CompositeState cs, Region r, CCompilerContext ctx, DebugProfile debugProfile) {
boolean first = true;
// Gather all the handlers
ArrayList<Handler> transitions = new ArrayList<Handler>();
transitions.addAll(s.getOutgoing());
transitions.addAll(s.getInternal());
// Gather of the events of the reception of the message
ArrayList<ReceiveMessage> events = new ArrayList<ReceiveMessage>();
for (Handler t : transitions) {
for (Event e : t.getEvent()) {
if (e instanceof ReceiveMessage) {
ReceiveMessage rm = (ReceiveMessage) e;
if (rm.getPort() == port && rm.getMessage() == msg) events.add(rm);
}
}
}
// Generate code for each of those events
for (ReceiveMessage mh : events) {
Handler h = ThingMLElementHelper.findContainingHandler(mh);
if (first) first = false;
else builder.append("else ");
if (cs != null) builder.append("if (" + ctx.getStateVarName(r) + "_event_consumed == 0 && ");
else builder.append("if (");
if (h.getGuard() != null) ctx.getCompiler().getThingActionCompiler().generate(h.getGuard(), builder, ctx);
else builder.append("1");
builder.append(") {\n");
if (h instanceof InternalTransition) {
if (debugProfile.isDebugBehavior()) {
builder.append(thing.getName() + "_print_debug(" + ctx.getInstanceVarName() + ", \""
+ ctx.traceInternal(thing, port, msg) + "\\n\");\n");
}
InternalTransition it = (InternalTransition) h;
ctx.getCompiler().getThingActionCompiler().generate(it.getAction(), builder, ctx);
if (r != null) builder.append(ctx.getStateVarName(r) + "_event_consumed = 1;\n");
} else if (h instanceof Transition) {
Transition et = (Transition) h;
if (debugProfile.isDebugBehavior()) {
builder.append(thing.getName() + "_print_debug(" + ctx.getInstanceVarName() + ", \""
+ ctx.traceTransition(thing, et, port, msg) + "\\n\");\n");
}
// Execute the exit actions for current states (starting at the deepest)
builder.append(ThingMLElementHelper.qname(ThingMLHelpers.allStateMachines(thing).get(0), "_") + "_OnExit(" + ctx.getStateID(et.getSource()) + ", " + ctx.getInstanceVarName() + ");\n");
// Set the new current state
builder.append(ctx.getInstanceVarName() + "->" + ctx.getStateVarName(r) + " = " + ctx.getStateID(et.getTarget()) + ";\n");
// Do the action
ctx.getCompiler().getThingActionCompiler().generate(et.getAction(), builder, ctx);
// Enter the target state and initialize its children
builder.append(ThingMLElementHelper.qname(ThingMLHelpers.allStateMachines(thing).get(0), "_") + "_OnEntry(" + ctx.getStateID(et.getTarget()) + ", " + ctx.getInstanceVarName() + ");\n");
// The event has been consumed
if (r != null) builder.append(ctx.getStateVarName(r) + "_event_consumed = 1;\n");
}
builder.append("}\n");
}
}
protected void generatePrivateMessageSendingOperations(Thing thing, StringBuilder builder, CCompilerContext ctx, DebugProfile debugProfile) {
// NB sdalgard - Incorporated C++ prototypes
StringBuilder cppHeaderBuilder = ctx.getCppHeaderCode();
if (isGeneratingCpp()) {
cppHeaderBuilder.append("// Observers for outgoing messages:\n");
}
for (Port port : ThingMLHelpers.allPorts(thing)) {
for (Message msg : port.getSends()) {
if (isGeneratingCpp()) {
// Variable for the function pointer
cppHeaderBuilder.append("//generatePrivateMessageSendingOperations\nvoid (" + getCppNameScope() + "*" + ctx.getSenderName(thing, port, msg) + "_listener)");
ctx.appendFormalTypeSignature(thing, cppHeaderBuilder, msg);
cppHeaderBuilder.append(";\n");
// Variable for the external function pointer
cppHeaderBuilder.append("//generatePrivateMessageSendingOperations2\nvoid (" + getCppNameScope() + "*external_" + ctx.getSenderName(thing, port, msg) + "_listener)");
ctx.appendFormalTypeSignature(thing, cppHeaderBuilder, msg);
cppHeaderBuilder.append(";\n");
cppHeaderBuilder.append("void " + ctx.getSenderName(thing, port, msg));
ctx.appendFormalParameters(thing, cppHeaderBuilder, msg);
cppHeaderBuilder.append(";\n");
}
if (!isGeneratingCpp()) {
//for external messages
//var
builder.append("void (*external_" + ctx.getSenderName(thing, port, msg) + "_listener)");
ctx.appendFormalTypeSignature(thing, builder, msg);
builder.append("= 0x0;\n");
// Variable for the function pointer
builder.append("void (*" + ctx.getSenderName(thing, port, msg) + "_listener)");
ctx.appendFormalTypeSignature(thing, builder, msg);
builder.append("= 0x0;\n");
}
//register
builder.append("void " + getCppNameScope() + "register_external_" + ctx.getSenderName(thing, port, msg) + "_listener(");
builder.append("void (" + getCppNameScope() + "*_listener)");
ctx.appendFormalTypeSignature(thing, builder, msg);
builder.append("){\n");
builder.append("external_" + ctx.getSenderName(thing, port, msg) + "_listener = _listener;\n");
builder.append("}\n");
builder.append("void " + getCppNameScope() + "register_" + ctx.getSenderName(thing, port, msg) + "_listener(");
builder.append("void (" + getCppNameScope() + "*_listener)");
ctx.appendFormalTypeSignature(thing, builder, msg);
builder.append("){\n");
builder.append("" + ctx.getSenderName(thing, port, msg) + "_listener = _listener;\n");
builder.append("}\n");
// Operation which calls on the function pointer if it is not NULL
builder.append("void " + getCppNameScope() + ctx.getSenderName(thing, port, msg));
ctx.appendFormalParameters(thing, builder, msg);
builder.append("{\n");
// if (timer_receive_timeout_listener != 0) timer_receive_timeout_listener(timer_id);
//if(ctx.isToBeDebugged(ctx.getCurrentConfiguration(), thing, port, msg)) {
if (debugProfile.getDebugMessages().containsKey(port)) {
if (debugProfile.getDebugMessages().get(port).contains(msg)) {
builder.append(thing.getName() + "_print_debug(" + ctx.getInstanceVarName() + ", \""
+ ctx.traceSendMessage(thing, port, msg) + "\\n\");\n");
}
}
if (!isGeneratingCpp()) {
builder.append("if (" + ctx.getSenderName(thing, port, msg) + "_listener != 0x0) " + ctx.getSenderName(thing, port, msg) + "_listener");
} else {
builder.append("if (" + ctx.getSenderName(thing, port, msg) + "_listener != 0x0) (this->*" + ctx.getSenderName(thing, port, msg) + "_listener)");
}
ctx.appendActualParameters(thing, builder, msg, null);
builder.append(";\n");
if (!isGeneratingCpp()) {
builder.append("if (external_" + ctx.getSenderName(thing, port, msg) + "_listener != 0x0) external_" + ctx.getSenderName(thing, port, msg) + "_listener");
} else {
builder.append("if (external_" + ctx.getSenderName(thing, port, msg) + "_listener != 0x0) (this->*external_" + ctx.getSenderName(thing, port, msg) + "_listener)");
}
ctx.appendActualParameters(thing, builder, msg, null);
builder.append(";\n");
builder.append(";\n}\n");
}
}
if (isGeneratingCpp()) {
cppHeaderBuilder.append("\n");
}
builder.append("\n");
}
protected void generateCppMessageSendingInit(Thing thing, StringBuilder builder, CCompilerContext ctx) {
// NB sdalgard - This function is derivated from generatePrivateMessageSendingOperations
for (Port port : ThingMLHelpers.allPorts(thing)) {
for (Message msg : port.getSends()) {
builder.append("" + ctx.getSenderName(thing, port, msg) + "_listener = 0x0;\n");
builder.append("external_" + ctx.getSenderName(thing, port, msg) + "_listener = 0x0;\n");
}
}
builder.append("\n");
}
private void generateSessionTerminate(Thing thing, StringBuilder builder, CCompilerContext ctx, DebugProfile debugProfile) {
if(RegionHelper.allContainedSessions(ThingMLHelpers.allStateMachines(thing).get(0)).size() > 0) {
builder.append("void " + thing.getName() + "_terminate(struct " + ctx.getInstanceStructName(thing) + " * _instance) {\n");
for(Session s : RegionHelper.allContainedSessions(ThingMLHelpers.allStateMachines(thing).get(0))) {
builder.append(" _instance->active = false;\n");
builder.append(" uint16_t index_" + s.getName() + " = 0;\n");
builder.append(" while(index_" + s.getName() + " < _instance->nb_max_sessions_" + s.getName() + ") {\n");
builder.append(" " + thing.getName() + "_terminate(&(_instance->sessions_" + s.getName() + "[index_" + s.getName() + "]));\n");
builder.append(" index_" + s.getName() + "++;\n");
builder.append(" }\n");
}
builder.append("}\n\n");
}
}
private void generateSessionForks(Thing thing, StringBuilder builder, CCompilerContext ctx, DebugProfile debugProfile) {
for(Session s : RegionHelper.allContainedSessions(ThingMLHelpers.allStateMachines(thing).get(0))) {
builder.append("int " + thing.getName() + "_fork_" + s.getName() + "(struct " + ctx.getInstanceStructName(thing) + " * _instance) {\n");
builder.append(" struct " + ctx.getInstanceStructName(thing) + " * new_session = NULL;\n");
builder.append(" uint16_t index_s = 0;\n");
builder.append(" while(index_s < _instance->nb_max_sessions_" + s.getName() + ") {\n");
builder.append(" if(!(_instance->sessions_" + s.getName() + "[index_s].active)) {\n");
builder.append(" new_session = &(_instance->sessions_" + s.getName() + "[index_s]);\n");
builder.append(" break;\n");
builder.append(" }\n");
builder.append(" index_s++;\n");
builder.append(" }\n\n");
builder.append(" if(new_session == NULL)\n");
builder.append(" return -1;\n\n");
builder.append(" new_session->active = true;\n\n");
builder.append(" //Copy of properties\n");
for (Property p : ThingHelper.allPropertiesInDepth(thing)) {
if (!p.isIsArray()) {//Not an array
builder.append("new_session->" + ctx.getVariableName(p) + " = ");
builder.append("_instance->" + ctx.getVariableName(p));
builder.append(";\n");
} else {
builder.append("new_session->" + ctx.getVariableName(p) + "_size = ");
builder.append("_instance->" + ctx.getVariableName(p) + "_size");
builder.append(";\n");
builder.append("memcpy(&(new_session->" + ctx.getVariableName(p) + "[0]), "
+ "&(_instance->" + ctx.getVariableName(p) + "[0]), _instance->"
+ ctx.getVariableName(p) + "_size * sizeof(" + ctx.getCType(p.getType()) + "));\n");
}
}
builder.append(" //Copy of port id\n");
for (Port p : ThingMLHelpers.allPorts(thing)) {
builder.append("new_session->id_");
builder.append(p.getName());
builder.append(" = _instance->id_");
builder.append(p.getName());
builder.append(";\n");
}
builder.append(" new_session->" + ctx.getStateVarName(ThingMLHelpers.allStateMachines(thing).get(0)) + " = " + ctx.getStateID(s.getInitial()) + ";\n");
StateMachine sm = ThingMLHelpers.allStateMachines(thing).get(0);
for(Region r : RegionHelper.allContainedRegionsAndSessions(sm)) {
if((!RegionHelper.allContainedRegionsAndSessions(s).contains(r)) || ((r instanceof Session) && (r != s))) {
builder.append(" new_session->" + ctx.getStateVarName(r) + " = -1;\n");
} else {
builder.append(" new_session->" + ctx.getStateVarName(r) + " = " + ctx.getStateID(r.getInitial()) + ";\n");
}
}
if (ThingMLHelpers.allStateMachines(thing).size() > 0) { // there is a state machine
builder.append(" " + ThingMLElementHelper.qname(sm, "_") + "_OnEntry(" + ctx.getStateID(s) + ", new_session);\n");
}
builder.append(" return 0;\n");
builder.append("}\n");
builder.append("\n");
}
}
public void generateSessionHandlerCalls(Thing thing, Port port, Message msg, CCompilerContext ctx, StringBuilder builder) {
builder.append("if(!(_instance->active)) return;\n");
for(Session s: RegionHelper.allContainedSessions(ThingMLHelpers.allStateMachines(thing).get(0))) {
builder.append("uint16_t index_" + s.getName() + " = 0;\n");
builder.append("while(index_" + s.getName() + " < _instance->nb_max_sessions_" + s.getName() + ") {\n");
builder.append(" " + ctx.getHandlerName(thing, port, msg) + "(");
builder.append("&(_instance->sessions_" + s.getName() + "[index_" + s.getName() + "])");
for(Parameter p : msg.getParameters()) {
builder.append(", " + p.getName());
}
builder.append(");\n");
builder.append(" index_" + s.getName() + "++;\n");
builder.append("}\n");
}
}
public void generateSessionEmptyHandlerCalls(Thing thing, CCompilerContext ctx, StringBuilder builder) {
builder.append("if(!(_instance->active)) return 0;\n");
for(Session s: RegionHelper.allContainedSessions(ThingMLHelpers.allStateMachines(thing).get(0))) {
builder.append("uint16_t index_" + s.getName() + " = 0;\n");
builder.append("while(index_" + s.getName() + " < _instance->nb_max_sessions_" + s.getName() + ") {\n");
builder.append(" empty_event_consumed |= " + ctx.getEmptyHandlerName(thing) + "(");
builder.append("&(_instance->sessions_" + s.getName() + "[index_" + s.getName() + "])");
builder.append(");\n");
builder.append(" index_" + s.getName() + "++;\n");
builder.append("}\n");
}
}
public void generateKillChildren(Thing thing, StringBuilder builder) {
if(RegionHelper.allContainedSessions(ThingMLHelpers.allStateMachines(thing).get(0)).size() > 0) {
builder.append(thing.getName() + "_terminate(_instance);\n");
}
}
}