CppGenerator.xtend 34 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001
  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, if(inVars !== null) inVars.value else null,
  192. if(outVars !== null) outVars.value else null, if(crtlVars !== null) crtlVars.value else null);
  193. /*
  194. * Compile the constructor, destructor and initialize functions
  195. */
  196. val String deAndConstructorAndInitializeSource = compileDeAndConstructorAndInitialize(
  197. adapClassName,
  198. innerFMUsData,
  199. md.guid,
  200. paramsConstructorSource,
  201. if(inVars !== null) inVars.key else "",
  202. if(outVars !== null) outVars.key else "",
  203. if(crtlVars !== null) crtlVars.key else "",
  204. adap.machine,
  205. adap.reactiveness,
  206. inRules !== null || inPortsWithSrcDep.length > 0,
  207. outRules !== null || outPortsWithSrcDep.length > 0
  208. );
  209. /*
  210. * Compile getRuleThis function
  211. */
  212. val String getRuleThisSource = compileGetRuleThis(adapClassName);
  213. /*
  214. * The in and out rules have populated the semantic adaptation scalar variables we can generate the getFmiValue* and setFmiValue functions.
  215. */
  216. val String getFuncsSource = compileGetFmiValueFunctions(adapClassName, SASVs);
  217. val String setFuncsSource = compileSetFmiValueFunctions(adapClassName, SASVs);
  218. // Compile the state functions
  219. val Pair<String,String> stateFunctions = compileStateFunctions(adapClassName);
  220. // Compile the source file
  221. val String sourceInclude = '''#include "«adapClassName».h"''';
  222. val sourceFile = compileSource(
  223. sourceInclude,
  224. deAndConstructorAndInitializeSource,
  225. getRuleThisSource,
  226. getFuncsSource,
  227. setFuncsSource,
  228. inRuleResult.generatedCpp,
  229. outRuleResult.generatedCpp,
  230. crtlRuleResult.generatedCpp,
  231. stateFunctions.value
  232. );
  233. fsa.generateFile(adapClassName + ".cpp", sourceFile);
  234. // Merge the global variables for use in compiling the header file.
  235. // TODO: Check for duplicates
  236. var LinkedHashMap<String, GlobalInOutVariable> allGVars = newLinkedHashMap();
  237. allGVars.putAll(params);
  238. if (inVars !== null)
  239. allGVars.putAll(inVars.value);
  240. if (outVars !== null)
  241. allGVars.putAll(outVars.value);
  242. if (crtlVars !== null)
  243. allGVars.putAll(crtlVars.value);
  244. // Compile the header file
  245. val headerFile = compileHeader(
  246. adapClassName,
  247. fmusDefines,
  248. SADefines,
  249. inRuleResult.functionSignatures,
  250. outRuleResult.functionSignatures,
  251. crtlRuleResult.functionSignatures,
  252. allGVars,
  253. innerFMUsData,
  254. SASVs.values.map[CalcSVar()].toList,
  255. stateFunctions.key
  256. );
  257. fsa.generateFile(adapClassName + ".h", headerFile);
  258. // Compile the model description file
  259. val modelDescCreator = new ModelDescriptionCreator(adapExternalName);
  260. val modelDescription = modelDescCreator.generateModelDescription(SASVs.values);
  261. fsa.generateFile("modelDescription.xml", modelDescription);
  262. // Compile the fmu.cpp file
  263. val fmuCppFile = FmuGenerator.genFmuCppFile(adapClassName);
  264. fsa.generateFile("Fmu.cpp", fmuCppFile);
  265. fsa.generateFile("CMakeLists.txt",CMakeListsGenerator.generateCMakeLists(adapExternalName))
  266. fsa.generateFile("msys-toolchain.cmake",CMakeListsGenerator.generateToolChainCmake());
  267. }
  268. }
  269. def getFMUFile(String fmuUnresolvedPath, String resolvedFolderURI) {
  270. Log.println("Current working dir: " + resolvedFolderURI)
  271. //var resolvedFolderURI = CommonPlugin.resolve(adaptationFolderURI);
  272. Log.println("Resolved Current working dir: " + resolvedFolderURI)
  273. val fmuCompleteURI = URI.createFileURI(resolvedFolderURI + File.separatorChar + fmuUnresolvedPath.replace('\"', ''))
  274. var fmuPath = fmuCompleteURI.toFileString
  275. Log.println("Resolved fmu path: " + fmuPath)
  276. val fmuFile = new File(fmuPath);
  277. return fmuFile
  278. }
  279. def String compileParams(LinkedHashMap<String, GlobalInOutVariable> gVars, EList<ParamDeclarations> params) {
  280. val paramsConditionSwitch = new ParamConditionSwitch(gVars);
  281. var String paramsConstructorSource = "";
  282. for (paramDecl : params) {
  283. val doSwitchRes = paramsConditionSwitch.doSwitch(paramDecl);
  284. paramsConstructorSource += doSwitchRes.code;
  285. }
  286. return paramsConstructorSource;
  287. }
  288. def calcSADefines(Collection<SAScalarVariable> variables) {
  289. var ArrayList<String> defines = newArrayList();
  290. for (SASV : variables) {
  291. defines.add("#define " + SASV.defineName + " " + SASV.valueReference);
  292. }
  293. return defines.join("\n");
  294. }
  295. def calcDefines(LinkedHashMap<String, LinkedHashMap<String, MappedScalarVariable>> map) {
  296. var ArrayList<String> defines = newArrayList();
  297. for (fmuEntries : map.entrySet) {
  298. for (MappedScalarVariable mSV : fmuEntries.value.values) {
  299. defines.add("#define " + mSV.define.replace('(','_').replace(')','_') + " " + mSV.valueReference);
  300. }
  301. }
  302. return defines.join("\n");
  303. }
  304. def Pair<String,String> compileStateFunctions(String saName)
  305. {
  306. return
  307. '''
  308. fmi2FMUstate getInternalFMUState();
  309. void setInternalFMUState(fmi2FMUstate state);
  310. void freeInternalFMUState(fmi2FMUstate state);
  311. '''
  312. ->
  313. '''
  314. fmi2FMUstate «saName»::getInternalFMUState()
  315. {
  316. InternalState* s = new InternalState();
  317. *s = this->internalState;
  318. return s;
  319. }
  320. void «saName»::setInternalFMUState(fmi2FMUstate state)
  321. {
  322. this->internalState = *(InternalState*)state;
  323. }
  324. void «saName»::freeInternalFMUState(fmi2FMUstate state)
  325. {
  326. delete (InternalState*)state;
  327. }''';
  328. }
  329. // Compiles the final source file
  330. def String compileSource(String include, String constructor, String getRuleThis, String getFunctions,
  331. String setFunctions, String inFunctions, String outFunctions, String controlFunction, String stateFunctions) {
  332. return '''
  333. «include»
  334. namespace adaptation
  335. {
  336. «constructor»
  337. «getRuleThis»
  338. «getFunctions»
  339. «setFunctions»
  340. «inFunctions»
  341. «controlFunction»
  342. «outFunctions»
  343. «stateFunctions»
  344. }
  345. '''
  346. }
  347. /*
  348. * Compiles the header file split into two: The first part contains the includes and using namespace definitions and start the ,
  349. * the second part contains the class
  350. */
  351. def String compileHeader(String adapClassName, String fmusDefines, String SADefines,
  352. List<String> inRulesFuncSig, List<String> outRulesFuncSig, List<String> crtlRulesFuncSig,
  353. LinkedHashMap<String, GlobalInOutVariable> globalVariables, ArrayList<InnerFMUData> fmus,
  354. Collection<ScalarVariable> sVars, String stateFunctions) {
  355. return '''
  356. #ifndef SRC_«adapClassName.toUpperCase»_H
  357. #define SRC_«adapClassName.toUpperCase»_H
  358. #include "SemanticAdaptation.h"
  359. #include "HyfMath.h"
  360. #include <memory>
  361. #include "Fmu.h"
  362. using namespace std;
  363. using namespace fmi2;
  364. namespace adaptation
  365. {
  366. «fmusDefines»
  367. «SADefines»
  368. class «adapClassName» : public SemanticAdaptation<«adapClassName»>, public enable_shared_from_this<«adapClassName»>
  369. {
  370. public:
  371. «adapClassName»(shared_ptr<std::string> fmiInstanceName, shared_ptr<string> resourceLocation, const fmi2CallbackFunctions* functions);
  372. void initialize(bool loggingOn);
  373. virtual ~«adapClassName»();
  374. void setFmiValue(fmi2ValueReference id, int value);
  375. void setFmiValue(fmi2ValueReference id, bool value);
  376. void setFmiValue(fmi2ValueReference id, double value);
  377. void setFmiValue(fmi2ValueReference id, string value);
  378. int getFmiValueInteger(fmi2ValueReference id);
  379. bool getFmiValueBoolean(fmi2ValueReference id);
  380. double getFmiValueReal(fmi2ValueReference id);
  381. string getFmiValueString(fmi2ValueReference id);
  382. protected:
  383. «stateFunctions»
  384. private:
  385. «adapClassName»* getRuleThis();
  386. /*in rules*/
  387. «inRulesFuncSig.map[x | x+";"].join("\n")»
  388. /*out rules*/
  389. «outRulesFuncSig.map[x | x+";"].join("\n")»
  390. «crtlRulesFuncSig.map[x | x+";"].join("\n")»
  391. «FOR fmu : fmus»
  392. shared_ptr<FmuComponent> «fmu.name»;
  393. «ENDFOR»
  394. struct InternalState {
  395. «FOR sv : sVars»
  396. «Conversions.fmiTypeToCppType(sv.type)» «sv.name»;
  397. «IF sv.causality == SVCausality.input»
  398. bool isSet«sv.name»;
  399. «ENDIF»
  400. «ENDFOR»
  401. «FOR v : globalVariables.entrySet»
  402. «Conversions.fmiTypeToCppType(v.value.type)» «v.key»;
  403. «ENDFOR»
  404. };
  405. InternalState internalState;
  406. };
  407. }
  408. #endif
  409. ''';
  410. }
  411. /*
  412. * Compiles the source file constructor, destructor and the initialize function
  413. */
  414. def String compileDeAndConstructorAndInitialize(String adapClassName, ArrayList<InnerFMUData> fmus, String guid,
  415. String paramsCons, String inCons, String outCons, String crtlCons, MooreOrMealy machineType,
  416. ReactiveOrDelayed reactiveOrDealyed, boolean inputRules, boolean outputRules) {
  417. var ArrayList<String> initialisations = newArrayList();
  418. if (reactiveOrDealyed == ReactiveOrDelayed.DELAYED) {
  419. initialisations.add('''this->reactiveness = ReactiveOrDelayed::Delayed;''');
  420. } else if (reactiveOrDealyed == ReactiveOrDelayed.REACTIVE) {
  421. initialisations.add('''this->reactiveness = ReactiveOrDelayed::Reactive;''');
  422. }
  423. if (machineType == MooreOrMealy.MOORE) {
  424. initialisations.add('''this->machineType = MooreOrMealy::Moore;''');
  425. } else if (machineType == MooreOrMealy.MEALY) {
  426. initialisations.add('''this->machineType = MooreOrMealy::Mealy;''');
  427. }
  428. var pathCount = 1;
  429. for (fmu : fmus) {
  430. val pathName = '''path«pathCount»''';
  431. pathCount++;
  432. initialisations.add('''
  433. auto «pathName» = make_shared<string>(*resourceLocation);
  434. «pathName»->append(string(«fmu.getPath»));
  435. auto «fmu.name»Fmu = make_shared<fmi2::Fmu>(*«pathName»);
  436. «fmu.name»Fmu->initialize();
  437. this->«fmu.name» = «fmu.name»Fmu->instantiate("«fmu.name»",fmi2CoSimulation, "«fmu.guid»", true, loggingOn, shared_from_this());
  438. if(this->«fmu.name»->component == NULL)
  439. this->lastErrorState = fmi2Fatal;
  440. this->instances->push_back(this->«fmu.name»);
  441. ''');
  442. }
  443. return '''
  444. «adapClassName»::«adapClassName»(shared_ptr<std::string> fmiInstanceName,shared_ptr<string> resourceLocation, const fmi2CallbackFunctions* functions) :
  445. SemanticAdaptation(fmiInstanceName, resourceLocation, «if(inputRules) "createInputRules()" else "NULL"», «if(outputRules) "createOutputRules()" else "NULL"», functions)
  446. {
  447. «paramsCons»
  448. «inCons»
  449. «outCons»
  450. «crtlCons»
  451. }
  452. void «adapClassName»::initialize(bool loggingOn)
  453. {
  454. «initialisations.join("\r\n")»
  455. }
  456. «adapClassName»::~«adapClassName»()
  457. {
  458. }
  459. ''';
  460. }
  461. /*
  462. * Compiles the source file function getRuleThis
  463. */
  464. def String compileGetRuleThis(String adaptationName) {
  465. return '''
  466. «adaptationName»* «adaptationName»::getRuleThis()
  467. {
  468. return this;
  469. }
  470. '''
  471. }
  472. /*
  473. * Compiles the source file functions getFmiValue<double, int, string, bool>
  474. */
  475. def String compileGetFmiValueFunctions(String adaptationName,
  476. LinkedHashMap<String, SAScalarVariable> variables) {
  477. var ArrayList<String> cpp = newArrayList();
  478. var List<ScalarVariable> convertedSASVs = variables.values.map[CalcSVar()].toList;
  479. var convertedSASVsOrdered = convertedSASVs.filter[causality === SVCausality.output].groupBy[type];
  480. for (SVType type : SVType.values) {
  481. val functionSignature = '''«Conversions.fmiTypeToCppType(type)» «adaptationName»::getFmiValue«type.toString»(fmi2ValueReference id)''';
  482. val functionReturn = '''return «Conversions.fmiTypeToCppDefaultValue(type)»''';
  483. if (convertedSASVsOrdered.containsKey(type)) {
  484. cpp.add(
  485. '''
  486. «functionSignature»
  487. {
  488. «Utilities.getDebug(functionSignature)»
  489. switch (id)
  490. {
  491. «FOR svInner : convertedSASVsOrdered.get(type)»
  492. case «variables.get(svInner.name).defineName»:
  493. {
  494. return this->internalState.«svInner.name»;
  495. }
  496. «ENDFOR»
  497. default:
  498. {
  499. «functionReturn»;
  500. }
  501. }
  502. }
  503. '''
  504. );
  505. } else {
  506. cpp.add(
  507. '''
  508. «functionSignature»
  509. {
  510. «Utilities.getDebug(functionSignature)»
  511. «functionReturn»;
  512. }
  513. '''
  514. );
  515. }
  516. }
  517. return cpp.join("\n");
  518. }
  519. /*
  520. * Compiles the source file functions setFmiValue<double, int, string, bool>*
  521. */
  522. def String compileSetFmiValueFunctions(String adapClassName,
  523. LinkedHashMap<String, SAScalarVariable> variables) {
  524. var ArrayList<String> cpp = newArrayList();
  525. var List<ScalarVariable> convertedSASVs = variables.values.map[CalcSVar()].filter [
  526. causality === SVCausality.input
  527. ].toList;
  528. var convertedSASVsOrdered = convertedSASVs.groupBy[type];
  529. for (SVType type : SVType.values) {
  530. val functionSignature = '''void «adapClassName»::setFmiValue(fmi2ValueReference id, «Conversions.fmiTypeToCppType(type)» value)''';
  531. cpp.add(
  532. '''
  533. «functionSignature»
  534. {
  535. «Utilities.getDebug2('''printf("«adapClassName»::setFmiValue(%d,?)",id);''')»
  536. «IF convertedSASVsOrdered.containsKey(type)»
  537. switch (id)
  538. {
  539. «FOR svInner : convertedSASVsOrdered.get(type)»
  540. case «variables.get(svInner.name).defineName»:
  541. {
  542. this->internalState.«svInner.name» = value;
  543. this->internalState.isSet«svInner.name» = true;
  544. break;
  545. }
  546. «ENDFOR»
  547. default:
  548. {
  549. }
  550. }
  551. «ENDIF»
  552. }
  553. '''
  554. );
  555. }
  556. return cpp.join("\n");
  557. }
  558. /*
  559. * Compiles the source file function executeInternalControlFlow.
  560. * Calculates necessary information on function signatures necessary for generation of the header file.
  561. */
  562. def InOutRulesBlockResult compileControlRuleBlock(ControlRuleBlock crtlRuleBlock, String adaptationClassName,
  563. String adaptationName, LinkedHashMap<String, LinkedHashMap<String, MappedScalarVariable>> mSVars,
  564. LinkedHashMap<String, SAScalarVariable> SASVs, LinkedHashMap<String, GlobalInOutVariable> params,
  565. LinkedHashMap<String, GlobalInOutVariable> inVars, LinkedHashMap<String, GlobalInOutVariable> outVars,
  566. LinkedHashMap<String, GlobalInOutVariable> crtlVars) {
  567. var cpp = "";
  568. val visitor = new ControlConditionSwitch(adaptationClassName, adaptationName,
  569. mSVars, SASVs, params, inVars, outVars, crtlVars
  570. );
  571. if (crtlRuleBlock !== null)
  572. cpp += visitor.doSwitch(crtlRuleBlock).code;
  573. return new InOutRulesBlockResult(cpp, visitor.functionSignatures);
  574. }
  575. def String SplitAtSpaceAndRemoveFirst(String content) {
  576. content.substring(content.indexOf(" ") + 1, content.length);
  577. }
  578. def String removeEmptyArgumentParenthesis(String content) {
  579. return content.substring(0, content.length - 2);
  580. }
  581. def String removeArgumentParenthesis(String content) {
  582. val startParen = content.indexOf('(');
  583. return content.substring(0,startParen);
  584. }
  585. /*
  586. * Calculates necessary information on global in/out variables
  587. */
  588. def Pair<String, LinkedHashMap<String, GlobalInOutVariable>> compileRuleBlockVars(EList<Declaration> gVars,
  589. LinkedHashMap<String, GlobalInOutVariable> params) {
  590. val visitor = new RulesConditionSwitch("", "", "", null, null, params, null, null, null)
  591. return visitor.getGlobalVars(gVars);
  592. }
  593. /*
  594. * Compiles the source file functions <in/out>_rule_<condition, body, flush>.
  595. * Calculates necessary information on function signatures necessary for generation of the header file.
  596. * Added the extra input and output functions
  597. */
  598. def InOutRulesBlockResult compileInOutRuleBlocks(
  599. IORuleType ioType,
  600. InOutRules rulesBlock,
  601. String adaptationClassName,
  602. String adaptationName,
  603. LinkedHashMap<String, LinkedHashMap<String, MappedScalarVariable>> mSVars,
  604. LinkedHashMap<String, SAScalarVariable> SASVs,
  605. LinkedHashMap<String, GlobalInOutVariable> params,
  606. LinkedHashMap<String, GlobalInOutVariable> inVars,
  607. LinkedHashMap<String, GlobalInOutVariable> outVars,
  608. LinkedHashMap<String, GlobalInOutVariable> crtlVars,
  609. List<Port> portsWithSrcDep
  610. ) {
  611. val visitor = if (ioType == IORuleType.Input)
  612. new InRulesConditionSwitch(adaptationClassName, adaptationName, mSVars, SASVs, params, inVars,
  613. outVars, crtlVars)
  614. else
  615. new OutRulesConditionSwitch(adaptationClassName, adaptationName, mSVars, SASVs, params, inVars,
  616. outVars, crtlVars);
  617. val functionName = "create" + ioType + "Rules()";
  618. var String cpp = "";
  619. var List<String> allFunctionSignatures = newArrayList();
  620. if (rulesBlock !== null) {
  621. cpp += visitor.doSwitch(rulesBlock).code;
  622. }
  623. if (!visitor.functionSignatures.empty || !portsWithSrcDep.empty) {
  624. allFunctionSignatures.addAll(visitor.functionSignatures);
  625. var ArrayList<String> createRulesFunction = newArrayList();
  626. if (rulesBlock !== null) {
  627. // For-loop Handles the out rules defined in the sa file
  628. for (var int i = 0; i < (visitor.functionSignatures.length); i += 3) {
  629. createRulesFunction.add(
  630. '''
  631. list->push_back(
  632. (Rule<«adaptationClassName»>){
  633. &«adaptationClassName»::«visitor.functionSignatures.get(i).SplitAtSpaceAndRemoveFirst.removeArgumentParenthesis»,
  634. &«adaptationClassName»::«visitor.functionSignatures.get(i+1).SplitAtSpaceAndRemoveFirst.removeArgumentParenthesis»,
  635. &«adaptationClassName»::«visitor.functionSignatures.get(i+2).SplitAtSpaceAndRemoveFirst.removeArgumentParenthesis»
  636. });
  637. ''');
  638. }
  639. }
  640. var List<String> depFunctionSource = newArrayList();
  641. var List<String> depFunctionSignatures = newArrayList();
  642. for (var int i = 0; i < portsWithSrcDep.length; i++) {
  643. val currentPort = portsWithSrcDep.get(i);
  644. // Output ports uses source dependencies.
  645. // Input ports uses target dependencies;
  646. val dependency = (if (ioType == IORuleType.Input)
  647. currentPort.targetdependency
  648. else
  649. currentPort.sourcedependency);
  650. val newCount = visitor.functionSignatures.length + i + 1;
  651. val funcSigCon = visitor.createFunctionSignature('''condition''', "bool", newCount,
  652. depFunctionSignatures)
  653. val funcSigBody = visitor.createFunctionSignature('''body''', "void", newCount,
  654. depFunctionSignatures)
  655. val funcSigFlush = visitor.createFunctionSignature('''flush''', "void", newCount,
  656. depFunctionSignatures)
  657. val type = mSVars.get(dependency.owner.name).get(dependency.port.name).mappedSv.type;
  658. val define = mSVars.get(dependency.owner.name).get(dependency.port.name).define;
  659. var ruleCpp = "";
  660. if (ioType == IORuleType.Output) {
  661. val getValueCpp = '''getValue«Conversions.fmiTypeToGetValueString(type)»(«dependency.owner.name»,«define»)''';
  662. ruleCpp = '''
  663. «funcSigCon»{
  664. «Utilities.getDebug(funcSigCon)»
  665. return true;
  666. }
  667. «funcSigBody»{
  668. «Utilities.getDebug(funcSigBody)»
  669. this->internalState.stored_«dependency.owner.name»_«dependency.port.name» = «getValueCpp»;
  670. }
  671. «funcSigFlush»{
  672. «Utilities.getDebug(funcSigFlush)»
  673. this->internalState.«currentPort.name» = this->internalState.stored_«dependency.owner.name»_«dependency.port.name»;
  674. }
  675. '''
  676. } else if (ioType == IORuleType.Input) {
  677. val setValueCpp = '''setValue(«dependency.owner.name»,«define»,this->internalState.stored_«dependency.owner.name»_«dependency.port.name»);''';
  678. ruleCpp = '''
  679. «funcSigCon»{
  680. «Utilities.getDebug(funcSigCon)»
  681. return true;
  682. }
  683. «funcSigBody»{
  684. «Utilities.getDebug(funcSigBody)»
  685. this->internalState.stored_«dependency.owner.name»_«dependency.port.name» = this->internalState.«currentPort.name»;
  686. }
  687. «funcSigFlush»{
  688. «Utilities.getDebug(funcSigFlush)»
  689. «setValueCpp»
  690. }
  691. '''
  692. }
  693. cpp += ruleCpp;
  694. depFunctionSource.add(funcSigCon);
  695. depFunctionSource.add(funcSigBody);
  696. depFunctionSource.add(funcSigFlush);
  697. }
  698. allFunctionSignatures.addAll(depFunctionSignatures);
  699. for (var int i = 0; i < (depFunctionSource.length); i += 3) {
  700. createRulesFunction.add(
  701. '''
  702. list->push_back(
  703. (Rule<«adaptationClassName»>){
  704. &«depFunctionSource.get(i).SplitAtSpaceAndRemoveFirst.removeArgumentParenthesis»,
  705. &«depFunctionSource.get(i+1).SplitAtSpaceAndRemoveFirst.removeArgumentParenthesis»,
  706. &«depFunctionSource.get(i+2).SplitAtSpaceAndRemoveFirst.removeArgumentParenthesis»
  707. });
  708. ''');
  709. }
  710. // Handles the createOutputRules and createInputRules
  711. val functionPrefix = '''shared_ptr<list<Rule<«adaptationClassName»>>>''';
  712. allFunctionSignatures.add(functionPrefix + " " + functionName)
  713. cpp += '''
  714. «functionPrefix» «adaptationClassName»::«functionName»
  715. {
  716. auto list = make_shared<std::list<Rule<«adaptationClassName»>>>();
  717. «createRulesFunction.join("\n")»
  718. return list;
  719. }
  720. '''
  721. }
  722. return new InOutRulesBlockResult(cpp, allFunctionSignatures);
  723. }
  724. /*
  725. * Calculates the semantic adaptation scalar variables via input ports and output ports.
  726. * Note: These a not fully populated yet as the in rules and out rules must be compiled first.
  727. */
  728. def LinkedHashMap<String, SAScalarVariable> calcSASVsFromInportsOutports(String definePrefix,
  729. EList<Port> inports, EList<Port> outports,
  730. LinkedHashMap<String, LinkedHashMap<String, MappedScalarVariable>> mSVs) {
  731. var LinkedHashMap<String, SAScalarVariable> saSVs = newLinkedHashMap();
  732. var int valueReference = 0;
  733. for (inport : inports) {
  734. var saSV = new SAScalarVariable();
  735. saSV.SetPartOfMD(true);
  736. saSV.valueReference = valueReference++;
  737. saSV.name = inport.name;
  738. saSV.defineName = (definePrefix + inport.name).toUpperCase
  739. saSV.causality = SVCausality.input;
  740. saSVs.put(saSV.name, saSV);
  741. if (inport.targetdependency !== null) {
  742. saSV.type = mSVs.get(inport.targetdependency.owner.name).get(inport.targetdependency.port.name).
  743. mappedSv.type;
  744. saSV.variability = mSVs.get(inport.targetdependency.owner.name).get(
  745. inport.targetdependency.port.name).mappedSv.variability;
  746. }
  747. }
  748. for (outport : outports) {
  749. var saSV = new SAScalarVariable();
  750. if (outport.sourcedependency !== null) {
  751. saSV.type = mSVs.get(outport.sourcedependency.owner.name).get(outport.sourcedependency.port.name).
  752. mappedSv.type;
  753. saSV.variability = mSVs.get(outport.sourcedependency.owner.name).get(
  754. outport.sourcedependency.port.name).mappedSv.variability;
  755. }
  756. saSV.SetPartOfMD(true);
  757. saSV.valueReference = valueReference++;
  758. saSV.defineName = (definePrefix + outport.name).toUpperCase
  759. saSV.name = outport.name;
  760. saSV.causality = SVCausality.output;
  761. saSVs.put(saSV.name, saSV);
  762. }
  763. return saSVs;
  764. }
  765. def List<File> getResourcePaths() {
  766. return resourcePaths;
  767. }
  768. }