CppGenerator.xtend 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991
  1. package be.uantwerpen.ansymo.semanticadaptation.cg.cpp.generation
  2. import be.uantwerpen.ansymo.semanticadaptation.cg.cpp.data.GlobalInOutVariable
  3. import be.uantwerpen.ansymo.semanticadaptation.cg.cpp.data.IORuleType
  4. import be.uantwerpen.ansymo.semanticadaptation.cg.cpp.data.InOutRulesBlockResult
  5. import be.uantwerpen.ansymo.semanticadaptation.cg.cpp.data.InnerFMUData
  6. import be.uantwerpen.ansymo.semanticadaptation.cg.cpp.data.MappedScalarVariable
  7. import be.uantwerpen.ansymo.semanticadaptation.cg.cpp.data.SAScalarVariable
  8. import be.uantwerpen.ansymo.semanticadaptation.cg.cpp.data.SVCausality
  9. import be.uantwerpen.ansymo.semanticadaptation.cg.cpp.data.SVType
  10. import be.uantwerpen.ansymo.semanticadaptation.cg.cpp.data.ScalarVariable
  11. import be.uantwerpen.ansymo.semanticadaptation.cg.cpp.exceptions.IncorrectAmountOfElementsException
  12. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.Adaptation
  13. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.ControlRuleBlock
  14. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.Declaration
  15. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.InOutRules
  16. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.InnerFMU
  17. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.MooreOrMealy
  18. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.ParamDeclarations
  19. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.Port
  20. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.ReactiveOrDelayed
  21. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.SemanticAdaptation
  22. import java.io.File
  23. import java.util.ArrayList
  24. import java.util.Collection
  25. import java.util.LinkedHashMap
  26. import java.util.List
  27. import org.eclipse.emf.common.util.EList
  28. import org.eclipse.emf.ecore.resource.Resource
  29. import org.eclipse.xtext.generator.IFileSystemAccess2
  30. import be.uantwerpen.ansymo.semanticadaptation.log.Log
  31. import org.eclipse.emf.common.util.URI
  32. import org.eclipse.emf.common.CommonPlugin
  33. class CppGenerator {
  34. var IFileSystemAccess2 fsa;
  35. List<File> resourcePaths = newArrayList();
  36. def void doGenerate(Resource resource, IFileSystemAccess2 fsa) {
  37. Log.push("CppGenerator.doGenerate")
  38. Log.println("Resource URI: " + resource.URI)
  39. val adaptationFolderURI = resource.URI.trimSegments(1)
  40. val resolvedFolderURI = CommonPlugin.resolve(adaptationFolderURI);
  41. Log.println("Adaptation folder URI: " + resolvedFolderURI.toFileString)
  42. doGenerate(resource, fsa, resolvedFolderURI.toFileString)
  43. Log.pop("CppGenerator.doGenerate")
  44. }
  45. def void doGenerate(Resource resource, IFileSystemAccess2 fsa, String resolvedFolderURI) {
  46. Log.push("CppGenerator.doGenerate " + resolvedFolderURI)
  47. this.fsa = fsa;
  48. for (SemanticAdaptation type : resource.allContents.toIterable.filter(SemanticAdaptation)) {
  49. type.compile(resolvedFolderURI);
  50. }
  51. Log.pop("CppGenerator.doGenerate" + resolvedFolderURI)
  52. }
  53. // TODO: Verify adaptation.name is not a C++ keyword
  54. def void compile(SemanticAdaptation adaptation, String resolvedFolderURI) {
  55. for (Adaptation adap : adaptation.elements.filter(Adaptation)) {
  56. // Value used for scoping variables in the .sa file
  57. val adapInteralRefName = adap.name;
  58. // The CPP class name
  59. val adapClassName = adap.name.toFirstUpper;
  60. // This is the external name used in the model description file for the semantic adaptation FMU
  61. val adapExternalName = adap.name;
  62. // List of inner FMUs
  63. var ArrayList<InnerFMUData> innerFMUsData = newArrayList();
  64. val innerFmus = adap.inner.eAllContents.toList.filter(InnerFMU);
  65. if (innerFmus.isEmpty) {
  66. throw new IncorrectAmountOfElementsException("The adaptation does not contain any InnerFMUs.")
  67. }
  68. if (innerFmus.size > 1) {
  69. throw new IncorrectAmountOfElementsException("Only one InnerFmu is supported.")
  70. }
  71. /*
  72. * This map will contain scalar variables from the FMUs defined in InnerFMU.
  73. * The structure is fmuName -> (SVName -> mappedSV) where SVName = mappedSV.name for easy lookup.
  74. * The mappedSV contains the original scalar variable and extra data such as define name.
  75. */
  76. var LinkedHashMap<String, LinkedHashMap<String, MappedScalarVariable>> mappedScalarVariables = newLinkedHashMap();
  77. /*
  78. * Loading the FMU defined in InnerFMU, the related model description file and its scalar variables.
  79. */
  80. // TODO: Add support for multiple inner fmus. Only partially supported
  81. var ModelDescription md;
  82. for (fmu : adap.inner.eAllContents.toList.filter(InnerFMU)) {
  83. Log.push("Loading fmu " + fmu.path)
  84. val fmuFile = getFMUFile(fmu.path, resolvedFolderURI)
  85. this.resourcePaths.add(fmuFile);
  86. md = new ModelDescription(fmu.name, fmuFile);
  87. innerFMUsData.add(new InnerFMUData(fmu.name, fmu.path, md.guid));
  88. val LinkedHashMap<String, MappedScalarVariable> mSV = newLinkedHashMap();
  89. Log.push("Loading fmu variables")
  90. for (sv : md.sv.values) {
  91. // Only declared ports are considered.
  92. val svInPort = fmu.inports.findFirst[Port p | p.name==sv.name || BuildUtilities.stripDelimiters(p.alias) == sv.name]
  93. val svOutPort = fmu.outports.findFirst[Port p | p.name==sv.name || BuildUtilities.stripDelimiters(p.alias) == sv.name]
  94. if (svInPort !== null || svOutPort !== null){
  95. val svPort = if (svInPort !== null) svInPort else svOutPort
  96. val svPortRef = svPort.name;
  97. var mappedSv = new MappedScalarVariable(sv);
  98. mappedSv.define = (mappedSv.mappedSv.owner + svPortRef).toUpperCase;
  99. mSV.put(mappedSv.mappedSv.name, mappedSv);
  100. Log.println("Variable " + sv.name + " declared.")
  101. } else {
  102. Log.println("Variable " + sv.name + " undeclared.")
  103. }
  104. }
  105. mappedScalarVariables.put(fmu.name, mSV);
  106. Log.pop("Loading fmu variables")
  107. mappedScalarVariables.put(fmu.name, mSV);
  108. }
  109. // C++ Defines for accessing FMU scalar variables.
  110. val String fmusDefines = calcDefines(mappedScalarVariables);
  111. /*
  112. * This map contains all the ScalarVariables for the semantic adaptation.
  113. * Some of them are not populated yet, but they will be during the compilation of the in and out rule blocks.
  114. */
  115. var LinkedHashMap<String, SAScalarVariable> SASVs = calcSASVsFromInportsOutports(adapInteralRefName,
  116. adap.inports, adap.outports, mappedScalarVariables)
  117. // C++ defines for accessing semantic adaptation scalar variables
  118. val String SADefines = calcSADefines(SASVs.values);
  119. // Compile Params
  120. var LinkedHashMap<String, GlobalInOutVariable> params = newLinkedHashMap;
  121. val String paramsConstructorSource = compileParams(params, adap.params);
  122. // Handles cases like this: output ports tau <- loop_sa.tau
  123. var List<Port> outPortsWithSrcDep = newArrayList();
  124. if (adap.outports !== null) {
  125. outPortsWithSrcDep = adap.outports.filter[x|x.sourcedependency !== null].toList;
  126. }
  127. var List<Port> inPortsWithSrcDep = newArrayList();
  128. if (adap.inports !== null) {
  129. inPortsWithSrcDep = adap.inports.filter[x|x.targetdependency !== null].toList;
  130. }
  131. // The three rule blocks
  132. val inRuleBlock = adap.in;
  133. val outRuleBlock = adap.out;
  134. val crtlRuleBlock = adap.control;
  135. // Get the control vars, in vars, and out vars
  136. var inVars = if(inRuleBlock !== null) compileRuleBlockVars(inRuleBlock.globalInVars, params);
  137. var outVars = if(outRuleBlock !== null) compileRuleBlockVars(outRuleBlock.globalOutVars, params);
  138. val crtlVars = if(crtlRuleBlock !== null) compileRuleBlockVars(crtlRuleBlock.globalCtrlVars, params);
  139. /*
  140. * Support for source dependency: output ports tau <- loop_sa.tau
  141. * Only carried out for outVars.
  142. * TODO: Do for inVars
  143. */
  144. for (Port port : outPortsWithSrcDep) {
  145. val name = '''stored_«port.sourcedependency.owner.name»_«port.sourcedependency.port.name»''';
  146. val type = mappedScalarVariables.get(port.sourcedependency.owner.name).get(
  147. port.sourcedependency.port.name).mappedSv.type;
  148. val globVar = new GlobalInOutVariable(name, type);
  149. val sourceDepType = mappedScalarVariables.get(port.sourcedependency.owner.name).get(
  150. port.sourcedependency.port.name).mappedSv.type;
  151. val constructorInit = '''this->internalState.«name» = «Conversions.fmiTypeToCppDefaultValue(sourceDepType)»;'''
  152. if (outVars !== null) {
  153. outVars.value.put(name, globVar);
  154. outVars = outVars.key.concat(constructorInit) -> outVars.value;
  155. } else {
  156. val LinkedHashMap<String, GlobalInOutVariable> gVars = newLinkedHashMap();
  157. gVars.put(name, globVar)
  158. outVars = constructorInit -> gVars;
  159. }
  160. }
  161. for (Port port : inPortsWithSrcDep) {
  162. val dependency = port.targetdependency;
  163. val name = '''stored_«dependency.owner.name»_«dependency.port.name»'''
  164. val type = mappedScalarVariables.get(dependency.owner.name).get(dependency.port.name).mappedSv.type;
  165. val globVar = new GlobalInOutVariable(name, type);
  166. val constructorInit = '''this->internalState.«name» = «Conversions.fmiTypeToCppDefaultValue(type)»;''';
  167. if (inVars !== null) {
  168. inVars.value.put(name, globVar);
  169. inVars = inVars.key.concat("\n" + constructorInit) -> inVars.value;
  170. } else {
  171. val LinkedHashMap<String, GlobalInOutVariable> gVars = newLinkedHashMap();
  172. gVars.put(name, globVar);
  173. inVars = constructorInit -> gVars;
  174. }
  175. }
  176. // Compile the in rules
  177. val inRules = if(adap.in !== null) adap.in as InOutRules else null;
  178. val inRuleResult = compileInOutRuleBlocks(IORuleType.Input, inRules, adapClassName, adapInteralRefName,
  179. mappedScalarVariables, SASVs, params, if(inVars !== null) inVars.value else null,
  180. if(outVars !== null) outVars.value else null, if(crtlVars !== null) crtlVars.value else null,
  181. inPortsWithSrcDep);
  182. // Compile the out rules
  183. val outRules = if(adap.out !== null) adap.out as InOutRules else null;
  184. val outRuleResult = compileInOutRuleBlocks(IORuleType.Output, outRules, adapClassName,
  185. adapInteralRefName, mappedScalarVariables, SASVs, params,
  186. if(inVars !== null) inVars.value else null, if(outVars !== null) outVars.value else null,
  187. if(crtlVars !== null) crtlVars.value else null, outPortsWithSrcDep);
  188. // Compile the Control Rules. These might use the out vars, so pass these along.
  189. val crtlRules = if(adap.control !== null) adap.control else null;
  190. val crtlRuleResult = compileControlRuleBlock(crtlRules, adapClassName, adapInteralRefName,
  191. mappedScalarVariables, SASVs, params,
  192. if(inVars !== null) inVars.value else null,
  193. if(outVars !== null) outVars.value else null,
  194. if(crtlVars !== null) crtlVars.value else null);
  195. /*
  196. * Compile the constructor, destructor and initialize functions
  197. */
  198. val String deAndConstructorAndInitializeSource = compileDeAndConstructorAndInitialize(
  199. adapClassName,
  200. innerFMUsData,
  201. md.guid,
  202. paramsConstructorSource,
  203. if(inVars !== null) inVars.key else "",
  204. if(outVars !== null) outVars.key else "",
  205. if(crtlVars !== null) crtlVars.key else "",
  206. adap.machine,
  207. adap.reactiveness,
  208. inRules !== null || inPortsWithSrcDep.length > 0,
  209. outRules !== null || outPortsWithSrcDep.length > 0
  210. );
  211. /*
  212. * Compile getRuleThis function
  213. */
  214. val String getRuleThisSource = compileGetRuleThis(adapClassName);
  215. /*
  216. * The in and out rules have populated the semantic adaptation scalar variables we can generate the getFmiValue* and setFmiValue functions.
  217. */
  218. val String getFuncsSource = compileGetFmiValueFunctions(adapClassName, SASVs);
  219. val String setFuncsSource = compileSetFmiValueFunctions(adapClassName, SASVs);
  220. // Compile the state functions
  221. val Pair<String,String> stateFunctions = compileStateFunctions(adapClassName);
  222. // Compile the source file
  223. val String sourceInclude = '''#include "«adapClassName».h"''';
  224. val sourceFile = compileSource(
  225. sourceInclude,
  226. deAndConstructorAndInitializeSource,
  227. getRuleThisSource,
  228. getFuncsSource,
  229. setFuncsSource,
  230. inRuleResult.generatedCpp,
  231. outRuleResult.generatedCpp,
  232. crtlRuleResult.generatedCpp,
  233. stateFunctions.value
  234. );
  235. fsa.generateFile(adapClassName + ".cpp", sourceFile);
  236. // Merge the global variables for use in compiling the header file.
  237. // TODO: Check for duplicates
  238. var LinkedHashMap<String, GlobalInOutVariable> allGVars = newLinkedHashMap();
  239. allGVars.putAll(params);
  240. if (inVars !== null)
  241. allGVars.putAll(inVars.value);
  242. if (outVars !== null)
  243. allGVars.putAll(outVars.value);
  244. if (crtlVars !== null)
  245. allGVars.putAll(crtlVars.value);
  246. // Compile the header file
  247. val headerFile = compileHeader(
  248. adapClassName,
  249. fmusDefines,
  250. SADefines,
  251. inRuleResult.functionSignatures,
  252. outRuleResult.functionSignatures,
  253. crtlRuleResult.functionSignatures,
  254. allGVars,
  255. innerFMUsData,
  256. SASVs.values.map[CalcSVar()].toList,
  257. stateFunctions.key
  258. );
  259. fsa.generateFile(adapClassName + ".h", headerFile);
  260. // Compile the model description file
  261. val modelDescCreator = new ModelDescriptionCreator(adapExternalName);
  262. val modelDescription = modelDescCreator.generateModelDescription(SASVs.values);
  263. fsa.generateFile("modelDescription.xml", modelDescription);
  264. // Compile the fmu.cpp file
  265. val fmuCppFile = FmuGenerator.genFmuCppFile(adapClassName);
  266. fsa.generateFile("Fmu.cpp", fmuCppFile);
  267. fsa.generateFile("CMakeLists.txt",CMakeListsGenerator.generateCMakeLists(adapExternalName))
  268. fsa.generateFile("msys-toolchain.cmake",CMakeListsGenerator.generateToolChainCmake());
  269. }
  270. }
  271. def getFMUFile(String fmuUnresolvedPath, String resolvedFolderURI) {
  272. Log.println("Current working dir: " + resolvedFolderURI)
  273. //var resolvedFolderURI = CommonPlugin.resolve(adaptationFolderURI);
  274. Log.println("Resolved Current working dir: " + resolvedFolderURI)
  275. val fmuCompleteURI = URI.createFileURI(resolvedFolderURI + File.separatorChar + fmuUnresolvedPath.replace('\"', ''))
  276. var fmuPath = fmuCompleteURI.toFileString
  277. Log.println("Resolved fmu path: " + fmuPath)
  278. val fmuFile = new File(fmuPath);
  279. return fmuFile
  280. }
  281. def String compileParams(LinkedHashMap<String, GlobalInOutVariable> gVars, EList<ParamDeclarations> params) {
  282. val paramsConditionSwitch = new ParamConditionSwitch(gVars);
  283. var String paramsConstructorSource = "";
  284. for (paramDecl : params) {
  285. val doSwitchRes = paramsConditionSwitch.doSwitch(paramDecl);
  286. paramsConstructorSource += doSwitchRes.code;
  287. }
  288. return paramsConstructorSource;
  289. }
  290. def calcSADefines(Collection<SAScalarVariable> variables) {
  291. var ArrayList<String> defines = newArrayList();
  292. for (SASV : variables) {
  293. defines.add("#define " + SASV.defineName + " " + SASV.valueReference);
  294. }
  295. return defines.join("\n");
  296. }
  297. def calcDefines(LinkedHashMap<String, LinkedHashMap<String, MappedScalarVariable>> map) {
  298. var ArrayList<String> defines = newArrayList();
  299. for (fmuEntries : map.entrySet) {
  300. for (MappedScalarVariable mSV : fmuEntries.value.values) {
  301. defines.add("#define " + mSV.define.replace('(','_').replace(')','_') + " " + mSV.valueReference);
  302. }
  303. }
  304. return defines.join("\n");
  305. }
  306. def Pair<String,String> compileStateFunctions(String saName)
  307. {
  308. return
  309. '''
  310. fmi2FMUstate getInternalFMUState();
  311. void setInternalFMUState(fmi2FMUstate state);
  312. void freeInternalFMUState(fmi2FMUstate state);
  313. '''
  314. ->
  315. '''
  316. fmi2FMUstate «saName»::getInternalFMUState()
  317. {
  318. InternalState* s = new InternalState();
  319. *s = this->internalState;
  320. return s;
  321. }
  322. void «saName»::setInternalFMUState(fmi2FMUstate state)
  323. {
  324. this->internalState = *(InternalState*)state;
  325. }
  326. void «saName»::freeInternalFMUState(fmi2FMUstate state)
  327. {
  328. delete (InternalState*)state;
  329. }''';
  330. }
  331. // Compiles the final source file
  332. def String compileSource(String include, String constructor, String getRuleThis, String getFunctions,
  333. String setFunctions, String inFunctions, String outFunctions, String controlFunction, String stateFunctions) {
  334. return '''
  335. «include»
  336. namespace adaptation
  337. {
  338. «constructor»
  339. «getRuleThis»
  340. «getFunctions»
  341. «setFunctions»
  342. «inFunctions»
  343. «controlFunction»
  344. «outFunctions»
  345. «stateFunctions»
  346. }
  347. '''
  348. }
  349. /*
  350. * Compiles the header file split into two: The first part contains the includes and using namespace definitions and start the ,
  351. * the second part contains the class
  352. */
  353. def String compileHeader(String adapClassName, String fmusDefines, String SADefines,
  354. List<String> inRulesFuncSig, List<String> outRulesFuncSig, List<String> crtlRulesFuncSig,
  355. LinkedHashMap<String, GlobalInOutVariable> globalVariables, ArrayList<InnerFMUData> fmus,
  356. Collection<ScalarVariable> sVars, String stateFunctions) {
  357. return '''
  358. #ifndef SRC_«adapClassName.toUpperCase»_H
  359. #define SRC_«adapClassName.toUpperCase»_H
  360. #include "SemanticAdaptation.h"
  361. #include "HyfMath.h"
  362. #include <memory>
  363. #include "Fmu.h"
  364. using namespace std;
  365. using namespace fmi2;
  366. namespace adaptation
  367. {
  368. «fmusDefines»
  369. «SADefines»
  370. class «adapClassName» : public SemanticAdaptation<«adapClassName»>, public enable_shared_from_this<«adapClassName»>
  371. {
  372. public:
  373. «adapClassName»(shared_ptr<std::string> fmiInstanceName, shared_ptr<string> resourceLocation, const fmi2CallbackFunctions* functions);
  374. void initialize(bool loggingOn);
  375. virtual ~«adapClassName»();
  376. void setFmiValue(fmi2ValueReference id, int value);
  377. void setFmiValue(fmi2ValueReference id, bool value);
  378. void setFmiValue(fmi2ValueReference id, double value);
  379. void setFmiValue(fmi2ValueReference id, string value);
  380. int getFmiValueInteger(fmi2ValueReference id);
  381. bool getFmiValueBoolean(fmi2ValueReference id);
  382. double getFmiValueReal(fmi2ValueReference id);
  383. string getFmiValueString(fmi2ValueReference id);
  384. protected:
  385. «stateFunctions»
  386. private:
  387. «adapClassName»* getRuleThis();
  388. /*in rules*/
  389. «inRulesFuncSig.map[x | x+";"].join("\n")»
  390. /*out rules*/
  391. «outRulesFuncSig.map[x | x+";"].join("\n")»
  392. «crtlRulesFuncSig.map[x | x+";"].join("\n")»
  393. «FOR fmu : fmus»
  394. shared_ptr<FmuComponent> «fmu.name»;
  395. «ENDFOR»
  396. struct InternalState {
  397. «FOR sv : sVars»
  398. «Conversions.fmiTypeToCppType(sv.type)» «sv.name»;
  399. «IF sv.causality == SVCausality.input»
  400. bool isSet«sv.name»;
  401. «ENDIF»
  402. «ENDFOR»
  403. «FOR v : globalVariables.entrySet»
  404. «Conversions.fmiTypeToCppType(v.value.type)» «v.key»;
  405. «ENDFOR»
  406. };
  407. InternalState internalState;
  408. };
  409. }
  410. #endif
  411. ''';
  412. }
  413. /*
  414. * Compiles the source file constructor, destructor and the initialize function
  415. */
  416. def String compileDeAndConstructorAndInitialize(String adapClassName, ArrayList<InnerFMUData> fmus, String guid,
  417. String paramsCons, String inCons, String outCons, String crtlCons, MooreOrMealy machineType,
  418. ReactiveOrDelayed reactiveOrDealyed, boolean inputRules, boolean outputRules) {
  419. var ArrayList<String> initialisations = newArrayList();
  420. if (reactiveOrDealyed == ReactiveOrDelayed.DELAYED) {
  421. initialisations.add('''this->reactiveness = ReactiveOrDelayed::Delayed;''');
  422. } else if (reactiveOrDealyed == ReactiveOrDelayed.REACTIVE) {
  423. initialisations.add('''this->reactiveness = ReactiveOrDelayed::Reactive;''');
  424. }
  425. if (machineType == MooreOrMealy.MOORE) {
  426. initialisations.add('''this->machineType = MooreOrMealy::Moore;''');
  427. } else if (machineType == MooreOrMealy.MEALY) {
  428. initialisations.add('''this->machineType = MooreOrMealy::Mealy;''');
  429. }
  430. var pathCount = 1;
  431. for (fmu : fmus) {
  432. val pathName = '''path«pathCount»''';
  433. pathCount++;
  434. initialisations.add('''
  435. auto «pathName» = make_shared<string>(*resourceLocation);
  436. «pathName»->append(string(«fmu.getPath»));
  437. auto «fmu.name»Fmu = make_shared<fmi2::Fmu>(*«pathName»);
  438. «fmu.name»Fmu->initialize();
  439. this->«fmu.name» = «fmu.name»Fmu->instantiate("«fmu.name»",fmi2CoSimulation, "«fmu.guid»", true, loggingOn, shared_from_this());
  440. if(this->«fmu.name»->component == NULL)
  441. this->lastErrorState = fmi2Fatal;
  442. this->instances->push_back(this->«fmu.name»);
  443. ''');
  444. }
  445. return '''
  446. «adapClassName»::«adapClassName»(shared_ptr<std::string> fmiInstanceName,shared_ptr<string> resourceLocation, const fmi2CallbackFunctions* functions) :
  447. SemanticAdaptation(fmiInstanceName, resourceLocation, «if(inputRules) "createInputRules()" else "NULL"», «if(outputRules) "createOutputRules()" else "NULL"», functions)
  448. {
  449. «paramsCons»
  450. «inCons»
  451. «outCons»
  452. «crtlCons»
  453. }
  454. void «adapClassName»::initialize(bool loggingOn)
  455. {
  456. «initialisations.join("\r\n")»
  457. }
  458. «adapClassName»::~«adapClassName»()
  459. {
  460. }
  461. ''';
  462. }
  463. /*
  464. * Compiles the source file function getRuleThis
  465. */
  466. def String compileGetRuleThis(String adaptationName) {
  467. return '''
  468. «adaptationName»* «adaptationName»::getRuleThis()
  469. {
  470. return this;
  471. }
  472. '''
  473. }
  474. /*
  475. * Compiles the source file functions getFmiValue<double, int, string, bool>
  476. */
  477. def String compileGetFmiValueFunctions(String adaptationName,
  478. LinkedHashMap<String, SAScalarVariable> variables) {
  479. var ArrayList<String> cpp = newArrayList();
  480. var List<ScalarVariable> convertedSASVs = variables.values.map[CalcSVar()].toList;
  481. var convertedSASVsOrdered = convertedSASVs.filter[causality === SVCausality.output].groupBy[type];
  482. for (SVType type : SVType.values) {
  483. val functionSignature = '''«Conversions.fmiTypeToCppType(type)» «adaptationName»::getFmiValue«type.toString»(fmi2ValueReference id)''';
  484. val functionReturn = '''return «Conversions.fmiTypeToCppDefaultValue(type)»''';
  485. if (convertedSASVsOrdered.containsKey(type)) {
  486. cpp.add(
  487. '''
  488. «functionSignature»
  489. {
  490. «Utilities.getDebug(functionSignature)»
  491. switch (id)
  492. {
  493. «FOR svInner : convertedSASVsOrdered.get(type)»
  494. case «variables.get(svInner.name).defineName»:
  495. {
  496. return this->internalState.«svInner.name»;
  497. }
  498. «ENDFOR»
  499. default:
  500. {
  501. «functionReturn»;
  502. }
  503. }
  504. }
  505. '''
  506. );
  507. } else {
  508. cpp.add(
  509. '''
  510. «functionSignature»
  511. {
  512. «Utilities.getDebug(functionSignature)»
  513. «functionReturn»;
  514. }
  515. '''
  516. );
  517. }
  518. }
  519. return cpp.join("\n");
  520. }
  521. /*
  522. * Compiles the source file functions setFmiValue<double, int, string, bool>*
  523. */
  524. def String compileSetFmiValueFunctions(String adapClassName,
  525. LinkedHashMap<String, SAScalarVariable> variables) {
  526. var ArrayList<String> cpp = newArrayList();
  527. var List<ScalarVariable> convertedSASVs = variables.values.map[CalcSVar()].filter [
  528. causality === SVCausality.input
  529. ].toList;
  530. var convertedSASVsOrdered = convertedSASVs.groupBy[type];
  531. for (SVType type : SVType.values) {
  532. val functionSignature = '''void «adapClassName»::setFmiValue(fmi2ValueReference id, «Conversions.fmiTypeToCppType(type)» value)''';
  533. cpp.add(
  534. '''
  535. «functionSignature»
  536. {
  537. «Utilities.getDebug2('''printf("«adapClassName»::setFmiValue(%d,?)",id);''')»
  538. «IF convertedSASVsOrdered.containsKey(type)»
  539. switch (id)
  540. {
  541. «FOR svInner : convertedSASVsOrdered.get(type)»
  542. case «variables.get(svInner.name).defineName»:
  543. {
  544. this->internalState.«svInner.name» = value;
  545. this->internalState.isSet«svInner.name» = true;
  546. break;
  547. }
  548. «ENDFOR»
  549. default:
  550. {
  551. }
  552. }
  553. «ENDIF»
  554. }
  555. '''
  556. );
  557. }
  558. return cpp.join("\n");
  559. }
  560. /*
  561. * Compiles the source file function executeInternalControlFlow.
  562. * Calculates necessary information on function signatures necessary for generation of the header file.
  563. */
  564. def InOutRulesBlockResult compileControlRuleBlock(ControlRuleBlock crtlRuleBlock, String adaptationClassName,
  565. String adaptationName, LinkedHashMap<String, LinkedHashMap<String, MappedScalarVariable>> mSVars,
  566. LinkedHashMap<String, SAScalarVariable> SASVs, LinkedHashMap<String, GlobalInOutVariable> params,
  567. LinkedHashMap<String, GlobalInOutVariable> inVars, LinkedHashMap<String, GlobalInOutVariable> outVars,
  568. LinkedHashMap<String, GlobalInOutVariable> crtlVars) {
  569. var cpp = "";
  570. val visitor = new ControlConditionSwitch(adaptationClassName, adaptationName,
  571. mSVars, SASVs, params, inVars, outVars, crtlVars
  572. );
  573. if (crtlRuleBlock !== null)
  574. cpp += visitor.doSwitch(crtlRuleBlock).code;
  575. return new InOutRulesBlockResult(cpp, visitor.functionSignatures);
  576. }
  577. def String SplitAtSpaceAndRemoveFirst(String content) {
  578. content.substring(content.indexOf(" ") + 1, content.length);
  579. }
  580. def String removeEmptyArgumentParenthesis(String content) {
  581. return content.substring(0, content.length - 2);
  582. }
  583. def String removeArgumentParenthesis(String content) {
  584. val startParen = content.indexOf('(');
  585. return content.substring(0,startParen);
  586. }
  587. /*
  588. * Calculates necessary information on global in/out variables
  589. */
  590. def Pair<String, LinkedHashMap<String, GlobalInOutVariable>> compileRuleBlockVars(EList<Declaration> gVars,
  591. LinkedHashMap<String, GlobalInOutVariable> params) {
  592. val visitor = new RulesConditionSwitch("", "", "", null, null, params, null, null, null)
  593. return visitor.getGlobalVars(gVars);
  594. }
  595. /*
  596. * Compiles the source file functions <in/out>_rule_<condition, body, flush>.
  597. * Calculates necessary information on function signatures necessary for generation of the header file.
  598. * Added the extra input and output functions
  599. */
  600. def InOutRulesBlockResult compileInOutRuleBlocks(
  601. IORuleType ioType,
  602. InOutRules rulesBlock,
  603. String adaptationClassName,
  604. String adaptationName,
  605. LinkedHashMap<String, LinkedHashMap<String, MappedScalarVariable>> mSVars,
  606. LinkedHashMap<String, SAScalarVariable> SASVs,
  607. LinkedHashMap<String, GlobalInOutVariable> params,
  608. LinkedHashMap<String, GlobalInOutVariable> inVars,
  609. LinkedHashMap<String, GlobalInOutVariable> outVars,
  610. LinkedHashMap<String, GlobalInOutVariable> crtlVars,
  611. List<Port> portsWithSrcDep
  612. ) {
  613. val visitor = if (ioType == IORuleType.Input)
  614. new InRulesConditionSwitch(adaptationClassName, adaptationName, mSVars, SASVs, params, inVars,
  615. outVars, crtlVars)
  616. else
  617. new OutRulesConditionSwitch(adaptationClassName, adaptationName, mSVars, SASVs, params, inVars,
  618. outVars, crtlVars);
  619. val functionName = "create" + ioType + "Rules()";
  620. var String cpp = "";
  621. var List<String> allFunctionSignatures = newArrayList();
  622. if (rulesBlock !== null) {
  623. cpp += visitor.doSwitch(rulesBlock).code;
  624. }
  625. if (!visitor.functionSignatures.empty || !portsWithSrcDep.empty) {
  626. allFunctionSignatures.addAll(visitor.functionSignatures);
  627. var ArrayList<String> createRulesFunction = newArrayList();
  628. if (rulesBlock !== null) {
  629. // For-loop Handles the out rules defined in the sa file
  630. for (var int i = 0; i < (visitor.functionSignatures.length); i += 3) {
  631. createRulesFunction.add(
  632. '''
  633. list->push_back(
  634. (Rule<«adaptationClassName»>){
  635. &«adaptationClassName»::«visitor.functionSignatures.get(i).SplitAtSpaceAndRemoveFirst.removeArgumentParenthesis»,
  636. &«adaptationClassName»::«visitor.functionSignatures.get(i+1).SplitAtSpaceAndRemoveFirst.removeArgumentParenthesis»,
  637. &«adaptationClassName»::«visitor.functionSignatures.get(i+2).SplitAtSpaceAndRemoveFirst.removeArgumentParenthesis»
  638. });
  639. ''');
  640. }
  641. }
  642. var List<String> depFunctionSource = newArrayList();
  643. var List<String> depFunctionSignatures = newArrayList();
  644. for (var int i = 0; i < portsWithSrcDep.length; i++) {
  645. val currentPort = portsWithSrcDep.get(i);
  646. // Output ports uses source dependencies.
  647. // Input ports uses target dependencies;
  648. val dependency = (if (ioType == IORuleType.Input)
  649. currentPort.targetdependency
  650. else
  651. currentPort.sourcedependency);
  652. val newCount = visitor.functionSignatures.length + i + 1;
  653. val funcSigCon = visitor.createFunctionSignature('''condition''', "bool", newCount,
  654. depFunctionSignatures)
  655. val funcSigBody = visitor.createFunctionSignature('''body''', "void", newCount,
  656. depFunctionSignatures)
  657. val funcSigFlush = visitor.createFunctionSignature('''flush''', "void", newCount,
  658. depFunctionSignatures)
  659. val type = mSVars.get(dependency.owner.name).get(dependency.port.name).mappedSv.type;
  660. val define = mSVars.get(dependency.owner.name).get(dependency.port.name).define;
  661. var ruleCpp = "";
  662. if (ioType == IORuleType.Output) {
  663. val getValueCpp = '''getValue«Conversions.fmiTypeToGetValueString(type)»(«dependency.owner.name»,«define»)''';
  664. ruleCpp = '''
  665. «funcSigCon»{
  666. «Utilities.getDebug(funcSigCon)»
  667. return true;
  668. }
  669. «funcSigBody»{
  670. «Utilities.getDebug(funcSigBody)»
  671. this->internalState.stored_«dependency.owner.name»_«dependency.port.name» = «getValueCpp»;
  672. }
  673. «funcSigFlush»{
  674. «Utilities.getDebug(funcSigFlush)»
  675. this->internalState.«currentPort.name» = this->internalState.stored_«dependency.owner.name»_«dependency.port.name»;
  676. }
  677. '''
  678. } else if (ioType == IORuleType.Input) {
  679. val setValueCpp = '''setValue(«dependency.owner.name»,«define»,this->internalState.stored_«dependency.owner.name»_«dependency.port.name»);''';
  680. ruleCpp = '''
  681. «funcSigCon»{
  682. «Utilities.getDebug(funcSigCon)»
  683. return true;
  684. }
  685. «funcSigBody»{
  686. «Utilities.getDebug(funcSigBody)»
  687. this->internalState.stored_«dependency.owner.name»_«dependency.port.name» = this->internalState.«currentPort.name»;
  688. }
  689. «funcSigFlush»{
  690. «Utilities.getDebug(funcSigFlush)»
  691. «setValueCpp»
  692. }
  693. '''
  694. }
  695. cpp += ruleCpp;
  696. depFunctionSource.add(funcSigCon);
  697. depFunctionSource.add(funcSigBody);
  698. depFunctionSource.add(funcSigFlush);
  699. }
  700. allFunctionSignatures.addAll(depFunctionSignatures);
  701. for (var int i = 0; i < (depFunctionSource.length); i += 3) {
  702. createRulesFunction.add(
  703. '''
  704. list->push_back(
  705. (Rule<«adaptationClassName»>){
  706. &«depFunctionSource.get(i).SplitAtSpaceAndRemoveFirst.removeArgumentParenthesis»,
  707. &«depFunctionSource.get(i+1).SplitAtSpaceAndRemoveFirst.removeArgumentParenthesis»,
  708. &«depFunctionSource.get(i+2).SplitAtSpaceAndRemoveFirst.removeArgumentParenthesis»
  709. });
  710. ''');
  711. }
  712. // Handles the createOutputRules and createInputRules
  713. val functionPrefix = '''shared_ptr<list<Rule<«adaptationClassName»>>>''';
  714. allFunctionSignatures.add(functionPrefix + " " + functionName)
  715. cpp += '''
  716. «functionPrefix» «adaptationClassName»::«functionName»
  717. {
  718. auto list = make_shared<std::list<Rule<«adaptationClassName»>>>();
  719. «createRulesFunction.join("\n")»
  720. return list;
  721. }
  722. '''
  723. }
  724. return new InOutRulesBlockResult(cpp, allFunctionSignatures);
  725. }
  726. /*
  727. * Calculates the semantic adaptation scalar variables via input ports and output ports.
  728. * Note: These a not fully populated yet as the in rules and out rules must be compiled first.
  729. */
  730. def LinkedHashMap<String, SAScalarVariable> calcSASVsFromInportsOutports(String definePrefix,
  731. EList<Port> inports, EList<Port> outports,
  732. LinkedHashMap<String, LinkedHashMap<String, MappedScalarVariable>> mSVs) {
  733. var LinkedHashMap<String, SAScalarVariable> saSVs = newLinkedHashMap();
  734. var int valueReference = 0;
  735. for (inport : inports) {
  736. var saSV = new SAScalarVariable();
  737. saSV.SetPartOfMD(true);
  738. saSV.valueReference = valueReference++;
  739. saSV.name = inport.name;
  740. saSV.defineName = (definePrefix + inport.name).toUpperCase
  741. saSV.causality = SVCausality.input;
  742. saSVs.put(saSV.name, saSV);
  743. if (inport.targetdependency !== null) {
  744. saSV.type = mSVs.get(inport.targetdependency.owner.name).get(inport.targetdependency.port.name).
  745. mappedSv.type;
  746. saSV.variability = mSVs.get(inport.targetdependency.owner.name).get(
  747. inport.targetdependency.port.name).mappedSv.variability;
  748. }
  749. }
  750. for (outport : outports) {
  751. var saSV = new SAScalarVariable();
  752. if (outport.sourcedependency !== null) {
  753. saSV.type = mSVs.get(outport.sourcedependency.owner.name).get(outport.sourcedependency.port.name).
  754. mappedSv.type;
  755. saSV.variability = mSVs.get(outport.sourcedependency.owner.name).get(
  756. outport.sourcedependency.port.name).mappedSv.variability;
  757. }
  758. saSV.SetPartOfMD(true);
  759. saSV.valueReference = valueReference++;
  760. saSV.defineName = (definePrefix + outport.name).toUpperCase
  761. saSV.name = outport.name;
  762. saSV.causality = SVCausality.output;
  763. saSVs.put(saSV.name, saSV);
  764. }
  765. return saSVs;
  766. }
  767. def List<File> getResourcePaths() {
  768. return resourcePaths;
  769. }
  770. }