diff --git a/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/typesystem/infra/AbstractSizeInferrer.xtend b/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/typesystem/infra/AbstractSizeInferrer.xtend index 3f6af352..bf7d2380 100644 --- a/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/typesystem/infra/AbstractSizeInferrer.xtend +++ b/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/typesystem/infra/AbstractSizeInferrer.xtend @@ -3,6 +3,7 @@ package org.eclipse.mita.base.typesystem.infra import org.eclipse.emf.ecore.EObject import org.eclipse.emf.ecore.resource.Resource import org.eclipse.mita.base.types.TypeSpecifier +import org.eclipse.mita.base.types.validation.IValidationIssueAcceptor.ValidationIssue import org.eclipse.mita.base.typesystem.constraints.MaxConstraint import org.eclipse.mita.base.typesystem.constraints.SumConstraint import org.eclipse.mita.base.typesystem.solver.ConstraintSolution @@ -12,7 +13,6 @@ import org.eclipse.mita.base.typesystem.types.TypeVariable import org.eclipse.xtend.lib.annotations.Accessors import org.eclipse.xtend.lib.annotations.EqualsHashCode import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor -import org.eclipse.mita.base.types.validation.IValidationIssueAcceptor.ValidationIssue abstract class AbstractSizeInferrer { def ConstraintSolution createSizeConstraints(ConstraintSolution cs, Resource r); @@ -72,9 +72,9 @@ interface TypeSizeInferrer extends FunctionSizeInferrer { def Iterable validateSizeInference(Resource r, ConstraintSystem system, EObject origin, AbstractType type); } -@FinalFieldsConstructor @Accessors @EqualsHashCode +@FinalFieldsConstructor class InferenceContext { val ConstraintSystem system; val Resource r; diff --git a/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/typesystem/solver/Substitution.xtend b/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/typesystem/solver/Substitution.xtend index 6523d258..0b4349ad 100644 --- a/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/typesystem/solver/Substitution.xtend +++ b/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/typesystem/solver/Substitution.xtend @@ -182,9 +182,6 @@ class Substitution { } def void addToContent(TypeVariable tv, AbstractType typ) { - if(tv.idx == 2679 && typ.toString == "uint32") { - print("") - } content.put(tv.idx, typ); idxToTypeVariable.put(tv.idx, tv); val freeVars = typ.freeVars; diff --git a/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/ArrayGenerator.xtend b/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/ArrayGenerator.xtend index a468df8d..dcd6ceec 100644 --- a/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/ArrayGenerator.xtend +++ b/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/ArrayGenerator.xtend @@ -345,6 +345,7 @@ class ArrayGenerator extends AbstractTypeGenerator { @Inject protected CodeFragmentProvider codeFragmentProvider + @Inject protected extension StatementGenerator override generate(CodeWithContext resultVariable, ElementReferenceExpression functionCall) { diff --git a/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/GenericContainerSizeInferrer.xtend b/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/GenericContainerSizeInferrer.xtend index 6ec16ec1..a3dcc849 100644 --- a/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/GenericContainerSizeInferrer.xtend +++ b/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/GenericContainerSizeInferrer.xtend @@ -255,6 +255,9 @@ abstract class GenericContainerSizeInferrer implements TypeSizeInferrer { dispatch def void doCreateConstraints(InferenceContext c, EObject obj, AbstractType t) { delegate.createConstraints(c); } + dispatch def void doCreateConstraints(InferenceContext c, Void obj, AbstractType t) { + delegate.createConstraints(c); + } // create max constraints for all sizes override createConstraintsForMax(ConstraintSystem system, Resource r, MaxConstraint constraint) { diff --git a/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/GenericPlatformSizeInferrer.xtend b/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/GenericPlatformSizeInferrer.xtend index a88ecf49..95edee94 100644 --- a/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/GenericPlatformSizeInferrer.xtend +++ b/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/GenericPlatformSizeInferrer.xtend @@ -4,31 +4,32 @@ import com.google.inject.Inject import org.eclipse.emf.ecore.EObject import org.eclipse.mita.base.expressions.ElementReferenceExpression import org.eclipse.mita.base.types.Variance -import org.eclipse.mita.base.types.validation.IValidationIssueAcceptor.ValidationIssue import org.eclipse.mita.base.typesystem.StdlibTypeRegistry -import org.eclipse.mita.base.typesystem.constraints.EqualityConstraint import org.eclipse.mita.base.typesystem.infra.FunctionSizeInferrer import org.eclipse.mita.base.typesystem.infra.InferenceContext +import org.eclipse.mita.base.typesystem.infra.TypeSizeInferrer import org.eclipse.mita.base.typesystem.types.AbstractType import org.eclipse.mita.base.typesystem.types.AtomicType import org.eclipse.mita.base.typesystem.types.FunctionType import org.eclipse.mita.base.typesystem.types.LiteralNumberType import org.eclipse.mita.base.typesystem.types.ProdType import org.eclipse.mita.base.typesystem.types.TypeConstructorType +import org.eclipse.mita.library.stdlib.functions.SignalInstanceSizeInferrer import org.eclipse.mita.platform.Signal +import org.eclipse.mita.program.EventHandlerDeclaration +import org.eclipse.mita.program.EventHandlerVariableDeclaration import org.eclipse.mita.program.SignalInstance +import org.eclipse.mita.program.SystemEventSource +import org.eclipse.mita.program.SystemResourceSetup import org.eclipse.mita.program.inferrer.StaticValueInferrer import org.eclipse.mita.program.model.ModelUtils import org.eclipse.xtend.lib.annotations.Accessors +import org.eclipse.xtext.EcoreUtil2 import static extension org.eclipse.mita.base.util.BaseUtils.castOrNull import static extension org.eclipse.mita.base.util.BaseUtils.init -import org.eclipse.mita.base.typesystem.constraints.ExplicitInstanceConstraint -import org.eclipse.xtext.EcoreUtil2 -import org.eclipse.mita.program.SystemResourceSetup -import org.eclipse.mita.base.types.NamedElement -import org.eclipse.mita.library.stdlib.functions.SignalInstanceSizeInferrer -import org.eclipse.mita.base.typesystem.infra.TypeSizeInferrer +import org.eclipse.mita.program.inferrer.ProgramSizeInferrer +import org.eclipse.mita.base.typesystem.solver.ConstraintSystem /** * This inferrer can handle all types in the stdlib, so if you're returning @@ -53,13 +54,10 @@ class GenericPlatformSizeInferrer implements FunctionSizeInferrer { return 'length'; } - - - protected dispatch def void doCreateConstraints(InferenceContext c, SignalInstance instance, TypeConstructorType type) { - if(!#["string", "array"].contains(type.name)) { - return; + protected def AbstractType computeSigInstDataType(ConstraintSystem system, SignalInstance instance, TypeConstructorType scheme) { + if(!#["string", "array"].contains(scheme.name)) { + return null; } - val lengthArg = ModelUtils.getArgumentValue(instance, instance.lengthParameterName); if(lengthArg !== null) { val maxLength = StaticValueInferrer.infer(lengthArg, [ ])?.castOrNull(Long); @@ -67,31 +65,64 @@ class GenericPlatformSizeInferrer implements FunctionSizeInferrer { val u32 = typeRegistry.getTypeModelObject(instance, StdlibTypeRegistry.u32TypeQID); // sigInst has type resource -> sigInst> // create string<'10> - val innerReturnType = new TypeConstructorType(instance, type.name, - type.typeArgumentsAndVariances.init + #[ - new LiteralNumberType(lengthArg, maxLength, c.system.getTypeVariable(u32)) as AbstractType -> + val innerReturnType = new TypeConstructorType(instance, scheme.name, + scheme.typeArgumentsAndVariances.init + #[ + new LiteralNumberType(lengthArg, maxLength, system.getTypeVariable(u32)) as AbstractType -> Variance.COVARIANT ] ); - // create sigInst> - val returnType = SignalInstanceSizeInferrer.wrapInSigInst(c, typeRegistry, innerReturnType); - val signal = instance.initialization?.castOrNull(ElementReferenceExpression)?.reference?.castOrNull(Signal); - val setup = EcoreUtil2.getContainerOfType(instance, SystemResourceSetup); - val systemResource = setup?.type; + return innerReturnType; + } + } + } + + protected dispatch def void doCreateConstraints(InferenceContext c, SystemEventSource eventSource, TypeConstructorType type) { + if(eventSource.signalInstance !== null) { + // we already type this via the eventVariable + return; + } + delegate.createConstraints(c); + } + protected dispatch def void doCreateConstraints(InferenceContext c, EventHandlerVariableDeclaration eventVariable, TypeConstructorType type) { + // if event is part of a signal instance, its initialization could have a size argument which we will use here + if(!#["string", "array"].contains(type.name)) { + return; + } + val eventSource = EcoreUtil2.getContainerOfType(eventVariable, EventHandlerDeclaration)?.event; + val signalInstance = eventSource?.castOrNull(SystemEventSource)?.signalInstance; + if(signalInstance !== null) { + doCreateConstraints(c, signalInstance, type); + ProgramSizeInferrer.inferUnmodifiedFrom(c.system, eventSource, eventVariable); + // signal instance is now typed. Next we need to extract its size + val typeWithSize = computeSigInstDataType(c.system, signalInstance, type); + c.system.associate(typeWithSize, eventVariable); + } + } + + protected dispatch def void doCreateConstraints(InferenceContext c, SignalInstance instance, TypeConstructorType type) { + if(!#["string", "array"].contains(type.name)) { + return; + } - val signalTv = c.system.getTypeVariable(signal); - val sigInstFunName = signal?.name + "_inst"; - // create resource -> sigInst> - val sigInstSetupType = new FunctionType( - null, - new AtomicType(instance, sigInstFunName), - new ProdType(null, new AtomicType(instance, "__args"), #[c.system.getTypeVariable(systemResource)]), - returnType - ); + val innerReturnType = computeSigInstDataType(c.system, instance, type); + if(innerReturnType !== null) { + // create sigInst> + val returnType = SignalInstanceSizeInferrer.wrapInSigInst(c, typeRegistry, innerReturnType); + val signal = instance.initialization?.castOrNull(ElementReferenceExpression)?.reference?.castOrNull(Signal); + val setup = EcoreUtil2.getContainerOfType(instance, SystemResourceSetup); + val systemResource = setup?.type; + + val sigInstFunName = signal?.name + "_inst"; + // create resource -> sigInst> + val sigInstSetupType = new FunctionType( + null, + new AtomicType(instance, sigInstFunName), + new ProdType(null, new AtomicType(instance, "__args"), #[c.system.getTypeVariable(systemResource)]), + returnType + ); // c.system.addConstraint(new EqualityConstraint(sigInstSetupType, signalTv, new ValidationIssue('''''', c.obj))) - // type sigInst - c.system.associate(sigInstSetupType, instance); - } + // type sigInst + c.system.associate(sigInstSetupType, instance); } return; diff --git a/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/RingbufferGenerator.xtend b/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/RingbufferGenerator.xtend index 3b0166ff..650c8230 100644 --- a/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/RingbufferGenerator.xtend +++ b/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/RingbufferGenerator.xtend @@ -219,7 +219,7 @@ class RingbufferGenerator extends AbstractTypeGenerator { ), true )» - «rbRef.code».length++; + ++«rbRef.code».length; ''').addHeader("MitaGeneratedTypes.h", false); } } diff --git a/bundles/org.eclipse.mita.library.stdlib/xtend-gen/.gitignore b/bundles/org.eclipse.mita.library.stdlib/xtend-gen/.gitignore index 6a5c8a7c..0479c7cb 100644 --- a/bundles/org.eclipse.mita.library.stdlib/xtend-gen/.gitignore +++ b/bundles/org.eclipse.mita.library.stdlib/xtend-gen/.gitignore @@ -1,4 +1,4 @@ # Ignore everything in this directory * # Except the gitignore -!.gitignore \ No newline at end of file +!.gitignore diff --git a/bundles/org.eclipse.mita.platform/model/platforms.xcore b/bundles/org.eclipse.mita.platform/model/platforms.xcore index b7693189..069c33a2 100644 --- a/bundles/org.eclipse.mita.platform/model/platforms.xcore +++ b/bundles/org.eclipse.mita.platform/model/platforms.xcore @@ -79,6 +79,7 @@ class ConfigurationItem extends Property { } class Signal extends Operation { + contains SystemResourceEvent[] events } class Modality extends Property { } diff --git a/bundles/org.eclipse.mita.platform/src/org/eclipse/mita/platform/PlatformDSL.xtext b/bundles/org.eclipse.mita.platform/src/org/eclipse/mita/platform/PlatformDSL.xtext index aa886236..855164a9 100644 --- a/bundles/org.eclipse.mita.platform/src/org/eclipse/mita/platform/PlatformDSL.xtext +++ b/bundles/org.eclipse.mita.platform/src/org/eclipse/mita/platform/PlatformDSL.xtext @@ -79,7 +79,9 @@ ConfigurationItem returns platform::ConfigurationItem: ; Signal returns platform::Signal: - 'signal' name=ID '(' (parameters+=SignalParameter (',' parameters+=SignalParameter)*)? ')' ':' typeSpecifier=TypeSpecifier + 'signal' name=ID '(' (parameters+=SignalParameter (',' parameters+=SignalParameter)*)? ')' ':' typeSpecifier=TypeSpecifier ('{' + (events += SystemResourceEvent)* + '}')? ; SignalParameter returns platform::SignalParameter: diff --git a/bundles/org.eclipse.mita.platform/src/org/eclipse/mita/platform/typesystem/PlatformConstraintFactory.xtend b/bundles/org.eclipse.mita.platform/src/org/eclipse/mita/platform/typesystem/PlatformConstraintFactory.xtend index dfde2ebe..fe14bcf5 100644 --- a/bundles/org.eclipse.mita.platform/src/org/eclipse/mita/platform/typesystem/PlatformConstraintFactory.xtend +++ b/bundles/org.eclipse.mita.platform/src/org/eclipse/mita/platform/typesystem/PlatformConstraintFactory.xtend @@ -89,6 +89,7 @@ class PlatformConstraintFactory extends BaseConstraintFactory { // signals are accessed like `mqtt.t.write("foo")`. // Therefore, t needs the type "(SystemResource, arg1, ...) -> siginst" // and topic needs to be of type (String, u32) -> ((SystemResource, arg1, ...) -> siginst) + sig.events.forEach[system.computeConstraints(it)]; val returnType = system.computeConstraints(sig.typeSpecifier); // \T. sigInst val sigInstType = typeRegistry.getTypeModelObjectProxy(system, sig, StdlibTypeRegistry.sigInstTypeQID); diff --git a/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/generator/tests/AllTests.java b/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/generator/tests/AllTests.java index dd98b5fa..c3bee2bc 100644 --- a/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/generator/tests/AllTests.java +++ b/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/generator/tests/AllTests.java @@ -18,18 +18,18 @@ import org.junit.runners.Suite.SuiteClasses; @SuiteClasses({ + ArraysTest.class, BasicControlStructuresTest.class, EnumsTest.class, FunctionOverloadingTest.class, + GlobalAndLocalVariables.class, + PrepareLoopForFunctionUnvravelingStageTest.class, SensorAccessTest.class, + SetupTest.class, StructsTest.class, - TryCatchGeneratorTest.class, - UnravelFunctionCallsTest.class, SumTypesTest.class, - SetupTest.class, - GlobalAndLocalVariables.class, - ArraysTest.class, - SetupTest.class + TryCatchGeneratorTest.class, + UnravelFunctionCallsTest.class }) @RunWith(Suite.class) public class AllTests { diff --git a/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/generator/tests/BasicControlStructuresTest.xtend b/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/generator/tests/BasicControlStructuresTest.xtend index 4494ef75..adee066b 100644 --- a/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/generator/tests/BasicControlStructuresTest.xtend +++ b/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/generator/tests/BasicControlStructuresTest.xtend @@ -40,7 +40,7 @@ class BasicControlStructuresTest extends AbstractGeneratorTest { ''') ast.assertNoCompileErrors(); - val generatedFunction = ast.value.findFunction("HandleEvery100Millisecond1_worker"); + val generatedFunction = ast.value.findFunction("HandleEvery100Millisecond_1_worker"); assertNotNull("No event handler was generated", generatedFunction); val body = generatedFunction.body as IASTCompoundStatement; diff --git a/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/generator/tests/PrepareLoopForFunctionUnvravelingStageTest.xtend b/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/generator/tests/PrepareLoopForFunctionUnvravelingStageTest.xtend index e83870d3..2b035d21 100644 --- a/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/generator/tests/PrepareLoopForFunctionUnvravelingStageTest.xtend +++ b/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/generator/tests/PrepareLoopForFunctionUnvravelingStageTest.xtend @@ -25,6 +25,8 @@ import org.junit.Test import static org.junit.Assert.* import org.eclipse.cdt.core.dom.ast.IASTDoStatement +import org.eclipse.cdt.core.dom.ast.IASTFunctionCallExpression +import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression class PrepareLoopForFunctionUnvravelingStageTest extends AbstractGeneratorTest { @@ -54,7 +56,7 @@ class PrepareLoopForFunctionUnvravelingStageTest extends AbstractGeneratorTest { val forCondition = forLoop.conditionExpression; assertTrue("For loop condition was not rewritten", forCondition instanceof IASTIdExpression); - assertEquals("For loop condition was not rewritten to TRUE", "TRUE", (forCondition as IASTIdExpression).name.toString()); + assertEquals("For loop condition was not rewritten to true", "true", (forCondition as IASTIdExpression).name.toString()); (forLoop.body as IASTCompoundStatement).assertHasBreakerIf(); } @@ -63,6 +65,7 @@ class PrepareLoopForFunctionUnvravelingStageTest extends AbstractGeneratorTest { def void testForLoopWithCallInPostLoopStatement() { val ast = generateAndParseApplication(''' package main; + import platforms.unittest; fn foo() { return 10; @@ -84,19 +87,23 @@ class PrepareLoopForFunctionUnvravelingStageTest extends AbstractGeneratorTest { assertNull("Post loop statement was not rewritten", forLoop.iterationExpression); - val lastStatement = (forLoop.body as IASTCompoundStatement).children.last; - assertTrue("Post loop statement is not the last statement in the loop", lastStatement instanceof IASTExpressionStatement); - val lastExpression = (lastStatement as IASTExpressionStatement).expression; - assertTrue("Post loop statement is not the last statement in the loop", lastExpression instanceof IASTBinaryExpression); - val leftOperand = (lastExpression as IASTBinaryExpression).operand1; - assertTrue("Post loop statement is not the last statement in the loop", leftOperand instanceof IASTIdExpression); - assertEquals("Post loop statement is not the last statement in the loop", "i", (leftOperand as IASTIdExpression).name.toString()); + val secondToLastStatement = (forLoop.body as IASTCompoundStatement).children.reverse.get(1); + assertTrue("Post loop statement is not the second to last statement in the loop", secondToLastStatement instanceof IASTExpressionStatement); + val secondToLastExpression = (secondToLastStatement as IASTExpressionStatement).expression; + assertTrue("Post loop statement is not the second to last statement in the loop", secondToLastExpression instanceof IASTBinaryExpression); + val fooCall = (secondToLastExpression as IASTBinaryExpression).operand2; + assertTrue("Post loop statement is not the second to last statement in the loop", fooCall instanceof IASTFunctionCallExpression); + val iRefArg = (fooCall as IASTFunctionCallExpression).arguments.head; + assertTrue("Post loop statement is not the second to last statement in the loop", iRefArg instanceof IASTUnaryExpression); + val iVariable = (iRefArg as IASTUnaryExpression).operand; + assertEquals("Post loop statement is not the second to last statement in the loop", "i", (iVariable as IASTIdExpression).name.toString()); } @Test def void testWhileLoopWithCallInCondition() { val ast = generateAndParseApplication(''' package main; + import platforms.unittest; fn foo() { return 10; @@ -119,7 +126,7 @@ class PrepareLoopForFunctionUnvravelingStageTest extends AbstractGeneratorTest { val condition = loop.condition; assertTrue("For loop condition was not rewritten", condition instanceof IASTIdExpression); - assertEquals("For loop condition was not rewritten to TRUE", "TRUE", (condition as IASTIdExpression).name.toString()); + assertEquals("For loop condition was not rewritten to true", "true", (condition as IASTIdExpression).name.toString()); (loop.body as IASTCompoundStatement).assertHasBreakerIf(); } @@ -128,6 +135,7 @@ class PrepareLoopForFunctionUnvravelingStageTest extends AbstractGeneratorTest { def void testDoWhileLoopWithCallInCondition() { val ast = generateAndParseApplication(''' package main; + import platforms.unittest; fn foo() { return 10; @@ -150,7 +158,7 @@ class PrepareLoopForFunctionUnvravelingStageTest extends AbstractGeneratorTest { val condition = loop.condition; assertTrue("For loop condition was not rewritten", condition instanceof IASTIdExpression); - assertEquals("For loop condition was not rewritten to TRUE", "TRUE", (condition as IASTIdExpression).name.toString()); + assertEquals("For loop condition was not rewritten to true", "true", (condition as IASTIdExpression).name.toString()); (loop.body as IASTCompoundStatement).assertHasBreakerIf(); } @@ -165,7 +173,7 @@ class PrepareLoopForFunctionUnvravelingStageTest extends AbstractGeneratorTest { return op.operand1 instanceof IASTIdExpression && ((op.operand1 as IASTIdExpression).name.toString() == "i"); ]; assertNotNull("No breaker if statement was generated", breakerIf); - val hasBreakStatement = (breakerIf.thenClause as IASTCompoundStatement).statements.exists[ it instanceof IASTBreakStatement ]; + val hasBreakStatement = (breakerIf.elseClause as IASTCompoundStatement).statements.exists[ it instanceof IASTBreakStatement ]; assertTrue("Breaker if has no break statement", hasBreakStatement); } diff --git a/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/generator/tests/SensorAccessTest.xtend b/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/generator/tests/SensorAccessTest.xtend index d26925fb..a6b79ded 100644 --- a/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/generator/tests/SensorAccessTest.xtend +++ b/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/generator/tests/SensorAccessTest.xtend @@ -34,7 +34,7 @@ class SensorAccessTest extends AbstractGeneratorTest { '''); ast.assertNoCompileErrors(); - val eventHandler = ast.value.findFunction("HandleEvery100Millisecond1_worker") + val eventHandler = ast.value.findFunction("HandleEvery100Millisecond_1_worker") assertNotNull("No event handler was generated", eventHandler); val body = eventHandler.body as IASTCompoundStatement; /* diff --git a/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/generator/tests/TryCatchGeneratorTest.xtend b/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/generator/tests/TryCatchGeneratorTest.xtend index 48d73d13..59f67cb6 100644 --- a/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/generator/tests/TryCatchGeneratorTest.xtend +++ b/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/generator/tests/TryCatchGeneratorTest.xtend @@ -53,7 +53,7 @@ class TryCatchGeneratorTest extends AbstractGeneratorTest { '''); ast.assertNoCompileErrors(); - val eventHandler = ast.value.findFunction("HandleEvery100Millisecond1_worker") + val eventHandler = ast.value.findFunction("HandleEvery100Millisecond_1_worker") assertNotNull("No event handler was generated", eventHandler); val body = eventHandler.body as IASTCompoundStatement; @@ -110,7 +110,7 @@ class TryCatchGeneratorTest extends AbstractGeneratorTest { '''); ast.assertNoCompileErrors(); - val eventHandler = ast.value.findFunction("HandleEvery100Millisecond1_worker") + val eventHandler = ast.value.findFunction("HandleEvery100Millisecond_1_worker") assertNotNull("No event handler was generated", eventHandler); val body = eventHandler.body as IASTCompoundStatement; @@ -225,7 +225,7 @@ class TryCatchGeneratorTest extends AbstractGeneratorTest { '''); ast.assertNoCompileErrors(); - val eventHandler = ast.value.findFunction("HandleEvery100Millisecond1_worker") + val eventHandler = ast.value.findFunction("HandleEvery100Millisecond_1_worker") assertNotNull("No event handler was generated", eventHandler); val body = eventHandler.body as IASTCompoundStatement; diff --git a/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/runtime/tests/AbstractRuntimeTest.xtend b/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/runtime/tests/AbstractRuntimeTest.xtend index f161c948..64c1dbb2 100644 --- a/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/runtime/tests/AbstractRuntimeTest.xtend +++ b/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/runtime/tests/AbstractRuntimeTest.xtend @@ -91,11 +91,15 @@ class AbstractRuntimeTest { } def Stream runAtMost(Path pathToExecutable, int timeInSeconds) { + return runAtMost(pathToExecutable, #[], timeInSeconds); + } + + def Stream runAtMost(Path pathToExecutable, String[] env, int timeInSeconds) { println("running exe..."); println(pathToExecutable); println(""); val Runtime rt = Runtime.getRuntime(); - val Process pr = rt.exec(pathToExecutable.toString); + val Process pr = rt.exec(pathToExecutable.toString, env); val output = new BufferedReader(new InputStreamReader(pr.inputStream)); pr.waitFor(timeInSeconds, TimeUnit.SECONDS); if(pr.alive) { diff --git a/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/runtime/tests/AllTests.java b/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/runtime/tests/AllTests.java index 21ac3b07..6b546483 100644 --- a/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/runtime/tests/AllTests.java +++ b/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/runtime/tests/AllTests.java @@ -18,10 +18,14 @@ import org.junit.runners.Suite.SuiteClasses; @SuiteClasses({ + ArraysTest.class, + ControlflowTest.class, + EpochTimeTest.class, HelloWorldTest.class, +// MqttTest.class, // to do this test we need some kind of MQTT broker, which is not available on jenkins + ReferencesTest.class, + RingbufferTest.class, StringTest.class, - ControlflowTest.class, - ArraysTest.class, SumTypesTest.class }) @RunWith(Suite.class) diff --git a/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/runtime/tests/EpochTimeTest.xtend b/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/runtime/tests/EpochTimeTest.xtend index f23de916..121e5850 100644 --- a/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/runtime/tests/EpochTimeTest.xtend +++ b/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/runtime/tests/EpochTimeTest.xtend @@ -43,8 +43,10 @@ class EpochTimeTest extends AbstractRuntimeTest { val executable = projectPath.resolve(Paths.get("src-gen", "build", "app")); val lines = runAtMost(executable, 60); val lastLine = lines.iterator.last; - val timeFromApp = Integer.parseInt(lastLine); - val timeFromJava = Instant.now().toEpochMilli(); - Assert.assertTrue(Math.abs(timeFromJava as int - timeFromApp) < 10); + val timeFromApp = Integer.parseInt(lastLine).intValue; + val timeFromJava = Instant.now().toEpochMilli() as int; + println('''java: «timeFromJava», testling: «timeFromApp»''') + // time difference should be less than 2s + Assert.assertTrue(Math.abs(timeFromJava - timeFromApp) < 2000); } } \ No newline at end of file diff --git a/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/runtime/tests/MqttTest.xtend b/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/runtime/tests/MqttTest.xtend new file mode 100644 index 00000000..458dc118 --- /dev/null +++ b/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/runtime/tests/MqttTest.xtend @@ -0,0 +1,63 @@ +package org.eclipse.mita.program.runtime.tests + +import java.nio.file.Paths +import java.time.Instant +import org.junit.Assert +import org.junit.Test + +import static extension org.eclipse.mita.base.util.BaseUtils.zip; +import java.util.stream.Collectors +import java.util.concurrent.TimeUnit + +class MqttTest extends AbstractRuntimeTest { + @Test + def testMe() { + val projectPath = setup("epochTimeTest", ''' + package my.pkg; + + import platforms.x86; + + setup mqtt: MQTT { + url = "tcp://localhost:1883"; + clientId = "replace_me"; + var x = topic("foo"); + } + + var ctr = 0; + + every 1 second { + mqtt.x.write(`${ctr}`); + ctr = ctr + 1; + if(ctr > 10) { + exit(0); + } + } + + every mqtt.x.msgReceived(msg) { + println(msg); + } + + native unchecked fn exit(status: int16): void header "stdlib.h"; + ''').key; + val Runtime rt = Runtime.getRuntime(); + val pahoLibUrl = "https://www.eclipse.org/downloads/download.php?file=/paho/1.4/Eclipse-Paho-MQTT-C-1.3.1-Linux.tar.gz"; + val downloadLocation = "/tmp/paho.tar.gz"; + + val wgetCommand = rt.exec(#["wget", pahoLibUrl, "-O", downloadLocation]); + wgetCommand.waitFor(60, TimeUnit.SECONDS); + + val extractCommand = rt.exec(#["tar", "xvzf", downloadLocation, "-C", projectPath.toString, "--strip-components=1"]); + extractCommand.waitFor(60, TimeUnit.SECONDS); + + compileMita(projectPath); + compileC(projectPath, "all"); + val mosquitto = rt.exec("mosquitto"); + val executable = projectPath.resolve(Paths.get("src-gen", "build", "app")); + val lines = runAtMost(executable, #["LD_LIBRARY_PATH=" + projectPath.resolve(Paths.get("lib"))], 60); + mosquitto.destroyForcibly; + val expectedLines = (0..9).map[it.toString]; + lines.collect(Collectors.toList).zip(expectedLines).forEach[ + Assert.assertEquals(it.key, it.value) + ] + } +} \ No newline at end of file diff --git a/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/runtime/tests/ReferencesTest.xtend b/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/runtime/tests/ReferencesTest.xtend index 34a7204d..a9e39a07 100644 --- a/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/runtime/tests/ReferencesTest.xtend +++ b/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/runtime/tests/ReferencesTest.xtend @@ -43,7 +43,7 @@ class ReferencesTest extends AbstractRuntimeTest { let x4: anyVec = .vec1d(1); let x5: anyVec = .vec2d(v2d(0,1)); let x6 = "foobar"; - let x7: array = [1,2,3,4]; + let x7: array = [1,2,3,4]; printRef(&x1); printRef(&x2); printRef(&x3); @@ -65,8 +65,8 @@ class ReferencesTest extends AbstractRuntimeTest { fn printRef(x: &v2d) { println(`v2d(${(*x).x}, ${(*x).y})`); - } - + } + fn printRef(a: &anyVec) { where(*a) { is(anyVec.vec0d) { diff --git a/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/runtime/tests/RingbufferTest.xtend b/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/runtime/tests/RingbufferTest.xtend index 2936f3b2..70dc1b2b 100644 --- a/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/runtime/tests/RingbufferTest.xtend +++ b/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/runtime/tests/RingbufferTest.xtend @@ -34,10 +34,10 @@ class RingbufferTest extends AbstractRuntimeTest { let a4: ringbuffer, 5>; let a5: ringbuffer, 5>, 3>; - fn report(r: &ringbuffer) { + fn report(r: &ringbuffer) { println(`${(*r).count()} ${(*r).empty()} ${(*r).full()}`); } - fn report(r: &ringbuffer) { + fn report(r: &ringbuffer) { println(`${(*r).count()} ${(*r).empty()} ${(*r).full()}`); } @@ -152,7 +152,7 @@ class RingbufferTest extends AbstractRuntimeTest { } } - fn printarray(a: array) { + fn printarray(a: array) { print("["); for(var i = 0; i < a.length(); i++) { print(`${a[i]}`); @@ -163,7 +163,7 @@ class RingbufferTest extends AbstractRuntimeTest { println("]"); } - fn printarray(a: array, _>) { + fn printarray(a: array, ?>) { print("["); for(var i = 0; i < a.length(); i++) { print(`${a[i]}`); diff --git a/bundles/org.eclipse.mita.program/model/program.xcore b/bundles/org.eclipse.mita.program/model/program.xcore index 71085190..899d5524 100644 --- a/bundles/org.eclipse.mita.program/model/program.xcore +++ b/bundles/org.eclipse.mita.program/model/program.xcore @@ -75,7 +75,7 @@ class SystemResourceSetup extends HasEvents { } op SystemResourceEvent[] getEvents() { - return ^type?.events + return ((^type?.events ?: #[]) + (signalInstances.map[it.events].filterNull.flatten ?: #[])).toEList } } @@ -93,7 +93,7 @@ class ConfigurationItemValue { /* * To get a parameter value, you need to use ModelUtils.getArgumentValue(vciv, 'paramName') */ -class SignalInstance extends VariableDeclaration { +class SignalInstance extends VariableDeclaration, HasEvents { op Signal getInstanceOf() { return if(initialization instanceof ElementReferenceExpression) { @@ -104,6 +104,13 @@ class SignalInstance extends VariableDeclaration { } } + op SystemResourceEvent[] getEvents() { + var signal = instanceOf; + if(signal !== null) { + return signal.events; + } + return #[].toEList; + } } class EventHandlerVariableDeclaration extends VariableDeclaration { @@ -133,6 +140,7 @@ class TimeIntervalEvent extends EventSource { class SystemEventSource extends EventSource { refers HasEvents origin refers SystemResourceEvent source + refers SignalInstance signalInstance op String toString() { val ref = eGet(ProgramPackage.eINSTANCE.systemEventSource_Source, false); diff --git a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/ProgramDsl.xtext b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/ProgramDsl.xtext index 97e17a1a..4565d833 100644 --- a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/ProgramDsl.xtext +++ b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/ProgramDsl.xtext @@ -118,7 +118,8 @@ enum TimeUnit returns program::TimeUnit: ; SystemEventSource returns program::SystemEventSource: - origin=[platform::HasEvents] '.' source=[types::SystemResourceEvent] + origin=[platform::HasEvents] '.' ((source=[types::SystemResourceEvent]) | + (signalInstance=[program::SignalInstance] '.' source=[types::SystemResourceEvent])) ; ReturnParameterDeclaration returns program::ReturnParameterDeclaration: diff --git a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/GeneratorUtils.xtend b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/GeneratorUtils.xtend index 59a968c8..cc23a1b6 100644 --- a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/GeneratorUtils.xtend +++ b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/GeneratorUtils.xtend @@ -22,6 +22,7 @@ import java.text.SimpleDateFormat import java.util.Date import java.util.function.Function import java.util.stream.Stream +import org.eclipse.core.runtime.NullProgressMonitor import org.eclipse.emf.ecore.EObject import org.eclipse.emf.ecore.plugin.EcorePlugin import org.eclipse.emf.ecore.resource.Resource @@ -36,8 +37,11 @@ import org.eclipse.mita.base.types.Singleton import org.eclipse.mita.base.types.StructureType import org.eclipse.mita.base.types.SumAlternative import org.eclipse.mita.base.types.SystemResourceEvent +import org.eclipse.mita.base.types.TypeReferenceSpecifier +import org.eclipse.mita.base.types.TypeSpecifier import org.eclipse.mita.base.types.TypeUtils import org.eclipse.mita.base.typesystem.BaseConstraintFactory +import org.eclipse.mita.base.typesystem.infra.MitaBaseResource import org.eclipse.mita.base.typesystem.types.AbstractType import org.eclipse.mita.base.typesystem.types.AtomicType import org.eclipse.mita.base.typesystem.types.ProdType @@ -50,6 +54,7 @@ import org.eclipse.mita.platform.InputOutput import org.eclipse.mita.platform.Modality import org.eclipse.mita.platform.Platform import org.eclipse.mita.platform.Sensor +import org.eclipse.mita.platform.Signal import org.eclipse.mita.platform.SystemResourceAlias import org.eclipse.mita.program.EventHandlerDeclaration import org.eclipse.mita.program.FunctionDefinition @@ -75,12 +80,7 @@ import org.eclipse.xtext.generator.trace.node.TextNode import org.eclipse.xtext.scoping.IScopeProvider import static extension org.eclipse.mita.base.util.BaseUtils.castOrNull -import org.eclipse.mita.base.util.BaseUtils -import org.eclipse.mita.base.types.TypeReferenceSpecifier -import org.eclipse.mita.base.types.TypeSpecifier import static extension org.eclipse.mita.base.util.BaseUtils.force -import org.eclipse.mita.base.typesystem.infra.MitaBaseResource -import org.eclipse.core.runtime.NullProgressMonitor /** * Utility functions for generating code. Eventually this will be moved into the model. @@ -155,9 +155,10 @@ class GeneratorUtils { } def getOccurrence(EObject obj) { - val EObject funDef = EcoreUtil2.getContainerOfType(obj, FunctionDefinition) as EObject - ?:EcoreUtil2.getContainerOfType(obj, EventHandlerDeclaration) as EObject - ?:EcoreUtil2.getContainerOfType(obj, Program) as EObject; + val parent = obj.eContainer; + val EObject funDef = EcoreUtil2.getContainerOfType(parent, FunctionDefinition) as EObject + ?:EcoreUtil2.getContainerOfType(parent, EventHandlerDeclaration) as EObject + ?:EcoreUtil2.getContainerOfType(parent, Program) as EObject; val result = funDef?.eAllContents?.indexed?.findFirst[it.value.equals(obj)]?.key?:(-1); return result + 1; } @@ -204,19 +205,8 @@ class GeneratorUtils { val program = EcoreUtil2.getContainerOfType(event, Program); if(program !== null) { // count event handlers, so we get unique names - var occurence = 1; - var found = false; - for(e: program.eventHandlers) { - if(e.equals(event)){ - found = true; - } - // no break; statement => need flag - // only count events with the same name - if(!found && e.baseName.equals(event.baseName)) { - occurence++; - } - } - return '''HandleEvery«event.baseName»«occurence»'''; + val occurrence = (event.eContainer as Program).eventHandlers.filter[it.event.baseName == event.event.baseName].indexed.filter[it.value === event].head.key + 1; + return '''HandleEvery«event.baseName»_«occurrence»'''; } // if we are somehow not a child of program, default to no numbering return '''HandleEvery«event.baseName»'''; @@ -369,12 +359,19 @@ class GeneratorUtils { val instanceName = origin.name; '''«instanceName.toFirstUpper»«event.source.name.toFirstUpper»''' } else { - event.source.baseName + return '''«event.origin.name.toFirstLower»«IF event.signalInstance !== null»«event.signalInstance.name.toFirstUpper»«ENDIF»«event.source.name.toFirstUpper»''' } } def dispatch String getBaseName(SystemResourceEvent event) { - return '''«(event.eContainer as AbstractSystemResource).name.toFirstUpper»«event.name.toFirstUpper»''' + var parent = event.eContainer; + if(parent instanceof AbstractSystemResource) { + return '''«parent.name.toFirstUpper»«event.name.toFirstUpper»''' + } + else if(parent instanceof Signal) { + var systemResource = parent.eContainer as AbstractSystemResource; + '''«systemResource.name.toFirstUpper»«parent.name.toFirstUpper»«event.name.toFirstUpper»''' + } } def dispatch String getBaseName(TimeIntervalEvent event) { diff --git a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/transformation/AddEventHandlerRingbufferStage.xtend b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/transformation/AddEventHandlerRingbufferStage.xtend index 366a9dbf..698ae12e 100644 --- a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/transformation/AddEventHandlerRingbufferStage.xtend +++ b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/transformation/AddEventHandlerRingbufferStage.xtend @@ -14,20 +14,23 @@ package org.eclipse.mita.program.generator.transformation import com.google.inject.Inject -import org.eclipse.emf.ecore.util.EcoreUtil +import org.eclipse.emf.ecore.EObject import org.eclipse.mita.base.expressions.ExpressionsFactory import org.eclipse.mita.base.expressions.ExpressionsPackage import org.eclipse.mita.base.types.GeneratedFunctionDefinition import org.eclipse.mita.base.types.NullTypeSpecifier import org.eclipse.mita.base.types.PresentTypeSpecifier -import org.eclipse.mita.base.types.SystemResourceEvent import org.eclipse.mita.base.types.Type +import org.eclipse.mita.base.types.TypeReferenceSpecifier import org.eclipse.mita.base.types.TypesFactory import org.eclipse.mita.base.types.TypesPackage +import org.eclipse.mita.base.typesystem.types.AbstractType +import org.eclipse.mita.base.typesystem.types.LiteralNumberType +import org.eclipse.mita.base.typesystem.types.LiteralTypeExpression +import org.eclipse.mita.base.typesystem.types.TypeConstructorType import org.eclipse.mita.base.typesystem.types.TypeVariable import org.eclipse.mita.base.util.BaseUtils import org.eclipse.mita.platform.AbstractSystemResource -import org.eclipse.mita.platform.SystemSpecification import org.eclipse.mita.program.EventHandlerDeclaration import org.eclipse.mita.program.Program import org.eclipse.mita.program.ProgramFactory @@ -129,6 +132,37 @@ class AddEventHandlerRingbufferStage extends AbstractTransformationStage { block.content.addAll(0, popCallStmts); } + protected dispatch def PresentTypeSpecifier typeToTypeSpecifier((String) => EObject scopeLookup, TypeConstructorType type) { + val ts = _typeToTypeSpecifier(scopeLookup, type as AbstractType) as TypeReferenceSpecifier; + ts.typeArguments += type.typeArguments.tail.map[typeToTypeSpecifier(scopeLookup, it)] + return ts; + } + protected dispatch def PresentTypeSpecifier typeToTypeSpecifier((String) => EObject scopeLookup, LiteralNumberType type) { + return _typeToTypeSpecifier(scopeLookup, type.value); + } + protected dispatch def PresentTypeSpecifier typeToTypeSpecifier((String) => EObject scopeLookup, LiteralTypeExpression type) { + val literalValue = type.eval; + return typeToTypeSpecifier(scopeLookup, literalValue); + } + protected dispatch def PresentTypeSpecifier typeToTypeSpecifier((String) => EObject scopeLookup, Long longLiteral) { + val ef = ExpressionsFactory.eINSTANCE; + val tf = TypesFactory.eINSTANCE; + + val sizeTypeSpecifier = tf.createTypeExpressionSpecifier; + val sizeExpression = ef.createPrimitiveValueExpression; + val sizeLiteral = ef.createIntLiteral; + sizeLiteral.value = longLiteral; + sizeExpression.value = sizeLiteral; + sizeTypeSpecifier.value = sizeExpression; + return sizeTypeSpecifier; + } + protected dispatch def PresentTypeSpecifier typeToTypeSpecifier((String) => EObject scopeLookup, AbstractType type) { + val tf = TypesFactory.eINSTANCE; + val ts = tf.createTypeReferenceSpecifier; + ts.type = scopeLookup.apply(type.name)?.castOrNull(Type); + return ts; + } + protected def VariableDeclaration addRingbufferDeclaration(EventHandlerDeclaration decl) { val type = BaseUtils.getType(decl.event.computeOrigin); if(type === null || type instanceof TypeVariable) { @@ -148,8 +182,8 @@ class AddEventHandlerRingbufferStage extends AbstractTransformationStage { } val scope = scopeProvider.getScope(decl, TypesPackage.eINSTANCE.typeReferenceSpecifier_Type); - val rbTypeDescription = scope.getElements(QualifiedName.create("ringbuffer")).head; - val rbType = rbTypeDescription?.EObjectOrProxy?.castOrNull(Type); + val (String) => EObject scopeLookupFun = [scope.getElements(QualifiedName.create(it)).head?.EObjectOrProxy]; + val rbType = scopeLookupFun.apply("ringbuffer")?.castOrNull(Type); if(rbType === null || rbType instanceof NullTypeSpecifier) { println("ringbuffer not found"); return null; @@ -157,27 +191,19 @@ class AddEventHandlerRingbufferStage extends AbstractTransformationStage { val pf = ProgramFactory.eINSTANCE; val tf = TypesFactory.eINSTANCE; - val ef = ExpressionsFactory.eINSTANCE; // let rb_everyButtonOnePressed... val rbDeclaration = pf.createVariableDeclaration; - rbDeclaration.name = "rb_" + decl.baseName; + rbDeclaration.name = "rb_" + decl.handlerName; rbDeclaration.writeable = false; // : ringbuffer<... val rbTypeSpecifier = tf.createTypeReferenceSpecifier; rbTypeSpecifier.type = rbType; // bool, ... - rbTypeSpecifier.typeArguments += EcoreUtil.copy(eventTypeSpec) as PresentTypeSpecifier; - + rbTypeSpecifier.typeArguments += typeToTypeSpecifier(scopeLookupFun, type); // 10>; - val sizeTypeSpecifier = tf.createTypeExpressionSpecifier; - val sizeExpression = ef.createPrimitiveValueExpression; - val sizeLiteral = ef.createIntLiteral; - sizeLiteral.value = queueSizeProvider.getEventHandlerPayloadQueueSize(decl); - sizeExpression.value = sizeLiteral; - sizeTypeSpecifier.value = sizeExpression; - rbTypeSpecifier.typeArguments += sizeTypeSpecifier; + rbTypeSpecifier.typeArguments += typeToTypeSpecifier(scopeLookupFun, queueSizeProvider.getEventHandlerPayloadQueueSize(decl)); rbDeclaration.typeSpecifier = rbTypeSpecifier; diff --git a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/transformation/UnravelFunctionCallsStage.xtend b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/transformation/UnravelFunctionCallsStage.xtend index 3b1f1738..c60948ad 100644 --- a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/transformation/UnravelFunctionCallsStage.xtend +++ b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/transformation/UnravelFunctionCallsStage.xtend @@ -80,7 +80,7 @@ class UnravelFunctionCallsStage extends AbstractUnravelingStage { if( parent instanceof VariableDeclaration) { // variable declarations are safe, unless they are loop variables. return parent.eContainer instanceof AbstractLoopStatement; - } else if((parent instanceof AssignmentExpression && parent.eContainer instanceof ExpressionStatement)) { + } else if((parent instanceof AssignmentExpression && parent.eContainer instanceof ExpressionStatement && parent.eContainer.eContainer instanceof ProgramBlock)) { return false; } diff --git a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/inferrer/ProgramSizeInferrer.xtend b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/inferrer/ProgramSizeInferrer.xtend index 853938fb..acb015ff 100644 --- a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/inferrer/ProgramSizeInferrer.xtend +++ b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/inferrer/ProgramSizeInferrer.xtend @@ -83,6 +83,7 @@ import org.eclipse.xtext.diagnostics.Severity import static extension org.eclipse.mita.base.util.BaseUtils.castOrNull import static extension org.eclipse.mita.base.util.BaseUtils.force import static extension org.eclipse.mita.base.util.BaseUtils.zip +import org.eclipse.mita.base.types.SystemResourceEvent /** * Hierarchically infers the size of a data element. @@ -200,6 +201,26 @@ class ProgramSizeInferrer extends AbstractSizeInferrer implements TypeSizeInferr it?.setDelegate(this)] } + val eventSource = if(obj instanceof EventHandlerVariableDeclaration) { + EcoreUtil2.getContainerOfType(obj, EventHandlerDeclaration).event?.castOrNull(SystemEventSource); + } + else { + obj; + } + val event = if(eventSource instanceof SystemEventSource) { + eventSource.source; + } + else { + eventSource; + } + val platformInferrerCls = if(event instanceof SystemResourceEvent) { + event.sizeInferrer; + } + val platformInferrer = if(platformInferrerCls !== null) { + loader.loadFromPlugin(obj.eResource, platformInferrerCls)?.castOrNull(FunctionSizeInferrer) => [ + it?.setDelegate(typeInferrer ?: this)] + } + // all generated elements may supply an inferrer // function calls val functionInferrerCls = if(obj instanceof ElementReferenceExpression) { @@ -209,13 +230,13 @@ class ProgramSizeInferrer extends AbstractSizeInferrer implements TypeSizeInferr ref.sizeInferrer; } } - } + } val functionInferrer = if(functionInferrerCls !== null) { - loader.loadFromPlugin(obj.eResource, typeInferrerCls)?.castOrNull(FunctionSizeInferrer) => [ + loader.loadFromPlugin(obj.eResource, functionInferrerCls)?.castOrNull(FunctionSizeInferrer) => [ it?.setDelegate(typeInferrer ?: this)] } - return functionInferrer ?: typeInferrer + return (functionInferrer ?: platformInferrer) ?: typeInferrer } // only generated types have special needs for size inference for now @@ -319,7 +340,10 @@ class ProgramSizeInferrer extends AbstractSizeInferrer implements TypeSizeInferr } dispatch def void doCreateConstraints(InferenceContext c, SignalInstance siginst) { - inferUnmodifiedFrom(c.system, siginst, siginst.initialization); + // siginsts should be typed by the platform; + // if they are not then we get here and they are write-only, + // therefore we can just assign the original type. + c.system.associate(c.type, siginst); } dispatch def void doCreateConstraints(InferenceContext c, SystemEventSource eventSource) { diff --git a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/scoping/ProgramDslScopeProvider.xtend b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/scoping/ProgramDslScopeProvider.xtend index 87856eda..8c6ac90d 100644 --- a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/scoping/ProgramDslScopeProvider.xtend +++ b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/scoping/ProgramDslScopeProvider.xtend @@ -51,6 +51,7 @@ import org.eclipse.mita.platform.Sensor import org.eclipse.mita.platform.SystemResourceAlias import org.eclipse.mita.platform.SystemSpecification import org.eclipse.mita.program.ConfigurationItemValue +import org.eclipse.mita.program.EventHandlerDeclaration import org.eclipse.mita.program.IsDeconstructionCase import org.eclipse.mita.program.IsDeconstructor import org.eclipse.mita.program.Program @@ -73,6 +74,7 @@ import org.eclipse.xtext.scoping.impl.ImportNormalizer import org.eclipse.xtext.scoping.impl.ImportScope import org.eclipse.xtext.util.OnChangeEvictingCache +import static extension org.eclipse.mita.base.util.BaseUtils.castOrNull import static extension org.eclipse.mita.base.util.BaseUtils.force class ProgramDslScopeProvider extends AbstractProgramDslScopeProvider { @@ -662,15 +664,35 @@ class ProgramDslScopeProvider extends AbstractProgramDslScopeProvider { } } else if(obj instanceof SystemResourceSetup) { - return !obj.events.isNullOrEmpty + // TODO + return true } return false; ]) } def IScope scope_SystemEventSource_source(SystemEventSource context, EReference reference) { - return if (context === null || context.origin === null || context.origin.events.nullOrEmpty) { + var superScope = delegateGetScope(context, reference); + + return if(context === null) { IScope.NULLSCOPE; + } else if (context.origin === null || context.origin.events.nullOrEmpty) { + val eventSource = EcoreUtil2.getContainerOfType(context, EventHandlerDeclaration)?.event?.castOrNull(SystemEventSource); + if(eventSource === null) { + superScope; + } + else { + val qualifiers = #[ + QualifiedName.create(#[BaseUtils.getText(eventSource, ProgramPackage.eINSTANCE.systemEventSource_Origin)]) + ] + if(eventSource.origin !== null && eventSource.signalInstance !== null) { + #[QualifiedName.create(#[ + BaseUtils.getText(eventSource.origin, ProgramPackage.eINSTANCE.systemResourceSetup_Type), + BaseUtils.getText(eventSource.signalInstance.initialization, ExpressionsPackage.eINSTANCE.elementReferenceExpression_Reference) + ])]; + } else {#[]}; + val normalizers = qualifiers.map[qualifier | new ImportNormalizer(qualifier, true, false)]; + new ImportScope(normalizers.toList, superScope, null, ProgramPackage.eINSTANCE.systemEventSource, false); + } } else { Scopes.scopeFor(context.origin.events); } @@ -688,6 +710,13 @@ class ProgramDslScopeProvider extends AbstractProgramDslScopeProvider { val cache = new OnChangeEvictingCache(); + def IScope scope_SystemEventSource_signalInstance(SystemEventSource eventSource, EReference reference) { + val superScope = delegateGetScope(eventSource, reference); + val qualifier = QualifiedName.create(#[ BaseUtils.getText(eventSource, ProgramPackage.eINSTANCE.systemEventSource_Origin)]); + val normalizer = new ImportNormalizer(qualifier, true, false); + return new ImportScope(#[normalizer], superScope, null, ProgramPackage.eINSTANCE.systemEventSource, false); + } + override IScope getScope(EObject context, EReference reference) { // Performance improvement: hard-code well traveled routes diff --git a/platforms/org.eclipse.mita.platform.x86/1.0.0/x86.platform b/platforms/org.eclipse.mita.platform.x86/1.0.0/x86.platform index 8dd5ac53..c8384e24 100644 --- a/platforms/org.eclipse.mita.platform.x86/1.0.0/x86.platform +++ b/platforms/org.eclipse.mita.platform.x86/1.0.0/x86.platform @@ -1,11 +1,56 @@ package platforms.x86; - +/** + * Implements MQTT using https://www.eclipse.org/paho/clients/c/. + * Place headers in ${resourceLoc/include} and binaries in ${resourceLoc/lib}. + * To run compiled code add ${resourceLoc/lib} to your LD_LIBRARY_PATH. + */ +connectivity many MQTT { + generator "org.eclipse.mita.platform.x86.connectivity.MqttGenerator" + + /** + * The URL pointing to the MQTT broker, for example: mqtt://does-not.exist:8000 + */ + required configuration-item url : string + + /** + * The client identifier (here: clientID) is a identifier of each MQTT client + * connecting to a MQTT broker. It needs to be unique for the broker to + * know the state of the client. + */ + required configuration-item clientId : string + + /** + * The clean session flag indicates to the broker whether the client wants + * to establish a clean session or a persistent session where all + * subscriptions and messages (QoS 1 & 2) are stored for the client. + */ + configuration-item cleanSession : bool = false + + /** + * The keep alive interval (in seconds) is the time the client commits to for + * when sending regular pings to the broker. The broker responds to the + * pings enabling both sides to determine if the other one is still alive and + * reachable. + */ + configuration-item keepAliveInterval : uint32 = 60 + + /** + * Publishes a message to a particular topic. + */ + signal topic(name : string, qos : uint32 = 0, length: uint32 = 500) : string { + event msgReceived: string { + size-inferrer "org.eclipse.mita.library.stdlib.GenericPlatformSizeInferrer" + } + } +} platform x86 { module "org.eclipse.mita.platform.x86.platform.X86PlatformGeneratorModule" generator "org.eclipse.mita.platform.x86.platform.X86PlatformGenerator" + has MQTT + // payload is current time in ms since epoch (1970/1/1) event startup: int32 } diff --git a/platforms/org.eclipse.mita.platform.x86/src/org/eclipse/mita/platform/x86/IMakefileParticipant.xtend b/platforms/org.eclipse.mita.platform.x86/src/org/eclipse/mita/platform/x86/IMakefileParticipant.xtend new file mode 100644 index 00000000..2787ff24 --- /dev/null +++ b/platforms/org.eclipse.mita.platform.x86/src/org/eclipse/mita/platform/x86/IMakefileParticipant.xtend @@ -0,0 +1,5 @@ +package org.eclipse.mita.platform.x86 + +interface IMakefileParticipant { + def Iterable getLibraries(); +} \ No newline at end of file diff --git a/platforms/org.eclipse.mita.platform.x86/src/org/eclipse/mita/platform/x86/connectivity/MqttGenerator.xtend b/platforms/org.eclipse.mita.platform.x86/src/org/eclipse/mita/platform/x86/connectivity/MqttGenerator.xtend new file mode 100644 index 00000000..3b0b44a0 --- /dev/null +++ b/platforms/org.eclipse.mita.platform.x86/src/org/eclipse/mita/platform/x86/connectivity/MqttGenerator.xtend @@ -0,0 +1,130 @@ +package org.eclipse.mita.platform.x86.connectivity + +import com.google.inject.Inject +import java.util.Optional +import org.eclipse.mita.base.util.BaseUtils +import org.eclipse.mita.library.stdlib.RingbufferGenerator +import org.eclipse.mita.platform.x86.IMakefileParticipant +import org.eclipse.mita.program.EventHandlerDeclaration +import org.eclipse.mita.program.SignalInstance +import org.eclipse.mita.program.SystemEventSource +import org.eclipse.mita.program.generator.AbstractSystemResourceGenerator +import org.eclipse.mita.program.generator.CodeFragment +import org.eclipse.mita.program.generator.CodeWithContext +import org.eclipse.mita.program.generator.StatementGenerator +import org.eclipse.mita.program.model.ModelUtils + +import static extension org.eclipse.mita.base.util.BaseUtils.castOrNull; +import org.eclipse.mita.library.stdlib.RingbufferGenerator.PushGenerator +import org.eclipse.mita.base.typesystem.StdlibTypeRegistry +import org.eclipse.mita.program.generator.GeneratorUtils + +class MqttGenerator extends AbstractSystemResourceGenerator implements IMakefileParticipant { + @Inject + protected extension StatementGenerator; + + @Inject + protected PushGenerator pushGenerator; + + @Inject + protected StdlibTypeRegistry typeRegistry; + + @Inject + protected extension GeneratorUtils; + + // returns a char* + protected def getHandlerTopic(EventHandlerDeclaration handler) { + val sigInst = handler.event.castOrNull(SystemEventSource)?.signalInstance; + return '''«sigInst?.name»TopicBuf'''; + } + + override generateSetup() { + return codeFragmentProvider.create(''' + int exception = MQTTClient_create(&client, «setup.getConfigurationItemValue("url").code», «setup.getConfigurationItemValue("clientId").code», MQTTCLIENT_PERSISTENCE_NONE, NULL); + if(exception != 0) { + printf("Error in MQTT_Setup: %d\n", exception); + return exception; + } + conn_opts.keepAliveInterval = «setup.getConfigurationItemValueOrDefault("keepAliveInterval").code»; + conn_opts.cleansession = «setup.getConfigurationItemValueOrDefault("cleanSession").code»; + MQTTClient_setCallbacks(client, NULL, NULL, messageArrivedCb, NULL); + ''').setPreamble(''' + MQTTClient client; + MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer; + MQTTClient_deliveryToken token; + + «FOR signalInstance: setup.signalInstances» + char «signalInstance.name»TopicBuf[] = «ModelUtils.getArgumentValue(signalInstance, "name").code»; + «ENDFOR» + «FOR handler: eventHandler» + extern ringbuffer_array_char rb_«handler.handlerName»; + «ENDFOR» + + int messageArrivedCb(void* context, char* topicName, int topicLen, MQTTClient_message* message) { + array_char msg = (array_char) { + .data = message->payload, + .capacity = message->payloadlen, + .length = message->payloadlen + }; + int exception = 0; + if(topicLen == 0) { + topicLen = strlen(topicName); + } + «FOR handler: eventHandler» + if(exception == 0 && strlen(«getHandlerTopic(handler)») == topicLen && 0 == memcmp(topicName, «getHandlerTopic(handler)», topicLen)) { + «pushGenerator.generate( + handler, + new CodeWithContext(RingbufferGenerator.wrapInRingbuffer(typeRegistry, handler, BaseUtils.getType(handler.event.castOrNull(SystemEventSource))), Optional.empty, codeFragmentProvider.create('''rb_«handler.handlerName»''')), + codeFragmentProvider.create('''msg''') + )» + «handler.handlerName»_flag = 1; + } + «ENDFOR» + MQTTClient_free(topicName); + return exception; + } + ''').addHeader("MQTTClient.h", false) + .addHeader("MitaEvents.h", false) + .addHeader("string.h", true) + } + + override generateEnable() { + return codeFragmentProvider.create(''' + int exception; + exception = MQTTClient_connect(client, &conn_opts); + if(exception != MQTTCLIENT_SUCCESS) { + return exception; + } + «FOR signalInstance: setup.signalInstances» + exception = MQTTClient_subscribe(client, «signalInstance.name»TopicBuf, «ModelUtils.getArgumentValue(signalInstance, "qos").code»); + if(exception != MQTTCLIENT_SUCCESS) { + return exception; + } + «ENDFOR» + ''').addHeader("MQTTClient.h", false) + } + + override generateSignalInstanceGetter(SignalInstance signalInstance, String resultName) { + return CodeFragment.EMPTY; + } + + override generateSignalInstanceSetter(SignalInstance signalInstance, String valueVariableName) { + return codeFragmentProvider.create(''' + uint32_t exception = 0; + + MQTTClient_message pubmsg = MQTTClient_message_initializer; + pubmsg.payload = «valueVariableName»->data; + pubmsg.payloadlen = «valueVariableName»->length; + pubmsg.qos = «ModelUtils.getArgumentValue(signalInstance, "qos").code»; + pubmsg.retained = 0; + MQTTClient_publishMessage(client, «signalInstance.name»TopicBuf, &pubmsg, &token); + exception = MQTTClient_waitForCompletion(client, token, 10000L); + return exception; + '''); + } + + override getLibraries() { + return #["paho-mqtt3c"] + } + +} diff --git a/platforms/org.eclipse.mita.platform.x86/src/org/eclipse/mita/platform/x86/platform/EventLoopGenerator.xtend b/platforms/org.eclipse.mita.platform.x86/src/org/eclipse/mita/platform/x86/platform/EventLoopGenerator.xtend index 4e9a1f26..b193aaf6 100644 --- a/platforms/org.eclipse.mita.platform.x86/src/org/eclipse/mita/platform/x86/platform/EventLoopGenerator.xtend +++ b/platforms/org.eclipse.mita.platform.x86/src/org/eclipse/mita/platform/x86/platform/EventLoopGenerator.xtend @@ -73,11 +73,11 @@ class EventLoopGenerator implements IPlatformEventLoopGenerator { } override generateSetupPreamble(CompilationContext context) { - val startupEventHandler = context.allEventHandlers.filter[it.event instanceof SystemEventSource].findFirst[(it.event as SystemEventSource).source.name == "startup"] + val startupEventHandlers = context.allEventHandlers.filter[it.event instanceof SystemEventSource].filter[(it.event as SystemEventSource).source.name == "startup"] return codeFragmentProvider.create(''' - «IF startupEventHandler !== null» + «FOR startupEventHandler: startupEventHandlers» «startupEventHandler.handlerName»_flag = 1; - «ENDIF» + «ENDFOR» '''); } diff --git a/platforms/org.eclipse.mita.platform.x86/src/org/eclipse/mita/platform/x86/platform/MakefileGenerator.xtend b/platforms/org.eclipse.mita.platform.x86/src/org/eclipse/mita/platform/x86/platform/MakefileGenerator.xtend index fbf8c0e0..6df9fc98 100644 --- a/platforms/org.eclipse.mita.platform.x86/src/org/eclipse/mita/platform/x86/platform/MakefileGenerator.xtend +++ b/platforms/org.eclipse.mita.platform.x86/src/org/eclipse/mita/platform/x86/platform/MakefileGenerator.xtend @@ -13,17 +13,25 @@ package org.eclipse.mita.platform.x86.platform +import com.google.inject.Inject import java.util.List import org.eclipse.mita.program.generator.CompilationContext import org.eclipse.mita.program.generator.PlatformMakefileGenerator +import org.eclipse.mita.program.resource.PluginResourceLoader +import org.eclipse.mita.platform.x86.IMakefileParticipant class MakefileGenerator extends PlatformMakefileGenerator { + @Inject + protected PluginResourceLoader pluginLoader; + override generateMakefile(CompilationContext context, List sourceFiles) { + val loadedLibraries = context.allSystemResourceSetup.map[it.type].map[pluginLoader.loadFromPlugin(it.eResource, it.generator)].filter(IMakefileParticipant).flatMap[it.libraries].map["-l" + it]; return codeFragmentProvider.create(''' export CC=gcc export CCFLAGS=-Wall -std=c99 -D_POSIX_C_SOURCE=199309L -D_DEFAULT_SOURCE -g export BUILDDIR=./build - export SOURCE_INCLUDES = -I. -I./base + export LDFLAGS=-L../lib «loadedLibraries.join(" ")» + export SOURCE_INCLUDES = -I. -I./base -I../include export SOURCE_DIR=. export SOURCE_FILES = \ «sourceFiles.filter[x | x.endsWith('.c') ].map[x | '''$(SOURCE_DIR)/«x»'''].join(' \\\n')» @@ -32,7 +40,7 @@ class MakefileGenerator extends PlatformMakefileGenerator { all: mkdir -p $(BUILDDIR) - $(CC) $(CCFLAGS) $(SOURCE_INCLUDES) -o$(BUILDDIR)/app $(SOURCE_FILES) + $(CC) $(CCFLAGS) $(SOURCE_INCLUDES) -o$(BUILDDIR)/app $(SOURCE_FILES) $(LDFLAGS) clean: rm $(BUILDDIR)/* diff --git a/platforms/org.eclipse.mita.platform.x86/src/org/eclipse/mita/platform/x86/platform/StartupGenerator.xtend b/platforms/org.eclipse.mita.platform.x86/src/org/eclipse/mita/platform/x86/platform/StartupGenerator.xtend index bc5bb07d..0b6a8048 100644 --- a/platforms/org.eclipse.mita.platform.x86/src/org/eclipse/mita/platform/x86/platform/StartupGenerator.xtend +++ b/platforms/org.eclipse.mita.platform.x86/src/org/eclipse/mita/platform/x86/platform/StartupGenerator.xtend @@ -47,8 +47,7 @@ class StartupGenerator implements IPlatformStartupGenerator { .map[it -> it.event] .filter[it.value instanceof SystemEventSource] .map[it.key -> it.value as SystemEventSource] - .map[it.key -> it.value.source] - .filter[it.value.name == "startup"] + .filter[it.value.source.name == "startup"] return codeFragmentProvider.create(''' Mita_initialize(); Mita_goLive(); @@ -61,7 +60,7 @@ class StartupGenerator implements IPlatformStartupGenerator { new CodeWithContext( RingbufferGenerator.wrapInRingbuffer(typeRegistry, startupEventHandler, BaseUtils.getType(event)), Optional.empty, - codeFragmentProvider.create('''rb_«startupEventHandler.baseName»''') + codeFragmentProvider.create('''rb_«startupEventHandler.handlerName»''') ), codeFragmentProvider.create('''getTime()''') )» @@ -90,12 +89,13 @@ class StartupGenerator implements IPlatformStartupGenerator { ''') .setPreamble(''' «FOR startupEventHandler_event: startupEventHandlersAndEvents» - extern ringbuffer_int32_t rb_«startupEventHandler_event.key.baseName»; + extern ringbuffer_int32_t rb_«startupEventHandler_event.key.handlerName»; «ENDFOR» ''') .addHeader('time.h', true) .addHeader('stdio.h', true) - .addHeader('stdbool.h', true); + .addHeader('stdbool.h', true) + .addHeader("MitaEvents.h", false); } } diff --git a/platforms/org.eclipse.mita.platform.xdk110/1.0.0/xdk110.platform b/platforms/org.eclipse.mita.platform.xdk110/1.0.0/xdk110.platform index ed54b21d..f5a4dad5 100644 --- a/platforms/org.eclipse.mita.platform.xdk110/1.0.0/xdk110.platform +++ b/platforms/org.eclipse.mita.platform.xdk110/1.0.0/xdk110.platform @@ -828,9 +828,11 @@ connectivity many MQTT { /** * Publishes a message to a particular topic. */ - signal topic(name : string, qos : uint32 = 0) : string - - event msgReceived: string<500> + signal topic(name : string, qos : uint32 = 0, length: uint32 = 500) : string { + event msgReceived: string { + size-inferrer "org.eclipse.mita.library.stdlib.GenericPlatformSizeInferrer" + } + } } alt HonoAuthentication { diff --git a/platforms/org.eclipse.mita.platform.xdk110/src/org/eclipse/mita/platform/xdk110/connectivity/MqttGenerator.xtend b/platforms/org.eclipse.mita.platform.xdk110/src/org/eclipse/mita/platform/xdk110/connectivity/MqttGenerator.xtend index 75325cc3..482010eb 100644 --- a/platforms/org.eclipse.mita.platform.xdk110/src/org/eclipse/mita/platform/xdk110/connectivity/MqttGenerator.xtend +++ b/platforms/org.eclipse.mita.platform.xdk110/src/org/eclipse/mita/platform/xdk110/connectivity/MqttGenerator.xtend @@ -15,12 +15,19 @@ package org.eclipse.mita.platform.xdk110.connectivity import com.google.inject.Inject import java.net.URI +import java.util.Optional import java.util.stream.Collectors +import org.eclipse.mita.base.typesystem.StdlibTypeRegistry +import org.eclipse.mita.base.util.BaseUtils +import org.eclipse.mita.library.stdlib.RingbufferGenerator import org.eclipse.mita.library.stdlib.RingbufferGenerator.PushGenerator +import org.eclipse.mita.program.EventHandlerDeclaration import org.eclipse.mita.program.SignalInstance +import org.eclipse.mita.program.SystemEventSource import org.eclipse.mita.program.generator.AbstractSystemResourceGenerator import org.eclipse.mita.program.generator.CodeFragment import org.eclipse.mita.program.generator.CodeFragment.IncludePath +import org.eclipse.mita.program.generator.CodeWithContext import org.eclipse.mita.program.generator.GeneratorUtils import org.eclipse.mita.program.generator.IPlatformLoggingGenerator import org.eclipse.mita.program.generator.IPlatformLoggingGenerator.LogLevel @@ -29,15 +36,8 @@ import org.eclipse.mita.program.inferrer.StaticValueInferrer import org.eclipse.mita.program.inferrer.StaticValueInferrer.SumTypeRepr import org.eclipse.mita.program.model.ModelUtils import org.eclipse.xtext.generator.IFileSystemAccess2 -import java.util.Optional -import org.eclipse.mita.program.generator.CodeWithContext -import org.eclipse.mita.base.typesystem.types.TypeConstructorType -import org.eclipse.mita.base.util.BaseUtils -import org.eclipse.mita.base.types.Variance -import org.eclipse.mita.library.stdlib.RingbufferGenerator -import org.eclipse.mita.base.typesystem.StdlibTypeRegistry -import org.eclipse.mita.program.SystemEventSource -import static extension org.eclipse.mita.base.util.BaseUtils.castOrNull; + +import static extension org.eclipse.mita.base.util.BaseUtils.castOrNull class MqttGenerator extends AbstractSystemResourceGenerator { @@ -414,6 +414,12 @@ class MqttGenerator extends AbstractSystemResourceGenerator { return result; } + + // returns a char* + protected def getHandlerTopic(EventHandlerDeclaration handler) { + val sigInst = handler.event.castOrNull(SystemEventSource)?.signalInstance; + return '''«sigInst?.name»TopicBuf'''; + } protected def isLogin(SumTypeRepr repr) { return repr.name == "Login" @@ -429,7 +435,7 @@ class MqttGenerator extends AbstractSystemResourceGenerator { codeFragmentProvider.create(''' «FOR handler: eventHandler» - extern ringbuffer_array_char rb_«handler.baseName»; + extern ringbuffer_array_char rb_«handler.handlerName»; «ENDFOR» /** @@ -501,15 +507,17 @@ class MqttGenerator extends AbstractSystemResourceGenerator { .length = eventData->publish.length }; «FOR handler: eventHandler» - «pushGenerator.generate( - handler, - new CodeWithContext(RingbufferGenerator.wrapInRingbuffer(typeRegistry, handler, BaseUtils.getType(handler.event.castOrNull(SystemEventSource).source)), Optional.empty, codeFragmentProvider.create('''rb_«handler.baseName»''')), - codeFragmentProvider.create('''msg''') - )» - exception = CmdProcessor_enqueue(&Mita_EventQueue, «handler.handlerName», NULL, 0); - if(exception != RETCODE_OK) - { - Retcode_RaiseError(exception); + if(exception == RETCODE_OK && strlen(«getHandlerTopic(handler)») == eventData->publish.topic.length && 0 == memcmp(eventData->publish.topic.start, «getHandlerTopic(handler)», eventData->publish.topic.length)) { + «pushGenerator.generate( + handler, + new CodeWithContext(RingbufferGenerator.wrapInRingbuffer(typeRegistry, handler, BaseUtils.getType(handler.event.castOrNull(SystemEventSource).source)), Optional.empty, codeFragmentProvider.create('''rb_«handler.handlerName»''')), + codeFragmentProvider.create('''msg''') + )» + exception = CmdProcessor_enqueue(&Mita_EventQueue, «handler.handlerName», NULL, 0); + if(exception != RETCODE_OK) + { + Retcode_RaiseError(exception); + } } «ENDFOR» break; diff --git a/platforms/org.eclipse.mita.platform.xdk110/src/org/eclipse/mita/platform/xdk110/connectivity/WlanGenerator.xtend b/platforms/org.eclipse.mita.platform.xdk110/src/org/eclipse/mita/platform/xdk110/connectivity/WlanGenerator.xtend index 951e0a02..740ed019 100644 --- a/platforms/org.eclipse.mita.platform.xdk110/src/org/eclipse/mita/platform/xdk110/connectivity/WlanGenerator.xtend +++ b/platforms/org.eclipse.mita.platform.xdk110/src/org/eclipse/mita/platform/xdk110/connectivity/WlanGenerator.xtend @@ -260,7 +260,7 @@ class WlanGenerator extends AbstractSystemResourceGenerator { { networkStatusFlag = true; printf("Network with SSID %s is available\n", NETWORK_SSID); - exception = ConnectivityWLANWifi_Enable(); + exception = «setup.baseName»_Enable(); if (RETCODE_OK != exception) { printf("Not able to connect to the network\n"); diff --git a/platforms/org.eclipse.mita.platform.xdk110/src/org/eclipse/mita/platform/xdk110/sensors/ButtonGenerator.xtend b/platforms/org.eclipse.mita.platform.xdk110/src/org/eclipse/mita/platform/xdk110/sensors/ButtonGenerator.xtend index 3bc32dc6..1bc0ba97 100644 --- a/platforms/org.eclipse.mita.platform.xdk110/src/org/eclipse/mita/platform/xdk110/sensors/ButtonGenerator.xtend +++ b/platforms/org.eclipse.mita.platform.xdk110/src/org/eclipse/mita/platform/xdk110/sensors/ButtonGenerator.xtend @@ -60,7 +60,7 @@ class ButtonGenerator extends AbstractSystemResourceGenerator { «FOR handlergrp : eventHandler.groupBy[it.sensorInstance.buttonNumber].values» «val changedHandlers = handlergrp.filter[(it.event as SystemEventSource)?.source?.name == "changed"]» «FOR changedHandler: changedHandlers» - extern ringbuffer_bool rb_«changedHandler.baseName»; + extern ringbuffer_bool rb_«changedHandler.handlerName»; «ENDFOR» Retcode_T «handlergrp.head.internalHandlerName»(uint32_t data) @@ -83,7 +83,7 @@ class ButtonGenerator extends AbstractSystemResourceGenerator { new CodeWithContext( RingbufferGenerator.wrapInRingbuffer(typeRegistry, changedHandler, BaseUtils.getType(changedHandler.event.castOrNull(SystemEventSource).source)), Optional.empty, - codeFragmentProvider.create('''rb_«changedHandler.baseName»''') + codeFragmentProvider.create('''rb_«changedHandler.handlerName»''') ), codeFragmentProvider.create('''data == BSP_XDK_BUTTON_PRESSED''') )»