sim_support.c 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595
  1. /* -------------------------------------------------------------------------
  2. * sim_support.c
  3. * Functions used by both FMU simulators fmu20sim_me and fmu20sim_cs
  4. * to parse command-line arguments, to unzip and load an fmu,
  5. * to write CSV file, and more.
  6. *
  7. * Revision history
  8. * 07.03.2014 initial version released in FMU SDK 2.0.0
  9. * 10.04.2014 use FMI 2.0 headers that prefix function and type names with 'fmi2'.
  10. * When 'fmi2' functions are not found in loaded DLL, look also for
  11. * FMI 2.0 RC1 function names.
  12. *
  13. * Author: Adrian Tirea
  14. * Copyright QTronic GmbH. All rights reserved.
  15. * -------------------------------------------------------------------------*/
  16. #include <stdio.h>
  17. #include <stdlib.h>
  18. #include <string.h>
  19. #include <assert.h>
  20. #include <stdarg.h>
  21. #include <dlfcn.h>
  22. #include "fmi2.h"
  23. #include "sim_support.h"
  24. #define FMI_COSIMULATION
  25. extern FMU fmu;
  26. //int unzip(const char *zipPath, const char *outPath) {
  27. // int code;
  28. // char cwd[BUFSIZE];
  29. // char binPath[BUFSIZE];
  30. // int n = strlen(UNZIP_CMD) + strlen(outPath) + 3 + strlen(zipPath) + 9;
  31. // char* cmd = (char*)calloc(sizeof(char), n);
  32. //
  33. // // remember current directory
  34. // if (!GetCurrentDirectory(BUFSIZE, cwd)) {
  35. // printf ("error: Could not get current directory\n");
  36. // return 0; // error
  37. // }
  38. //
  39. // // change to %FMUSDK_HOME%\bin to find 7z.dll and 7z.exe
  40. // if (!GetEnvironmentVariable("FMUSDK_HOME", binPath, BUFSIZE)) {
  41. // if (GetLastError() == ERROR_ENVVAR_NOT_FOUND) {
  42. // printf ("error: Environment variable FMUSDK_HOME not defined\n");
  43. // }
  44. // else {
  45. // printf ("error: Could not get value of FMUSDK_HOME\n");
  46. // }
  47. // return 0; // error
  48. // }
  49. // strcat(binPath, "\\bin");
  50. // if (!SetCurrentDirectory(binPath)) {
  51. // printf ("error: could not change to directory '%s'\n", binPath);
  52. // return 0; // error
  53. // }
  54. //
  55. // // run the unzip command
  56. // // remove "> NUL" to see the unzip protocol
  57. // sprintf(cmd, "%s\"%s\" \"%s\" > NUL", UNZIP_CMD, outPath, zipPath);
  58. // // printf("cmd='%s'\n", cmd);
  59. // code = system(cmd);
  60. // free(cmd);
  61. // if (code != SEVEN_ZIP_NO_ERROR) {
  62. // printf("7z: ");
  63. // switch (code) {
  64. // case SEVEN_ZIP_WARNING: printf("warning\n"); break;
  65. // case SEVEN_ZIP_ERROR: printf("error\n"); break;
  66. // case SEVEN_ZIP_COMMAND_LINE_ERROR: printf("command line error\n"); break;
  67. // case SEVEN_ZIP_OUT_OF_MEMORY: printf("out of memory\n"); break;
  68. // case SEVEN_ZIP_STOPPED_BY_USER: printf("stopped by user\n"); break;
  69. // default: printf("unknown problem\n");
  70. // }
  71. // }
  72. //
  73. // // restore current directory
  74. // SetCurrentDirectory(cwd);
  75. // return (code == SEVEN_ZIP_NO_ERROR || code == SEVEN_ZIP_WARNING) ? 1 : 0;
  76. //}
  77. //
  78. //// fileName is an absolute path, e.g. C:\test\a.fmu
  79. //// or relative to the current dir, e.g. ..\test\a.fmu
  80. //// Does not check for existence of the file
  81. //static char* getFmuPath(const char* fileName){
  82. // char pathName[MAX_PATH];
  83. // int n = GetFullPathName(fileName, MAX_PATH, pathName, NULL);
  84. // return n ? strdup(pathName) : NULL;
  85. //}
  86. //
  87. //static char* getTmpPath() {
  88. // char tmpPath[BUFSIZE];
  89. // if(! GetTempPath(BUFSIZE, tmpPath)) {
  90. // printf ("error: Could not find temporary disk space\n");
  91. // return NULL;
  92. // }
  93. // strcat(tmpPath, "fmu\\");
  94. // return strdup(tmpPath);
  95. //}
  96. //
  97. //char *getTempResourcesLocation() {
  98. // char *tempPath = getTmpPath();
  99. // char *resourcesLocation = (char *)calloc(sizeof(char), 9 + strlen(RESOURCES_DIR) + strlen(tempPath));
  100. // strcpy(resourcesLocation, "file:///");
  101. // strcat(resourcesLocation, tempPath);
  102. // strcat(resourcesLocation, RESOURCES_DIR);
  103. // free(tempPath);
  104. // return resourcesLocation;
  105. //}
  106. static void *getAdr(int *success, void *dllHandle, const char *functionName, const char* preamble) {
  107. int length = strlen(preamble) + strlen(functionName) + 1;
  108. char* new_name = malloc(length); // allocate memory
  109. strcpy(new_name, preamble); // copy first string
  110. strcat(new_name, functionName);
  111. void* fp = dlsym(dllHandle, new_name);
  112. if (!fp) {
  113. printf("warning: Function %s not found in dll\n", new_name);
  114. *success = 0;
  115. }
  116. free(new_name);
  117. return fp;
  118. }
  119. // Load the given dll and set function pointers in fmu
  120. // Return 0 to indicate failure
  121. int loadDll(const char* dllPath, FMU *fmu, const char* preamble) {
  122. int x = 1, s = 1;
  123. //HMODULE h = LoadLibrary(dllPath);
  124. void *h = dlopen(dllPath, RTLD_LAZY);
  125. printf("%s", dlerror());
  126. if (!h) {
  127. printf("error: Could not load %s\n", dllPath);
  128. return 0; // failure
  129. }
  130. fmu->dllHandle = h;
  131. fmu->getTypesPlatform = (fmi2GetTypesPlatformTYPE *) getAdr(&s, h, "fmi2GetTypesPlatform", preamble);
  132. fmu->getVersion = (fmi2GetVersionTYPE *) getAdr(&s, h, "fmi2GetVersion", preamble);
  133. fmu->setDebugLogging = (fmi2SetDebugLoggingTYPE *) getAdr(&s, h, "fmi2SetDebugLogging",preamble);
  134. fmu->instantiate = (fmi2InstantiateTYPE *) getAdr(&s, h, "fmi2Instantiate", preamble);
  135. fmu->freeInstance = (fmi2FreeInstanceTYPE *) getAdr(&s, h, "fmi2FreeInstance", preamble);
  136. fmu->setupExperiment = (fmi2SetupExperimentTYPE *) getAdr(&s, h, "fmi2SetupExperiment", preamble);
  137. fmu->enterInitializationMode = (fmi2EnterInitializationModeTYPE *) getAdr(&s, h, "fmi2EnterInitializationMode", preamble);
  138. fmu->exitInitializationMode = (fmi2ExitInitializationModeTYPE *) getAdr(&s, h, "fmi2ExitInitializationMode", preamble);
  139. fmu->terminate = (fmi2TerminateTYPE *) getAdr(&s, h, "fmi2Terminate", preamble);
  140. fmu->reset = (fmi2ResetTYPE *) getAdr(&s, h, "fmi2Reset", preamble);
  141. fmu->getReal = (fmi2GetRealTYPE *) getAdr(&s, h, "fmi2GetReal", preamble);
  142. fmu->getInteger = (fmi2GetIntegerTYPE *) getAdr(&s, h, "fmi2GetInteger", preamble);
  143. fmu->getBoolean = (fmi2GetBooleanTYPE *) getAdr(&s, h, "fmi2GetBoolean", preamble);
  144. fmu->getString = (fmi2GetStringTYPE *) getAdr(&s, h, "fmi2GetString", preamble);
  145. fmu->setReal = (fmi2SetRealTYPE *) getAdr(&s, h, "fmi2SetReal", preamble);
  146. fmu->setInteger = (fmi2SetIntegerTYPE *) getAdr(&s, h, "fmi2SetInteger", preamble);
  147. fmu->setBoolean = (fmi2SetBooleanTYPE *) getAdr(&s, h, "fmi2SetBoolean", preamble);
  148. fmu->setString = (fmi2SetStringTYPE *) getAdr(&s, h, "fmi2SetString", preamble);
  149. fmu->getFMUstate = (fmi2GetFMUstateTYPE *) getAdr(&s, h, "fmi2GetFMUstate", preamble);
  150. fmu->setFMUstate = (fmi2SetFMUstateTYPE *) getAdr(&s, h, "fmi2SetFMUstate", preamble);
  151. fmu->freeFMUstate = (fmi2FreeFMUstateTYPE *) getAdr(&s, h, "fmi2FreeFMUstate", preamble);
  152. fmu->serializedFMUstateSize = (fmi2SerializedFMUstateSizeTYPE *) getAdr(&s, h, "fmi2SerializedFMUstateSize", preamble);
  153. fmu->serializeFMUstate = (fmi2SerializeFMUstateTYPE *) getAdr(&s, h, "fmi2SerializeFMUstate", preamble);
  154. fmu->deSerializeFMUstate = (fmi2DeSerializeFMUstateTYPE *) getAdr(&s, h, "fmi2DeSerializeFMUstate", preamble);
  155. fmu->getDirectionalDerivative = (fmi2GetDirectionalDerivativeTYPE *) getAdr(&s, h, "fmi2GetDirectionalDerivative", preamble);
  156. #ifdef FMI_COSIMULATION
  157. fmu->setRealInputDerivatives = (fmi2SetRealInputDerivativesTYPE *) getAdr(&s, h, "fmi2SetRealInputDerivatives", preamble);
  158. fmu->getRealOutputDerivatives = (fmi2GetRealOutputDerivativesTYPE *) getAdr(&s, h, "fmi2GetRealOutputDerivatives", preamble);
  159. fmu->doStep = (fmi2DoStepTYPE *) getAdr(&s, h, "fmi2DoStep", preamble);
  160. fmu->cancelStep = (fmi2CancelStepTYPE *) getAdr(&s, h, "fmi2CancelStep", preamble);
  161. fmu->getStatus = (fmi2GetStatusTYPE *) getAdr(&s, h, "fmi2GetStatus", preamble);
  162. fmu->getRealStatus = (fmi2GetRealStatusTYPE *) getAdr(&s, h, "fmi2GetRealStatus", preamble);
  163. fmu->getIntegerStatus = (fmi2GetIntegerStatusTYPE *) getAdr(&s, h, "fmi2GetIntegerStatus", preamble);
  164. fmu->getBooleanStatus = (fmi2GetBooleanStatusTYPE *) getAdr(&s, h, "fmi2GetBooleanStatus", preamble);
  165. fmu->getStringStatus = (fmi2GetStringStatusTYPE *) getAdr(&s, h, "fmi2GetStringStatus", preamble);
  166. #else // FMI2 for Model Exchange
  167. fmu->enterEventMode = (fmi2EnterEventModeTYPE *) getAdr(&s, h, "fmi2EnterEventMode", preamble);
  168. fmu->newDiscreteStates = (fmi2NewDiscreteStatesTYPE *) getAdr(&s, h, "fmi2NewDiscreteStates", preamble);
  169. fmu->enterContinuousTimeMode = (fmi2EnterContinuousTimeModeTYPE *) getAdr(&s, h, "fmi2EnterContinuousTimeMode", preamble);
  170. fmu->completedIntegratorStep = (fmi2CompletedIntegratorStepTYPE *) getAdr(&s, h, "fmi2CompletedIntegratorStep", preamble);
  171. fmu->setTime = (fmi2SetTimeTYPE *) getAdr(&s, h, "fmi2SetTime", preamble);
  172. fmu->setContinuousStates = (fmi2SetContinuousStatesTYPE *) getAdr(&s, h, "fmi2SetContinuousStates", preamble);
  173. fmu->getDerivatives = (fmi2GetDerivativesTYPE *) getAdr(&s, h, "fmi2GetDerivatives", preamble);
  174. fmu->getEventIndicators = (fmi2GetEventIndicatorsTYPE *) getAdr(&s, h, "fmi2GetEventIndicators", preamble);
  175. fmu->getContinuousStates = (fmi2GetContinuousStatesTYPE *) getAdr(&s, h, "fmi2GetContinuousStates", preamble);
  176. fmu->getNominalsOfContinuousStates = (fmi2GetNominalsOfContinuousStatesTYPE *) getAdr(&s, h, "fmi2GetNominalsOfContinuousStates", preamble);
  177. #endif
  178. if (fmu->getVersion == NULL && fmu->instantiate == NULL) {
  179. printf("warning: Functions from FMI 2.0 could not be found in %s\n", dllPath);
  180. printf("warning: Simulator will look for FMI 2.0 RC1 functions names...\n");
  181. fmu->getTypesPlatform = (fmi2GetTypesPlatformTYPE *) getAdr(&s, h, "fmiGetTypesPlatform", preamble);
  182. fmu->getVersion = (fmi2GetVersionTYPE *) getAdr(&s, h, "fmiGetVersion", preamble);
  183. fmu->setDebugLogging = (fmi2SetDebugLoggingTYPE *) getAdr(&s, h, "fmiSetDebugLogging", preamble);
  184. fmu->instantiate = (fmi2InstantiateTYPE *) getAdr(&s, h, "fmiInstantiate", preamble);
  185. fmu->freeInstance = (fmi2FreeInstanceTYPE *) getAdr(&s, h, "fmiFreeInstance", preamble);
  186. fmu->setupExperiment = (fmi2SetupExperimentTYPE *) getAdr(&s, h, "fmiSetupExperiment", preamble);
  187. fmu->enterInitializationMode = (fmi2EnterInitializationModeTYPE *) getAdr(&s, h, "fmiEnterInitializationMode", preamble);
  188. fmu->exitInitializationMode = (fmi2ExitInitializationModeTYPE *) getAdr(&s, h, "fmiExitInitializationMode", preamble);
  189. fmu->terminate = (fmi2TerminateTYPE *) getAdr(&s, h, "fmiTerminate", preamble);
  190. fmu->reset = (fmi2ResetTYPE *) getAdr(&s, h, "fmiReset", preamble);
  191. fmu->getReal = (fmi2GetRealTYPE *) getAdr(&s, h, "fmiGetReal", preamble);
  192. fmu->getInteger = (fmi2GetIntegerTYPE *) getAdr(&s, h, "fmiGetInteger", preamble);
  193. fmu->getBoolean = (fmi2GetBooleanTYPE *) getAdr(&s, h, "fmiGetBoolean", preamble);
  194. fmu->getString = (fmi2GetStringTYPE *) getAdr(&s, h, "fmiGetString", preamble);
  195. fmu->setReal = (fmi2SetRealTYPE *) getAdr(&s, h, "fmiSetReal", preamble);
  196. fmu->setInteger = (fmi2SetIntegerTYPE *) getAdr(&s, h, "fmiSetInteger", preamble);
  197. fmu->setBoolean = (fmi2SetBooleanTYPE *) getAdr(&s, h, "fmiSetBoolean", preamble);
  198. fmu->setString = (fmi2SetStringTYPE *) getAdr(&s, h, "fmiSetString", preamble);
  199. fmu->getFMUstate = (fmi2GetFMUstateTYPE *) getAdr(&s, h, "fmiGetFMUstate", preamble);
  200. fmu->setFMUstate = (fmi2SetFMUstateTYPE *) getAdr(&s, h, "fmiSetFMUstate", preamble);
  201. fmu->freeFMUstate = (fmi2FreeFMUstateTYPE *) getAdr(&s, h, "fmiFreeFMUstate", preamble);
  202. fmu->serializedFMUstateSize = (fmi2SerializedFMUstateSizeTYPE *) getAdr(&s, h, "fmiSerializedFMUstateSize", preamble);
  203. fmu->serializeFMUstate = (fmi2SerializeFMUstateTYPE *) getAdr(&s, h, "fmiSerializeFMUstate", preamble);
  204. fmu->deSerializeFMUstate = (fmi2DeSerializeFMUstateTYPE *) getAdr(&s, h, "fmiDeSerializeFMUstate", preamble);
  205. fmu->getDirectionalDerivative = (fmi2GetDirectionalDerivativeTYPE *) getAdr(&s, h, "fmiGetDirectionalDerivative", preamble);
  206. #ifdef FMI_COSIMULATION
  207. fmu->setRealInputDerivatives = (fmi2SetRealInputDerivativesTYPE *) getAdr(&s, h, "fmiSetRealInputDerivatives", preamble);
  208. fmu->getRealOutputDerivatives = (fmi2GetRealOutputDerivativesTYPE *) getAdr(&s, h, "fmiGetRealOutputDerivatives", preamble);
  209. fmu->doStep = (fmi2DoStepTYPE *) getAdr(&s, h, "fmiDoStep", preamble);
  210. fmu->cancelStep = (fmi2CancelStepTYPE *) getAdr(&s, h, "fmiCancelStep", preamble);
  211. fmu->getStatus = (fmi2GetStatusTYPE *) getAdr(&s, h, "fmiGetStatus", preamble);
  212. fmu->getRealStatus = (fmi2GetRealStatusTYPE *) getAdr(&s, h, "fmiGetRealStatus", preamble);
  213. fmu->getIntegerStatus = (fmi2GetIntegerStatusTYPE *) getAdr(&s, h, "fmiGetIntegerStatus", preamble);
  214. fmu->getBooleanStatus = (fmi2GetBooleanStatusTYPE *) getAdr(&s, h, "fmiGetBooleanStatus", preamble);
  215. fmu->getStringStatus = (fmi2GetStringStatusTYPE *) getAdr(&s, h, "fmiGetStringStatus", preamble);
  216. #else // FMI2 for Model Exchange
  217. fmu->enterEventMode = (fmi2EnterEventModeTYPE *) getAdr(&s, h, "fmiEnterEventMode", preamble);
  218. fmu->newDiscreteStates = (fmi2NewDiscreteStatesTYPE *) getAdr(&s, h, "fmiNewDiscreteStates", preamble);
  219. fmu->enterContinuousTimeMode = (fmi2EnterContinuousTimeModeTYPE *) getAdr(&s, h, "fmiEnterContinuousTimeMode", preamble);
  220. fmu->completedIntegratorStep = (fmi2CompletedIntegratorStepTYPE *) getAdr(&s, h, "fmiCompletedIntegratorStep", preamble);
  221. fmu->setTime = (fmi2SetTimeTYPE *) getAdr(&s, h, "fmiSetTime", preamble);
  222. fmu->setContinuousStates = (fmi2SetContinuousStatesTYPE *) getAdr(&s, h, "fmiSetContinuousStates", preamble);
  223. fmu->getDerivatives = (fmi2GetDerivativesTYPE *) getAdr(&s, h, "fmiGetDerivatives", preamble);
  224. fmu->getEventIndicators = (fmi2GetEventIndicatorsTYPE *) getAdr(&s, h, "fmiGetEventIndicators", preamble);
  225. fmu->getContinuousStates = (fmi2GetContinuousStatesTYPE *) getAdr(&s, h, "fmiGetContinuousStates", preamble);
  226. fmu->getNominalsOfContinuousStates = (fmi2GetNominalsOfContinuousStatesTYPE *) getAdr(&s, h, "fmiGetNominalsOfContinuousStates", preamble);
  227. #endif
  228. }
  229. return s;
  230. }
  231. //static void printModelDescription(ModelDescription* md){
  232. // Element* e = (Element*)md;
  233. // int i;
  234. // int n; // number of attributes
  235. // const char **attributes = getAttributesAsArray(e, &n);
  236. // Component *component;
  237. //
  238. // if (!attributes) {
  239. // printf("ModelDescription printing aborted.");
  240. // return;
  241. // }
  242. // printf("%s\n", getElementTypeName(e));
  243. // for (i = 0; i < n; i += 2) {
  244. // printf(" %s=%s\n", attributes[i], attributes[i+1]);
  245. // }
  246. // free((void *)attributes);
  247. //
  248. //#ifdef FMI_COSIMULATION
  249. // component = getCoSimulation(md);
  250. // if (!component) {
  251. // printf("error: No CoSimulation element found in model description. This FMU is not for Co-Simulation.\n");
  252. // exit(EXIT_FAILURE);
  253. // }
  254. //#else // FMI_MODEL_EXCHANGE
  255. // component = getModelExchange(md);
  256. // if (!component) {
  257. // printf("error: No ModelExchange element found in model description. This FMU is not for Model Exchange.\n");
  258. // exit(EXIT_FAILURE);
  259. // }
  260. //#endif
  261. // printf("%s\n", getElementTypeName((Element *)component));
  262. // attributes = getAttributesAsArray((Element *)component, &n);
  263. // if (!attributes) {
  264. // printf("ModelDescription printing aborted.");
  265. // return;
  266. // }
  267. // for (i = 0; i < n; i += 2) {
  268. // printf(" %s=%s\n", attributes[i], attributes[i+1]);
  269. // }
  270. //
  271. // free((void *)attributes);
  272. //}
  273. //
  274. //void loadFMU(const char* fmuFileName) {
  275. // char* fmuPath;
  276. // char* tmpPath;
  277. // char* xmlPath;
  278. // char* dllPath;
  279. // const char *modelId;
  280. //
  281. // // get absolute path to FMU, NULL if not found
  282. // fmuPath = getFmuPath(fmuFileName);
  283. // if (!fmuPath) exit(EXIT_FAILURE);
  284. //
  285. // // unzip the FMU to the tmpPath directory
  286. // tmpPath = getTmpPath();
  287. // if (!unzip(fmuPath, tmpPath)) exit(EXIT_FAILURE);
  288. //
  289. // // parse tmpPath\modelDescription.xml
  290. // xmlPath = calloc(sizeof(char), strlen(tmpPath) + strlen(XML_FILE) + 1);
  291. // sprintf(xmlPath, "%s%s", tmpPath, XML_FILE);
  292. // fmu.modelDescription = parse(xmlPath);
  293. // free(xmlPath);
  294. // if (!fmu.modelDescription) exit(EXIT_FAILURE);
  295. // printModelDescription(fmu.modelDescription);
  296. //#ifdef FMI_COSIMULATION
  297. // modelId = getAttributeValue((Element *)getCoSimulation(fmu.modelDescription), att_modelIdentifier);
  298. //#else // FMI_MODEL_EXCHANGE
  299. // modelId = getAttributeValue((Element *)getModelExchange(fmu.modelDescription), att_modelIdentifier);
  300. //#endif
  301. // // load the FMU dll
  302. // dllPath = calloc(sizeof(char), strlen(tmpPath) + strlen(DLL_DIR)
  303. // + strlen(modelId) + strlen(".dll") + 1);
  304. // sprintf(dllPath, "%s%s%s.dll", tmpPath, DLL_DIR, modelId);
  305. // if (!loadDll(dllPath, &fmu)) {
  306. // exit(EXIT_FAILURE);
  307. // }
  308. // free(dllPath);
  309. // free(fmuPath);
  310. // free(tmpPath);
  311. //}
  312. //
  313. //void deleteUnzippedFiles() {
  314. // const char *fmuTempPath = getTmpPath();
  315. // char *cmd = (char *)calloc(15 + strlen(fmuTempPath), sizeof(char));
  316. // sprintf(cmd, "rmdir /S /Q %s", fmuTempPath);
  317. // system(cmd);
  318. // free(cmd);
  319. //}
  320. //
  321. //static void doubleToCommaString(char* buffer, double r){
  322. // char* comma;
  323. // sprintf(buffer, "%.16g", r);
  324. // comma = strchr(buffer, '.');
  325. // if (comma) *comma = ',';
  326. //}
  327. //
  328. //// output time and all variables in CSV format
  329. //// if separator is ',', columns are separated by ',' and '.' is used for floating-point numbers.
  330. //// otherwise, the given separator (e.g. ';' or '\t') is to separate columns, and ',' is used
  331. //// as decimal dot in floating-point numbers.
  332. //void outputRow(FMU *fmu, fmi2Component c, double time, FILE* file, char separator, fmi2Boolean header) {
  333. // int k;
  334. // fmi2Real r;
  335. // fmi2Integer i;
  336. // fmi2Boolean b;
  337. // fmi2String s;
  338. // fmi2ValueReference vr;
  339. // int n = getScalarVariableSize(fmu->modelDescription);
  340. // char buffer[32];
  341. //
  342. // // print first column
  343. // if (header) {
  344. // fprintf(file, "time");
  345. // } else {
  346. // if (separator==',')
  347. // fprintf(file, "%.16g", time);
  348. // else {
  349. // // separator is e.g. ';' or '\t'
  350. // doubleToCommaString(buffer, time);
  351. // fprintf(file, "%s", buffer);
  352. // }
  353. // }
  354. //
  355. // // print all other columns
  356. // for (k = 0; k < n; k++) {
  357. // ScalarVariable *sv = getScalarVariable(fmu->modelDescription, k);
  358. // if (header) {
  359. // // output names only
  360. // if (separator == ',') {
  361. // // treat array element, e.g. print a[1, 2] as a[1.2]
  362. // const char *s = getAttributeValue((Element *)sv, att_name);
  363. // fprintf(file, "%c", separator);
  364. // while (*s) {
  365. // if (*s != ' ') {
  366. // fprintf(file, "%c", *s == ',' ? '.' : *s);
  367. // }
  368. // s++;
  369. // }
  370. // } else {
  371. // fprintf(file, "%c%s", separator, getAttributeValue((Element *)sv, att_name));
  372. // }
  373. // } else {
  374. // // output values
  375. // vr = getValueReference(sv);
  376. // switch (getElementType(getTypeSpec(sv))) {
  377. // case elm_Real:
  378. // fmu->getReal(c, &vr, 1, &r);
  379. // if (separator == ',') {
  380. // fprintf(file, ",%.16g", r);
  381. // } else {
  382. // // separator is e.g. ';' or '\t'
  383. // doubleToCommaString(buffer, r);
  384. // fprintf(file, "%c%s", separator, buffer);
  385. // }
  386. // break;
  387. // case elm_Integer:
  388. // case elm_Enumeration:
  389. // fmu->getInteger(c, &vr, 1, &i);
  390. // fprintf(file, "%c%d", separator, i);
  391. // break;
  392. // case elm_Boolean:
  393. // fmu->getBoolean(c, &vr, 1, &b);
  394. // fprintf(file, "%c%d", separator, b);
  395. // break;
  396. // case elm_String:
  397. // fmu->getString(c, &vr, 1, &s);
  398. // fprintf(file, "%c%s", separator, s);
  399. // break;
  400. // default:
  401. // fprintf(file, "%cNoValueForType=%d", separator, getElementType(getTypeSpec(sv)));
  402. // }
  403. // }
  404. // } // for
  405. //
  406. // // terminate this row
  407. // fprintf(file, "\n");
  408. //}
  409. //
  410. static const char* fmi2StatusToString(fmi2Status status){
  411. switch (status){
  412. case fmi2OK: return "ok";
  413. case fmi2Warning: return "warning";
  414. case fmi2Discard: return "discard";
  415. case fmi2Error: return "error";
  416. case fmi2Fatal: return "fatal";
  417. #ifdef FMI_COSIMULATION
  418. case fmi2Pending: return "fmi2Pending";
  419. #endif
  420. default: return "?";
  421. }
  422. }
  423. // search a fmu for the given variable, matching the type specified.
  424. // return NULL if not found
  425. //static ScalarVariable* getSV(FMU* fmu, char type, fmi2ValueReference vr) {
  426. // return NULL;
  427. // int i;
  428. // int n = getScalarVariableSize(fmu->modelDescription);
  429. // Elm tp;
  430. //
  431. // switch (type) {
  432. // case 'r': tp = elm_Real; break;
  433. // case 'i': tp = elm_Integer; break;
  434. // case 'b': tp = elm_Boolean; break;
  435. // case 's': tp = elm_String; break;
  436. // default : tp = elm_BAD_DEFINED;
  437. // }
  438. // for (i = 0; i < n; i++) {
  439. // ScalarVariable* sv = getScalarVariable(fmu->modelDescription ,i);
  440. // if (vr == getValueReference(sv) && tp == getElementType(getTypeSpec(sv))) {
  441. // return sv;
  442. // }
  443. // }
  444. // return NULL;
  445. //}
  446. // replace e.g. #r1365# by variable name and ## by # in message
  447. // copies the result to buffer
  448. static void replaceRefsInMessage(const char* msg, char* buffer, int nBuffer, FMU* fmu){
  449. int i = 0; // position in msg
  450. int k = 0; // position in buffer
  451. int n;
  452. char c = msg[i];
  453. while (c != '\0' && k < nBuffer) {
  454. if (c != '#') {
  455. buffer[k++] = c;
  456. i++;
  457. c = msg[i];
  458. } else {
  459. char* end = strchr(msg + i + 1, '#');
  460. if (!end) {
  461. printf("unmatched '#' in '%s'\n", msg);
  462. buffer[k++] = '#';
  463. break;
  464. }
  465. n = end - (msg + i);
  466. if (n == 1) {
  467. // ## detected, output #
  468. buffer[k++] = '#';
  469. i += 2;
  470. c = msg[i];
  471. } else {
  472. char type = msg[i + 1]; // one of ribs
  473. fmi2ValueReference vr;
  474. int nvr = sscanf(msg + i + 2, "%u", &vr);
  475. if (nvr == 1) {
  476. // vr of type detected, e.g. #r12#
  477. //ScalarVariable* sv = getSV(fmu, type, vr);
  478. //const char* name = sv ? getAttributeValue((Element *)sv, att_name) : "?";
  479. //sprintf(buffer + k, "%s", name);
  480. //k += strlen(name);
  481. //i += (n+1);
  482. //c = msg[i];
  483. } else {
  484. // could not parse the number
  485. printf("illegal value reference at position %d in '%s'\n", i + 2, msg);
  486. buffer[k++] = '#';
  487. break;
  488. }
  489. }
  490. }
  491. } // while
  492. buffer[k] = '\0';
  493. }
  494. #define MAX_MSG_SIZE 1000
  495. void fmuLogger(void *componentEnvironment, fmi2String instanceName, fmi2Status status,
  496. fmi2String category, fmi2String message, ...) {
  497. char msg[MAX_MSG_SIZE];
  498. char* copy;
  499. va_list argp;
  500. // replace C format strings
  501. va_start(argp, message);
  502. vsprintf(msg, message, argp);
  503. va_end(argp);
  504. // replace e.g. ## and #r12#
  505. copy = strdup(msg);
  506. // replaceRefsInMessage(copy, msg, MAX_MSG_SIZE, NULL);
  507. free(copy);
  508. // print the final message
  509. if (!instanceName) instanceName = "?";
  510. if (!category) category = "?";
  511. printf("%s %s (%s): %s\n", fmi2StatusToString(status), instanceName, category, msg);
  512. }
  513. int error(const char* message){
  514. printf("%s\n", message);
  515. return 0;
  516. }
  517. //
  518. //void parseArguments(int argc, char *argv[], const char **fmuFileName, double *tEnd, double *h,
  519. // int *loggingOn, char *csv_separator, int *nCategories, char **logCategories[]) {
  520. // // parse command line arguments
  521. // if (argc > 1) {
  522. // *fmuFileName = argv[1];
  523. // } else {
  524. // printf("error: no fmu file\n");
  525. // printHelp(argv[0]);
  526. // exit(EXIT_FAILURE);
  527. // }
  528. // if (argc > 2) {
  529. // if (sscanf(argv[2],"%lf", tEnd) != 1) {
  530. // printf("error: The given end time (%s) is not a number\n", argv[2]);
  531. // exit(EXIT_FAILURE);
  532. // }
  533. // }
  534. // if (argc > 3) {
  535. // if (sscanf(argv[3],"%lf", h) != 1) {
  536. // printf("error: The given stepsize (%s) is not a number\n", argv[3]);
  537. // exit(EXIT_FAILURE);
  538. // }
  539. // }
  540. // if (argc > 4) {
  541. // if (sscanf(argv[4],"%d", loggingOn) != 1 || *loggingOn < 0 || *loggingOn > 1) {
  542. // printf("error: The given logging flag (%s) is not boolean\n", argv[4]);
  543. // exit(EXIT_FAILURE);
  544. // }
  545. // }
  546. // if (argc > 5) {
  547. // if (strlen(argv[5]) != 1) {
  548. // printf("error: The given CSV separator char (%s) is not valid\n", argv[5]);
  549. // exit(EXIT_FAILURE);
  550. // }
  551. // switch (argv[5][0]) {
  552. // case 'c': *csv_separator = ','; break; // comma
  553. // case 's': *csv_separator = ';'; break; // semicolon
  554. // default: *csv_separator = argv[5][0]; break; // any other char
  555. // }
  556. // }
  557. // if (argc > 6) {
  558. // int i;
  559. // *nCategories = argc - 6;
  560. // *logCategories = (char **)calloc(sizeof(char *), *nCategories);
  561. // for (i = 0; i < *nCategories; i++) {
  562. // (*logCategories)[i] = argv[i + 6];
  563. // }
  564. // }
  565. //}
  566. //
  567. //void printHelp(const char *fmusim) {
  568. // printf("command syntax: %s <model.fmu> <tEnd> <h> <loggingOn> <csv separator>\n", fmusim);
  569. // printf(" <model.fmu> .... path to FMU, relative to current dir or absolute, required\n");
  570. // printf(" <tEnd> ......... end time of simulation, optional, defaults to 1.0 sec\n");
  571. // printf(" <h> ............ step size of simulation, optional, defaults to 0.1 sec\n");
  572. // printf(" <loggingOn> .... 1 to activate logging, optional, defaults to 0\n");
  573. // printf(" <csv separator>. separator in csv file, optional, c for ',', s for';', defaults to c\n");
  574. // printf(" <logCategories>. list of active categories, optional, see modelDescription.xml for possible values\n");
  575. //}