CppGenerator.xtend 37 KB

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