|
@@ -0,0 +1,594 @@
|
|
|
+/* -------------------------------------------------------------------------
|
|
|
+ * sim_support.c
|
|
|
+ * Functions used by both FMU simulators fmu20sim_me and fmu20sim_cs
|
|
|
+ * to parse command-line arguments, to unzip and load an fmu,
|
|
|
+ * to write CSV file, and more.
|
|
|
+ *
|
|
|
+ * Revision history
|
|
|
+ * 07.03.2014 initial version released in FMU SDK 2.0.0
|
|
|
+ * 10.04.2014 use FMI 2.0 headers that prefix function and type names with 'fmi2'.
|
|
|
+ * When 'fmi2' functions are not found in loaded DLL, look also for
|
|
|
+ * FMI 2.0 RC1 function names.
|
|
|
+ *
|
|
|
+ * Author: Adrian Tirea
|
|
|
+ * Copyright QTronic GmbH. All rights reserved.
|
|
|
+ * -------------------------------------------------------------------------*/
|
|
|
+
|
|
|
+#include <stdio.h>
|
|
|
+#include <stdlib.h>
|
|
|
+#include <string.h>
|
|
|
+#include <assert.h>
|
|
|
+#include <stdarg.h>
|
|
|
+#include <dlfcn.h>
|
|
|
+#include "fmi2.h"
|
|
|
+#include "sim_support.h"
|
|
|
+
|
|
|
+#define FMI_COSIMULATION
|
|
|
+extern FMU fmu;
|
|
|
+
|
|
|
+
|
|
|
+//int unzip(const char *zipPath, const char *outPath) {
|
|
|
+// int code;
|
|
|
+// char cwd[BUFSIZE];
|
|
|
+// char binPath[BUFSIZE];
|
|
|
+// int n = strlen(UNZIP_CMD) + strlen(outPath) + 3 + strlen(zipPath) + 9;
|
|
|
+// char* cmd = (char*)calloc(sizeof(char), n);
|
|
|
+//
|
|
|
+// // remember current directory
|
|
|
+// if (!GetCurrentDirectory(BUFSIZE, cwd)) {
|
|
|
+// printf ("error: Could not get current directory\n");
|
|
|
+// return 0; // error
|
|
|
+// }
|
|
|
+//
|
|
|
+// // change to %FMUSDK_HOME%\bin to find 7z.dll and 7z.exe
|
|
|
+// if (!GetEnvironmentVariable("FMUSDK_HOME", binPath, BUFSIZE)) {
|
|
|
+// if (GetLastError() == ERROR_ENVVAR_NOT_FOUND) {
|
|
|
+// printf ("error: Environment variable FMUSDK_HOME not defined\n");
|
|
|
+// }
|
|
|
+// else {
|
|
|
+// printf ("error: Could not get value of FMUSDK_HOME\n");
|
|
|
+// }
|
|
|
+// return 0; // error
|
|
|
+// }
|
|
|
+// strcat(binPath, "\\bin");
|
|
|
+// if (!SetCurrentDirectory(binPath)) {
|
|
|
+// printf ("error: could not change to directory '%s'\n", binPath);
|
|
|
+// return 0; // error
|
|
|
+// }
|
|
|
+//
|
|
|
+// // run the unzip command
|
|
|
+// // remove "> NUL" to see the unzip protocol
|
|
|
+// sprintf(cmd, "%s\"%s\" \"%s\" > NUL", UNZIP_CMD, outPath, zipPath);
|
|
|
+// // printf("cmd='%s'\n", cmd);
|
|
|
+// code = system(cmd);
|
|
|
+// free(cmd);
|
|
|
+// if (code != SEVEN_ZIP_NO_ERROR) {
|
|
|
+// printf("7z: ");
|
|
|
+// switch (code) {
|
|
|
+// case SEVEN_ZIP_WARNING: printf("warning\n"); break;
|
|
|
+// case SEVEN_ZIP_ERROR: printf("error\n"); break;
|
|
|
+// case SEVEN_ZIP_COMMAND_LINE_ERROR: printf("command line error\n"); break;
|
|
|
+// case SEVEN_ZIP_OUT_OF_MEMORY: printf("out of memory\n"); break;
|
|
|
+// case SEVEN_ZIP_STOPPED_BY_USER: printf("stopped by user\n"); break;
|
|
|
+// default: printf("unknown problem\n");
|
|
|
+// }
|
|
|
+// }
|
|
|
+//
|
|
|
+// // restore current directory
|
|
|
+// SetCurrentDirectory(cwd);
|
|
|
+// return (code == SEVEN_ZIP_NO_ERROR || code == SEVEN_ZIP_WARNING) ? 1 : 0;
|
|
|
+//}
|
|
|
+//
|
|
|
+//// fileName is an absolute path, e.g. C:\test\a.fmu
|
|
|
+//// or relative to the current dir, e.g. ..\test\a.fmu
|
|
|
+//// Does not check for existence of the file
|
|
|
+//static char* getFmuPath(const char* fileName){
|
|
|
+// char pathName[MAX_PATH];
|
|
|
+// int n = GetFullPathName(fileName, MAX_PATH, pathName, NULL);
|
|
|
+// return n ? strdup(pathName) : NULL;
|
|
|
+//}
|
|
|
+//
|
|
|
+//static char* getTmpPath() {
|
|
|
+// char tmpPath[BUFSIZE];
|
|
|
+// if(! GetTempPath(BUFSIZE, tmpPath)) {
|
|
|
+// printf ("error: Could not find temporary disk space\n");
|
|
|
+// return NULL;
|
|
|
+// }
|
|
|
+// strcat(tmpPath, "fmu\\");
|
|
|
+// return strdup(tmpPath);
|
|
|
+//}
|
|
|
+//
|
|
|
+//char *getTempResourcesLocation() {
|
|
|
+// char *tempPath = getTmpPath();
|
|
|
+// char *resourcesLocation = (char *)calloc(sizeof(char), 9 + strlen(RESOURCES_DIR) + strlen(tempPath));
|
|
|
+// strcpy(resourcesLocation, "file:///");
|
|
|
+// strcat(resourcesLocation, tempPath);
|
|
|
+// strcat(resourcesLocation, RESOURCES_DIR);
|
|
|
+// free(tempPath);
|
|
|
+// return resourcesLocation;
|
|
|
+//}
|
|
|
+
|
|
|
+static void *getAdr(int *success, void *dllHandle, const char *functionName, const char* preamble) {
|
|
|
+
|
|
|
+ int length = strlen(preamble) + strlen(functionName) + 1;
|
|
|
+ char* new_name = malloc(length); // allocate memory
|
|
|
+ strcpy(new_name, preamble); // copy first string
|
|
|
+ strcat(new_name, functionName);
|
|
|
+ void* fp = dlsym(dllHandle, new_name);
|
|
|
+ if (!fp) {
|
|
|
+ printf("warning: Function %s not found in dll\n", new_name);
|
|
|
+ *success = 0;
|
|
|
+ }
|
|
|
+ free(new_name);
|
|
|
+ return fp;
|
|
|
+}
|
|
|
+
|
|
|
+// Load the given dll and set function pointers in fmu
|
|
|
+// Return 0 to indicate failure
|
|
|
+int loadDll(const char* dllPath, FMU *fmu, const char* preamble) {
|
|
|
+ int x = 1, s = 1;
|
|
|
+ //HMODULE h = LoadLibrary(dllPath);
|
|
|
+ void *h = dlopen(dllPath, RTLD_LAZY);
|
|
|
+ printf("%s", dlerror());
|
|
|
+ if (!h) {
|
|
|
+ printf("error: Could not load %s\n", dllPath);
|
|
|
+ return 0; // failure
|
|
|
+ }
|
|
|
+ fmu->dllHandle = h;
|
|
|
+ fmu->getTypesPlatform = (fmi2GetTypesPlatformTYPE *) getAdr(&s, h, "fmi2GetTypesPlatform", preamble);
|
|
|
+ fmu->getVersion = (fmi2GetVersionTYPE *) getAdr(&s, h, "fmi2GetVersion", preamble);
|
|
|
+ fmu->setDebugLogging = (fmi2SetDebugLoggingTYPE *) getAdr(&s, h, "fmi2SetDebugLogging",preamble);
|
|
|
+ fmu->instantiate = (fmi2InstantiateTYPE *) getAdr(&s, h, "fmi2Instantiate", preamble);
|
|
|
+ fmu->freeInstance = (fmi2FreeInstanceTYPE *) getAdr(&s, h, "fmi2FreeInstance", preamble);
|
|
|
+ fmu->setupExperiment = (fmi2SetupExperimentTYPE *) getAdr(&s, h, "fmi2SetupExperiment", preamble);
|
|
|
+ fmu->enterInitializationMode = (fmi2EnterInitializationModeTYPE *) getAdr(&s, h, "fmi2EnterInitializationMode", preamble);
|
|
|
+ fmu->exitInitializationMode = (fmi2ExitInitializationModeTYPE *) getAdr(&s, h, "fmi2ExitInitializationMode", preamble);
|
|
|
+ fmu->terminate = (fmi2TerminateTYPE *) getAdr(&s, h, "fmi2Terminate", preamble);
|
|
|
+ fmu->reset = (fmi2ResetTYPE *) getAdr(&s, h, "fmi2Reset", preamble);
|
|
|
+ fmu->getReal = (fmi2GetRealTYPE *) getAdr(&s, h, "fmi2GetReal", preamble);
|
|
|
+ fmu->getInteger = (fmi2GetIntegerTYPE *) getAdr(&s, h, "fmi2GetInteger", preamble);
|
|
|
+ fmu->getBoolean = (fmi2GetBooleanTYPE *) getAdr(&s, h, "fmi2GetBoolean", preamble);
|
|
|
+ fmu->getString = (fmi2GetStringTYPE *) getAdr(&s, h, "fmi2GetString", preamble);
|
|
|
+ fmu->setReal = (fmi2SetRealTYPE *) getAdr(&s, h, "fmi2SetReal", preamble);
|
|
|
+ fmu->setInteger = (fmi2SetIntegerTYPE *) getAdr(&s, h, "fmi2SetInteger", preamble);
|
|
|
+ fmu->setBoolean = (fmi2SetBooleanTYPE *) getAdr(&s, h, "fmi2SetBoolean", preamble);
|
|
|
+ fmu->setString = (fmi2SetStringTYPE *) getAdr(&s, h, "fmi2SetString", preamble);
|
|
|
+ fmu->getFMUstate = (fmi2GetFMUstateTYPE *) getAdr(&s, h, "fmi2GetFMUstate", preamble);
|
|
|
+ fmu->setFMUstate = (fmi2SetFMUstateTYPE *) getAdr(&s, h, "fmi2SetFMUstate", preamble);
|
|
|
+ fmu->freeFMUstate = (fmi2FreeFMUstateTYPE *) getAdr(&s, h, "fmi2FreeFMUstate", preamble);
|
|
|
+ fmu->serializedFMUstateSize = (fmi2SerializedFMUstateSizeTYPE *) getAdr(&s, h, "fmi2SerializedFMUstateSize", preamble);
|
|
|
+ fmu->serializeFMUstate = (fmi2SerializeFMUstateTYPE *) getAdr(&s, h, "fmi2SerializeFMUstate", preamble);
|
|
|
+ fmu->deSerializeFMUstate = (fmi2DeSerializeFMUstateTYPE *) getAdr(&s, h, "fmi2DeSerializeFMUstate", preamble);
|
|
|
+ fmu->getDirectionalDerivative = (fmi2GetDirectionalDerivativeTYPE *) getAdr(&s, h, "fmi2GetDirectionalDerivative", preamble);
|
|
|
+#ifdef FMI_COSIMULATION
|
|
|
+ fmu->setRealInputDerivatives = (fmi2SetRealInputDerivativesTYPE *) getAdr(&s, h, "fmi2SetRealInputDerivatives", preamble);
|
|
|
+ fmu->getRealOutputDerivatives = (fmi2GetRealOutputDerivativesTYPE *) getAdr(&s, h, "fmi2GetRealOutputDerivatives", preamble);
|
|
|
+ fmu->doStep = (fmi2DoStepTYPE *) getAdr(&s, h, "fmi2DoStep", preamble);
|
|
|
+ fmu->cancelStep = (fmi2CancelStepTYPE *) getAdr(&s, h, "fmi2CancelStep", preamble);
|
|
|
+ fmu->getStatus = (fmi2GetStatusTYPE *) getAdr(&s, h, "fmi2GetStatus", preamble);
|
|
|
+ fmu->getRealStatus = (fmi2GetRealStatusTYPE *) getAdr(&s, h, "fmi2GetRealStatus", preamble);
|
|
|
+ fmu->getIntegerStatus = (fmi2GetIntegerStatusTYPE *) getAdr(&s, h, "fmi2GetIntegerStatus", preamble);
|
|
|
+ fmu->getBooleanStatus = (fmi2GetBooleanStatusTYPE *) getAdr(&s, h, "fmi2GetBooleanStatus", preamble);
|
|
|
+ fmu->getStringStatus = (fmi2GetStringStatusTYPE *) getAdr(&s, h, "fmi2GetStringStatus", preamble);
|
|
|
+#else // FMI2 for Model Exchange
|
|
|
+ fmu->enterEventMode = (fmi2EnterEventModeTYPE *) getAdr(&s, h, "fmi2EnterEventMode", preamble);
|
|
|
+ fmu->newDiscreteStates = (fmi2NewDiscreteStatesTYPE *) getAdr(&s, h, "fmi2NewDiscreteStates", preamble);
|
|
|
+ fmu->enterContinuousTimeMode = (fmi2EnterContinuousTimeModeTYPE *) getAdr(&s, h, "fmi2EnterContinuousTimeMode", preamble);
|
|
|
+ fmu->completedIntegratorStep = (fmi2CompletedIntegratorStepTYPE *) getAdr(&s, h, "fmi2CompletedIntegratorStep", preamble);
|
|
|
+ fmu->setTime = (fmi2SetTimeTYPE *) getAdr(&s, h, "fmi2SetTime", preamble);
|
|
|
+ fmu->setContinuousStates = (fmi2SetContinuousStatesTYPE *) getAdr(&s, h, "fmi2SetContinuousStates", preamble);
|
|
|
+ fmu->getDerivatives = (fmi2GetDerivativesTYPE *) getAdr(&s, h, "fmi2GetDerivatives", preamble);
|
|
|
+ fmu->getEventIndicators = (fmi2GetEventIndicatorsTYPE *) getAdr(&s, h, "fmi2GetEventIndicators", preamble);
|
|
|
+ fmu->getContinuousStates = (fmi2GetContinuousStatesTYPE *) getAdr(&s, h, "fmi2GetContinuousStates", preamble);
|
|
|
+ fmu->getNominalsOfContinuousStates = (fmi2GetNominalsOfContinuousStatesTYPE *) getAdr(&s, h, "fmi2GetNominalsOfContinuousStates", preamble);
|
|
|
+#endif
|
|
|
+
|
|
|
+ if (fmu->getVersion == NULL && fmu->instantiate == NULL) {
|
|
|
+ printf("warning: Functions from FMI 2.0 could not be found in %s\n", dllPath);
|
|
|
+ printf("warning: Simulator will look for FMI 2.0 RC1 functions names...\n");
|
|
|
+ fmu->getTypesPlatform = (fmi2GetTypesPlatformTYPE *) getAdr(&s, h, "fmiGetTypesPlatform", preamble);
|
|
|
+ fmu->getVersion = (fmi2GetVersionTYPE *) getAdr(&s, h, "fmiGetVersion", preamble);
|
|
|
+ fmu->setDebugLogging = (fmi2SetDebugLoggingTYPE *) getAdr(&s, h, "fmiSetDebugLogging", preamble);
|
|
|
+ fmu->instantiate = (fmi2InstantiateTYPE *) getAdr(&s, h, "fmiInstantiate", preamble);
|
|
|
+ fmu->freeInstance = (fmi2FreeInstanceTYPE *) getAdr(&s, h, "fmiFreeInstance", preamble);
|
|
|
+ fmu->setupExperiment = (fmi2SetupExperimentTYPE *) getAdr(&s, h, "fmiSetupExperiment", preamble);
|
|
|
+ fmu->enterInitializationMode = (fmi2EnterInitializationModeTYPE *) getAdr(&s, h, "fmiEnterInitializationMode", preamble);
|
|
|
+ fmu->exitInitializationMode = (fmi2ExitInitializationModeTYPE *) getAdr(&s, h, "fmiExitInitializationMode", preamble);
|
|
|
+ fmu->terminate = (fmi2TerminateTYPE *) getAdr(&s, h, "fmiTerminate", preamble);
|
|
|
+ fmu->reset = (fmi2ResetTYPE *) getAdr(&s, h, "fmiReset", preamble);
|
|
|
+ fmu->getReal = (fmi2GetRealTYPE *) getAdr(&s, h, "fmiGetReal", preamble);
|
|
|
+ fmu->getInteger = (fmi2GetIntegerTYPE *) getAdr(&s, h, "fmiGetInteger", preamble);
|
|
|
+ fmu->getBoolean = (fmi2GetBooleanTYPE *) getAdr(&s, h, "fmiGetBoolean", preamble);
|
|
|
+ fmu->getString = (fmi2GetStringTYPE *) getAdr(&s, h, "fmiGetString", preamble);
|
|
|
+ fmu->setReal = (fmi2SetRealTYPE *) getAdr(&s, h, "fmiSetReal", preamble);
|
|
|
+ fmu->setInteger = (fmi2SetIntegerTYPE *) getAdr(&s, h, "fmiSetInteger", preamble);
|
|
|
+ fmu->setBoolean = (fmi2SetBooleanTYPE *) getAdr(&s, h, "fmiSetBoolean", preamble);
|
|
|
+ fmu->setString = (fmi2SetStringTYPE *) getAdr(&s, h, "fmiSetString", preamble);
|
|
|
+ fmu->getFMUstate = (fmi2GetFMUstateTYPE *) getAdr(&s, h, "fmiGetFMUstate", preamble);
|
|
|
+ fmu->setFMUstate = (fmi2SetFMUstateTYPE *) getAdr(&s, h, "fmiSetFMUstate", preamble);
|
|
|
+ fmu->freeFMUstate = (fmi2FreeFMUstateTYPE *) getAdr(&s, h, "fmiFreeFMUstate", preamble);
|
|
|
+ fmu->serializedFMUstateSize = (fmi2SerializedFMUstateSizeTYPE *) getAdr(&s, h, "fmiSerializedFMUstateSize", preamble);
|
|
|
+ fmu->serializeFMUstate = (fmi2SerializeFMUstateTYPE *) getAdr(&s, h, "fmiSerializeFMUstate", preamble);
|
|
|
+ fmu->deSerializeFMUstate = (fmi2DeSerializeFMUstateTYPE *) getAdr(&s, h, "fmiDeSerializeFMUstate", preamble);
|
|
|
+ fmu->getDirectionalDerivative = (fmi2GetDirectionalDerivativeTYPE *) getAdr(&s, h, "fmiGetDirectionalDerivative", preamble);
|
|
|
+ #ifdef FMI_COSIMULATION
|
|
|
+ fmu->setRealInputDerivatives = (fmi2SetRealInputDerivativesTYPE *) getAdr(&s, h, "fmiSetRealInputDerivatives", preamble);
|
|
|
+ fmu->getRealOutputDerivatives = (fmi2GetRealOutputDerivativesTYPE *) getAdr(&s, h, "fmiGetRealOutputDerivatives", preamble);
|
|
|
+ fmu->doStep = (fmi2DoStepTYPE *) getAdr(&s, h, "fmiDoStep", preamble);
|
|
|
+ fmu->cancelStep = (fmi2CancelStepTYPE *) getAdr(&s, h, "fmiCancelStep", preamble);
|
|
|
+ fmu->getStatus = (fmi2GetStatusTYPE *) getAdr(&s, h, "fmiGetStatus", preamble);
|
|
|
+ fmu->getRealStatus = (fmi2GetRealStatusTYPE *) getAdr(&s, h, "fmiGetRealStatus", preamble);
|
|
|
+ fmu->getIntegerStatus = (fmi2GetIntegerStatusTYPE *) getAdr(&s, h, "fmiGetIntegerStatus", preamble);
|
|
|
+ fmu->getBooleanStatus = (fmi2GetBooleanStatusTYPE *) getAdr(&s, h, "fmiGetBooleanStatus", preamble);
|
|
|
+ fmu->getStringStatus = (fmi2GetStringStatusTYPE *) getAdr(&s, h, "fmiGetStringStatus", preamble);
|
|
|
+ #else // FMI2 for Model Exchange
|
|
|
+ fmu->enterEventMode = (fmi2EnterEventModeTYPE *) getAdr(&s, h, "fmiEnterEventMode", preamble);
|
|
|
+ fmu->newDiscreteStates = (fmi2NewDiscreteStatesTYPE *) getAdr(&s, h, "fmiNewDiscreteStates", preamble);
|
|
|
+ fmu->enterContinuousTimeMode = (fmi2EnterContinuousTimeModeTYPE *) getAdr(&s, h, "fmiEnterContinuousTimeMode", preamble);
|
|
|
+ fmu->completedIntegratorStep = (fmi2CompletedIntegratorStepTYPE *) getAdr(&s, h, "fmiCompletedIntegratorStep", preamble);
|
|
|
+ fmu->setTime = (fmi2SetTimeTYPE *) getAdr(&s, h, "fmiSetTime", preamble);
|
|
|
+ fmu->setContinuousStates = (fmi2SetContinuousStatesTYPE *) getAdr(&s, h, "fmiSetContinuousStates", preamble);
|
|
|
+ fmu->getDerivatives = (fmi2GetDerivativesTYPE *) getAdr(&s, h, "fmiGetDerivatives", preamble);
|
|
|
+ fmu->getEventIndicators = (fmi2GetEventIndicatorsTYPE *) getAdr(&s, h, "fmiGetEventIndicators", preamble);
|
|
|
+ fmu->getContinuousStates = (fmi2GetContinuousStatesTYPE *) getAdr(&s, h, "fmiGetContinuousStates", preamble);
|
|
|
+ fmu->getNominalsOfContinuousStates = (fmi2GetNominalsOfContinuousStatesTYPE *) getAdr(&s, h, "fmiGetNominalsOfContinuousStates", preamble);
|
|
|
+ #endif
|
|
|
+ }
|
|
|
+ return s;
|
|
|
+}
|
|
|
+
|
|
|
+//static void printModelDescription(ModelDescription* md){
|
|
|
+// Element* e = (Element*)md;
|
|
|
+// int i;
|
|
|
+// int n; // number of attributes
|
|
|
+// const char **attributes = getAttributesAsArray(e, &n);
|
|
|
+// Component *component;
|
|
|
+//
|
|
|
+// if (!attributes) {
|
|
|
+// printf("ModelDescription printing aborted.");
|
|
|
+// return;
|
|
|
+// }
|
|
|
+// printf("%s\n", getElementTypeName(e));
|
|
|
+// for (i = 0; i < n; i += 2) {
|
|
|
+// printf(" %s=%s\n", attributes[i], attributes[i+1]);
|
|
|
+// }
|
|
|
+// free((void *)attributes);
|
|
|
+//
|
|
|
+//#ifdef FMI_COSIMULATION
|
|
|
+// component = getCoSimulation(md);
|
|
|
+// if (!component) {
|
|
|
+// printf("error: No CoSimulation element found in model description. This FMU is not for Co-Simulation.\n");
|
|
|
+// exit(EXIT_FAILURE);
|
|
|
+// }
|
|
|
+//#else // FMI_MODEL_EXCHANGE
|
|
|
+// component = getModelExchange(md);
|
|
|
+// if (!component) {
|
|
|
+// printf("error: No ModelExchange element found in model description. This FMU is not for Model Exchange.\n");
|
|
|
+// exit(EXIT_FAILURE);
|
|
|
+// }
|
|
|
+//#endif
|
|
|
+// printf("%s\n", getElementTypeName((Element *)component));
|
|
|
+// attributes = getAttributesAsArray((Element *)component, &n);
|
|
|
+// if (!attributes) {
|
|
|
+// printf("ModelDescription printing aborted.");
|
|
|
+// return;
|
|
|
+// }
|
|
|
+// for (i = 0; i < n; i += 2) {
|
|
|
+// printf(" %s=%s\n", attributes[i], attributes[i+1]);
|
|
|
+// }
|
|
|
+//
|
|
|
+// free((void *)attributes);
|
|
|
+//}
|
|
|
+//
|
|
|
+//void loadFMU(const char* fmuFileName) {
|
|
|
+// char* fmuPath;
|
|
|
+// char* tmpPath;
|
|
|
+// char* xmlPath;
|
|
|
+// char* dllPath;
|
|
|
+// const char *modelId;
|
|
|
+//
|
|
|
+// // get absolute path to FMU, NULL if not found
|
|
|
+// fmuPath = getFmuPath(fmuFileName);
|
|
|
+// if (!fmuPath) exit(EXIT_FAILURE);
|
|
|
+//
|
|
|
+// // unzip the FMU to the tmpPath directory
|
|
|
+// tmpPath = getTmpPath();
|
|
|
+// if (!unzip(fmuPath, tmpPath)) exit(EXIT_FAILURE);
|
|
|
+//
|
|
|
+// // parse tmpPath\modelDescription.xml
|
|
|
+// xmlPath = calloc(sizeof(char), strlen(tmpPath) + strlen(XML_FILE) + 1);
|
|
|
+// sprintf(xmlPath, "%s%s", tmpPath, XML_FILE);
|
|
|
+// fmu.modelDescription = parse(xmlPath);
|
|
|
+// free(xmlPath);
|
|
|
+// if (!fmu.modelDescription) exit(EXIT_FAILURE);
|
|
|
+// printModelDescription(fmu.modelDescription);
|
|
|
+//#ifdef FMI_COSIMULATION
|
|
|
+// modelId = getAttributeValue((Element *)getCoSimulation(fmu.modelDescription), att_modelIdentifier);
|
|
|
+//#else // FMI_MODEL_EXCHANGE
|
|
|
+// modelId = getAttributeValue((Element *)getModelExchange(fmu.modelDescription), att_modelIdentifier);
|
|
|
+//#endif
|
|
|
+// // load the FMU dll
|
|
|
+// dllPath = calloc(sizeof(char), strlen(tmpPath) + strlen(DLL_DIR)
|
|
|
+// + strlen(modelId) + strlen(".dll") + 1);
|
|
|
+// sprintf(dllPath, "%s%s%s.dll", tmpPath, DLL_DIR, modelId);
|
|
|
+// if (!loadDll(dllPath, &fmu)) {
|
|
|
+// exit(EXIT_FAILURE);
|
|
|
+// }
|
|
|
+// free(dllPath);
|
|
|
+// free(fmuPath);
|
|
|
+// free(tmpPath);
|
|
|
+//}
|
|
|
+//
|
|
|
+//void deleteUnzippedFiles() {
|
|
|
+// const char *fmuTempPath = getTmpPath();
|
|
|
+// char *cmd = (char *)calloc(15 + strlen(fmuTempPath), sizeof(char));
|
|
|
+// sprintf(cmd, "rmdir /S /Q %s", fmuTempPath);
|
|
|
+// system(cmd);
|
|
|
+// free(cmd);
|
|
|
+//}
|
|
|
+//
|
|
|
+//static void doubleToCommaString(char* buffer, double r){
|
|
|
+// char* comma;
|
|
|
+// sprintf(buffer, "%.16g", r);
|
|
|
+// comma = strchr(buffer, '.');
|
|
|
+// if (comma) *comma = ',';
|
|
|
+//}
|
|
|
+//
|
|
|
+//// output time and all variables in CSV format
|
|
|
+//// if separator is ',', columns are separated by ',' and '.' is used for floating-point numbers.
|
|
|
+//// otherwise, the given separator (e.g. ';' or '\t') is to separate columns, and ',' is used
|
|
|
+//// as decimal dot in floating-point numbers.
|
|
|
+//void outputRow(FMU *fmu, fmi2Component c, double time, FILE* file, char separator, fmi2Boolean header) {
|
|
|
+// int k;
|
|
|
+// fmi2Real r;
|
|
|
+// fmi2Integer i;
|
|
|
+// fmi2Boolean b;
|
|
|
+// fmi2String s;
|
|
|
+// fmi2ValueReference vr;
|
|
|
+// int n = getScalarVariableSize(fmu->modelDescription);
|
|
|
+// char buffer[32];
|
|
|
+//
|
|
|
+// // print first column
|
|
|
+// if (header) {
|
|
|
+// fprintf(file, "time");
|
|
|
+// } else {
|
|
|
+// if (separator==',')
|
|
|
+// fprintf(file, "%.16g", time);
|
|
|
+// else {
|
|
|
+// // separator is e.g. ';' or '\t'
|
|
|
+// doubleToCommaString(buffer, time);
|
|
|
+// fprintf(file, "%s", buffer);
|
|
|
+// }
|
|
|
+// }
|
|
|
+//
|
|
|
+// // print all other columns
|
|
|
+// for (k = 0; k < n; k++) {
|
|
|
+// ScalarVariable *sv = getScalarVariable(fmu->modelDescription, k);
|
|
|
+// if (header) {
|
|
|
+// // output names only
|
|
|
+// if (separator == ',') {
|
|
|
+// // treat array element, e.g. print a[1, 2] as a[1.2]
|
|
|
+// const char *s = getAttributeValue((Element *)sv, att_name);
|
|
|
+// fprintf(file, "%c", separator);
|
|
|
+// while (*s) {
|
|
|
+// if (*s != ' ') {
|
|
|
+// fprintf(file, "%c", *s == ',' ? '.' : *s);
|
|
|
+// }
|
|
|
+// s++;
|
|
|
+// }
|
|
|
+// } else {
|
|
|
+// fprintf(file, "%c%s", separator, getAttributeValue((Element *)sv, att_name));
|
|
|
+// }
|
|
|
+// } else {
|
|
|
+// // output values
|
|
|
+// vr = getValueReference(sv);
|
|
|
+// switch (getElementType(getTypeSpec(sv))) {
|
|
|
+// case elm_Real:
|
|
|
+// fmu->getReal(c, &vr, 1, &r);
|
|
|
+// if (separator == ',') {
|
|
|
+// fprintf(file, ",%.16g", r);
|
|
|
+// } else {
|
|
|
+// // separator is e.g. ';' or '\t'
|
|
|
+// doubleToCommaString(buffer, r);
|
|
|
+// fprintf(file, "%c%s", separator, buffer);
|
|
|
+// }
|
|
|
+// break;
|
|
|
+// case elm_Integer:
|
|
|
+// case elm_Enumeration:
|
|
|
+// fmu->getInteger(c, &vr, 1, &i);
|
|
|
+// fprintf(file, "%c%d", separator, i);
|
|
|
+// break;
|
|
|
+// case elm_Boolean:
|
|
|
+// fmu->getBoolean(c, &vr, 1, &b);
|
|
|
+// fprintf(file, "%c%d", separator, b);
|
|
|
+// break;
|
|
|
+// case elm_String:
|
|
|
+// fmu->getString(c, &vr, 1, &s);
|
|
|
+// fprintf(file, "%c%s", separator, s);
|
|
|
+// break;
|
|
|
+// default:
|
|
|
+// fprintf(file, "%cNoValueForType=%d", separator, getElementType(getTypeSpec(sv)));
|
|
|
+// }
|
|
|
+// }
|
|
|
+// } // for
|
|
|
+//
|
|
|
+// // terminate this row
|
|
|
+// fprintf(file, "\n");
|
|
|
+//}
|
|
|
+//
|
|
|
+static const char* fmi2StatusToString(fmi2Status status){
|
|
|
+ switch (status){
|
|
|
+ case fmi2OK: return "ok";
|
|
|
+ case fmi2Warning: return "warning";
|
|
|
+ case fmi2Discard: return "discard";
|
|
|
+ case fmi2Error: return "error";
|
|
|
+ case fmi2Fatal: return "fatal";
|
|
|
+ #ifdef FMI_COSIMULATION
|
|
|
+ case fmi2Pending: return "fmi2Pending";
|
|
|
+ #endif
|
|
|
+ default: return "?";
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// search a fmu for the given variable, matching the type specified.
|
|
|
+// return NULL if not found
|
|
|
+//static ScalarVariable* getSV(FMU* fmu, char type, fmi2ValueReference vr) {
|
|
|
+// return NULL;
|
|
|
+// int i;
|
|
|
+// int n = getScalarVariableSize(fmu->modelDescription);
|
|
|
+// Elm tp;
|
|
|
+//
|
|
|
+// switch (type) {
|
|
|
+// case 'r': tp = elm_Real; break;
|
|
|
+// case 'i': tp = elm_Integer; break;
|
|
|
+// case 'b': tp = elm_Boolean; break;
|
|
|
+// case 's': tp = elm_String; break;
|
|
|
+// default : tp = elm_BAD_DEFINED;
|
|
|
+// }
|
|
|
+// for (i = 0; i < n; i++) {
|
|
|
+// ScalarVariable* sv = getScalarVariable(fmu->modelDescription ,i);
|
|
|
+// if (vr == getValueReference(sv) && tp == getElementType(getTypeSpec(sv))) {
|
|
|
+// return sv;
|
|
|
+// }
|
|
|
+// }
|
|
|
+// return NULL;
|
|
|
+//}
|
|
|
+
|
|
|
+// replace e.g. #r1365# by variable name and ## by # in message
|
|
|
+// copies the result to buffer
|
|
|
+static void replaceRefsInMessage(const char* msg, char* buffer, int nBuffer, FMU* fmu){
|
|
|
+ int i = 0; // position in msg
|
|
|
+ int k = 0; // position in buffer
|
|
|
+ int n;
|
|
|
+ char c = msg[i];
|
|
|
+ while (c != '\0' && k < nBuffer) {
|
|
|
+ if (c != '#') {
|
|
|
+ buffer[k++] = c;
|
|
|
+ i++;
|
|
|
+ c = msg[i];
|
|
|
+ } else {
|
|
|
+
|
|
|
+ char* end = strchr(msg + i + 1, '#');
|
|
|
+ if (!end) {
|
|
|
+ printf("unmatched '#' in '%s'\n", msg);
|
|
|
+ buffer[k++] = '#';
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ n = end - (msg + i);
|
|
|
+ if (n == 1) {
|
|
|
+ // ## detected, output #
|
|
|
+ buffer[k++] = '#';
|
|
|
+ i += 2;
|
|
|
+ c = msg[i];
|
|
|
+
|
|
|
+ } else {
|
|
|
+ char type = msg[i + 1]; // one of ribs
|
|
|
+ fmi2ValueReference vr;
|
|
|
+ int nvr = sscanf(msg + i + 2, "%u", &vr);
|
|
|
+ if (nvr == 1) {
|
|
|
+ // vr of type detected, e.g. #r12#
|
|
|
+ //ScalarVariable* sv = getSV(fmu, type, vr);
|
|
|
+ //const char* name = sv ? getAttributeValue((Element *)sv, att_name) : "?";
|
|
|
+ //sprintf(buffer + k, "%s", name);
|
|
|
+ //k += strlen(name);
|
|
|
+ //i += (n+1);
|
|
|
+ //c = msg[i];
|
|
|
+
|
|
|
+ } else {
|
|
|
+ // could not parse the number
|
|
|
+ printf("illegal value reference at position %d in '%s'\n", i + 2, msg);
|
|
|
+ buffer[k++] = '#';
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } // while
|
|
|
+ buffer[k] = '\0';
|
|
|
+}
|
|
|
+
|
|
|
+#define MAX_MSG_SIZE 1000
|
|
|
+void fmuLogger(void *componentEnvironment, fmi2String instanceName, fmi2Status status,
|
|
|
+ fmi2String category, fmi2String message, ...) {
|
|
|
+ char msg[MAX_MSG_SIZE];
|
|
|
+ char* copy;
|
|
|
+ va_list argp;
|
|
|
+
|
|
|
+ // replace C format strings
|
|
|
+ va_start(argp, message);
|
|
|
+ vsprintf(msg, message, argp);
|
|
|
+ va_end(argp);
|
|
|
+
|
|
|
+ // replace e.g. ## and #r12#
|
|
|
+ copy = strdup(msg);
|
|
|
+// replaceRefsInMessage(copy, msg, MAX_MSG_SIZE, NULL);
|
|
|
+ free(copy);
|
|
|
+
|
|
|
+ // print the final message
|
|
|
+ if (!instanceName) instanceName = "?";
|
|
|
+ if (!category) category = "?";
|
|
|
+ printf("%s %s (%s): %s\n", fmi2StatusToString(status), instanceName, category, msg);
|
|
|
+}
|
|
|
+
|
|
|
+int error(const char* message){
|
|
|
+ printf("%s\n", message);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+//
|
|
|
+//void parseArguments(int argc, char *argv[], const char **fmuFileName, double *tEnd, double *h,
|
|
|
+// int *loggingOn, char *csv_separator, int *nCategories, char **logCategories[]) {
|
|
|
+// // parse command line arguments
|
|
|
+// if (argc > 1) {
|
|
|
+// *fmuFileName = argv[1];
|
|
|
+// } else {
|
|
|
+// printf("error: no fmu file\n");
|
|
|
+// printHelp(argv[0]);
|
|
|
+// exit(EXIT_FAILURE);
|
|
|
+// }
|
|
|
+// if (argc > 2) {
|
|
|
+// if (sscanf(argv[2],"%lf", tEnd) != 1) {
|
|
|
+// printf("error: The given end time (%s) is not a number\n", argv[2]);
|
|
|
+// exit(EXIT_FAILURE);
|
|
|
+// }
|
|
|
+// }
|
|
|
+// if (argc > 3) {
|
|
|
+// if (sscanf(argv[3],"%lf", h) != 1) {
|
|
|
+// printf("error: The given stepsize (%s) is not a number\n", argv[3]);
|
|
|
+// exit(EXIT_FAILURE);
|
|
|
+// }
|
|
|
+// }
|
|
|
+// if (argc > 4) {
|
|
|
+// if (sscanf(argv[4],"%d", loggingOn) != 1 || *loggingOn < 0 || *loggingOn > 1) {
|
|
|
+// printf("error: The given logging flag (%s) is not boolean\n", argv[4]);
|
|
|
+// exit(EXIT_FAILURE);
|
|
|
+// }
|
|
|
+// }
|
|
|
+// if (argc > 5) {
|
|
|
+// if (strlen(argv[5]) != 1) {
|
|
|
+// printf("error: The given CSV separator char (%s) is not valid\n", argv[5]);
|
|
|
+// exit(EXIT_FAILURE);
|
|
|
+// }
|
|
|
+// switch (argv[5][0]) {
|
|
|
+// case 'c': *csv_separator = ','; break; // comma
|
|
|
+// case 's': *csv_separator = ';'; break; // semicolon
|
|
|
+// default: *csv_separator = argv[5][0]; break; // any other char
|
|
|
+// }
|
|
|
+// }
|
|
|
+// if (argc > 6) {
|
|
|
+// int i;
|
|
|
+// *nCategories = argc - 6;
|
|
|
+// *logCategories = (char **)calloc(sizeof(char *), *nCategories);
|
|
|
+// for (i = 0; i < *nCategories; i++) {
|
|
|
+// (*logCategories)[i] = argv[i + 6];
|
|
|
+// }
|
|
|
+// }
|
|
|
+//}
|
|
|
+//
|
|
|
+//void printHelp(const char *fmusim) {
|
|
|
+// printf("command syntax: %s <model.fmu> <tEnd> <h> <loggingOn> <csv separator>\n", fmusim);
|
|
|
+// printf(" <model.fmu> .... path to FMU, relative to current dir or absolute, required\n");
|
|
|
+// printf(" <tEnd> ......... end time of simulation, optional, defaults to 1.0 sec\n");
|
|
|
+// printf(" <h> ............ step size of simulation, optional, defaults to 0.1 sec\n");
|
|
|
+// printf(" <loggingOn> .... 1 to activate logging, optional, defaults to 0\n");
|
|
|
+// printf(" <csv separator>. separator in csv file, optional, c for ',', s for';', defaults to c\n");
|
|
|
+// printf(" <logCategories>. list of active categories, optional, see modelDescription.xml for possible values\n");
|
|
|
+//}
|