-/* ------------------------------------------------------------------------- \r
- * sim_support.c\r
- * Functions used by both FMU simulators fmusim_me and fmusim_cs\r
- * to parse command-line arguments, to unzip and load an fmu, \r
- * to write CSV file, and more.\r
- * Copyright 2011 QTronic GmbH. All rights reserved. \r
- * -------------------------------------------------------------------------*/ \r
-\r
-#include <stdio.h>\r
-#include <stdlib.h>\r
-#include <string.h>\r
-#include <assert.h>\r
-#include <time.h>\r
-#include <stdarg.h>\r
-\r
-#ifdef FMI_COSIMULATION\r
-#include "fmi_cs.h"\r
-#else\r
-#include "fmi_me.h"\r
-#endif\r
-\r
-// linux/unix DSO loading\r
-#ifndef _MSC_VER\r
-#include <dlfcn.h>\r
-#endif\r
-\r
-#include "sim_support.h"\r
-//#include "fmuExtract.h"\r
-\r
-#define MAX_PATH_SIZE 4096\r
-\r
-#ifdef _MSC_VER\r
-// fileName is an absolute path, e.g. C:\test\a.fmu\r
-// or relative to the current dir, e.g. ..\test\a.fmu\r
-// Does not check for existence of the file\r
-static char* getFmuPath(const char* fileName){\r
- char pathName[MAX_PATH_SIZE];\r
- int n = GetFullPathName(fileName, MAX_PATH, pathName, NULL);\r
- return n ? strdup(pathName) : NULL;\r
-}\r
-\r
-int tmpPathRequests = 0;\r
-static char* getTmpPath() {\r
- char tmpPath[BUFSIZE];\r
- if(! GetTempPath(BUFSIZE, tmpPath)) {\r
- printf ("error: Could not find temporary disk space\n");\r
- return NULL;\r
- }\r
- if(tmpPathRequests % 2 == 0) {\r
- strcat(tmpPath, "fmu\\");\r
- tmpPathRequests++;\r
- } else {\r
- strcat(tmpPath, "fmu2\\");\r
- tmpPathRequests = 0;\r
- }\r
-\r
- makedir(tmpPath);\r
-\r
- return strdup(tmpPath);\r
-}\r
-#endif\r
-\r
-static void* getAdr(int* s, FMU *fmu, const char* functionName){\r
- char name[BUFSIZE];\r
- void* fp;\r
- sprintf(name, "%s_%s", getModelIdentifier(fmu->modelDescription), functionName);\r
-#ifdef _MSC_VER\r
- fp = GetProcAddress(fmu->dllHandle, name);\r
-#else\r
- fp = dlsym(fmu->dllHandle, name);\r
-#endif\r
- if (!fp) {\r
- printf ("warning: Function %s not found in dll\n", name);\r
- *s = 0; // mark dll load as 'failed' \r
- }\r
- return fp;\r
-}\r
-\r
-// Load the given dll and set function pointers in fmu\r
-// Return 0 to indicate failure\r
-static int loadDll(const char* dllPath, FMU *fmu) {\r
- int s = 1;\r
-#ifdef _MSC_VER\r
- HANDLE h = LoadLibraryEx(dllPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);\r
- if (!h) {\r
- int error = GetLastError();\r
- printf("error %d: Could not load %s\n", error, dllPath);\r
- return 0; // failure\r
- }\r
- fmu->dllHandle = h;\r
-#else\r
- void* h = dlopen(dllPath, RTLD_LAZY);\r
- if (!h) {\r
- char* error = dlerror();\r
- printf("error %s: Could not load %s\n", error, dllPath);\r
- return 0; // failure\r
- }\r
- fmu->dllHandle = h;\r
-#endif\r
-\r
-#ifdef FMI_COSIMULATION \r
- fmu->getTypesPlatform = (fGetTypesPlatform) getAdr(&s, fmu, "fmiGetTypesPlatform");\r
- if (s==0) { \r
- s = 1; // work around bug for FMUs exported using Dymola 2012 and SimulationX 3.x\r
- fmu->getTypesPlatform = (fGetTypesPlatform) getAdr(&s, fmu, "fmiGetModelTypesPlatform");\r
- if (s==1) printf(" using fmiGetModelTypesPlatform instead\n", dllPath);\r
- }\r
- fmu->instantiateSlave = (fInstantiateSlave) getAdr(&s, fmu, "fmiInstantiateSlave");\r
- fmu->initializeSlave = (fInitializeSlave) getAdr(&s, fmu, "fmiInitializeSlave"); \r
- fmu->terminateSlave = (fTerminateSlave) getAdr(&s, fmu, "fmiTerminateSlave");\r
- fmu->resetSlave = (fResetSlave) getAdr(&s, fmu, "fmiResetSlave");\r
- fmu->freeSlaveInstance = (fFreeSlaveInstance) getAdr(&s, fmu, "fmiFreeSlaveInstance");\r
- fmu->setRealInputDerivatives = (fSetRealInputDerivatives) getAdr(&s, fmu, "fmiSetRealInputDerivatives");\r
- fmu->getRealOutputDerivatives = (fGetRealOutputDerivatives) getAdr(&s, fmu, "fmiGetRealOutputDerivatives");\r
- fmu->cancelStep = (fCancelStep) getAdr(&s, fmu, "fmiCancelStep");\r
- fmu->doStep = (fDoStep) getAdr(&s, fmu, "fmiDoStep");\r
- // SimulationX 3.4 and 3.5 do not yet export getStatus and getXStatus: do not count this as failure here\r
- fmu->getStatus = (fGetStatus) getAdr(&x, fmu, "fmiGetStatus");\r
- fmu->getRealStatus = (fGetRealStatus) getAdr(&x, fmu, "fmiGetRealStatus");\r
- fmu->getIntegerStatus = (fGetIntegerStatus) getAdr(&x, fmu, "fmiGetIntegerStatus");\r
- fmu->getBooleanStatus = (fGetBooleanStatus) getAdr(&x, fmu, "fmiGetBooleanStatus");\r
- fmu->getStringStatus = (fGetStringStatus) getAdr(&x, fmu, "fmiGetStringStatus"); \r
-\r
-#else // FMI for Model Exchange 1.0\r
- fmu->getModelTypesPlatform = (fGetModelTypesPlatform) getAdr(&s, fmu, "fmiGetModelTypesPlatform");\r
- fmu->instantiateModel = (fInstantiateModel) getAdr(&s, fmu, "fmiInstantiateModel");\r
- fmu->freeModelInstance = (fFreeModelInstance) getAdr(&s, fmu, "fmiFreeModelInstance");\r
- fmu->setTime = (fSetTime) getAdr(&s, fmu, "fmiSetTime");\r
- fmu->setContinuousStates = (fSetContinuousStates)getAdr(&s, fmu, "fmiSetContinuousStates");\r
- fmu->completedIntegratorStep = (fCompletedIntegratorStep)getAdr(&s, fmu, "fmiCompletedIntegratorStep");\r
- fmu->initialize = (fInitialize) getAdr(&s, fmu, "fmiInitialize");\r
- fmu->getDerivatives = (fGetDerivatives) getAdr(&s, fmu, "fmiGetDerivatives");\r
- fmu->getEventIndicators = (fGetEventIndicators) getAdr(&s, fmu, "fmiGetEventIndicators");\r
- fmu->eventUpdate = (fEventUpdate) getAdr(&s, fmu, "fmiEventUpdate");\r
- fmu->getContinuousStates = (fGetContinuousStates)getAdr(&s, fmu, "fmiGetContinuousStates");\r
- fmu->getNominalContinuousStates = (fGetNominalContinuousStates)getAdr(&s, fmu, "fmiGetNominalContinuousStates");\r
- fmu->getStateValueReferences = (fGetStateValueReferences)getAdr(&s, fmu, "fmiGetStateValueReferences");\r
- fmu->terminate = (fTerminate) getAdr(&s, fmu, "fmiTerminate");\r
-#endif \r
- fmu->getVersion = (fGetVersion) getAdr(&s, fmu, "fmiGetVersion");\r
- fmu->setDebugLogging = (fSetDebugLogging) getAdr(&s, fmu, "fmiSetDebugLogging");\r
- fmu->setReal = (fSetReal) getAdr(&s, fmu, "fmiSetReal");\r
- fmu->setInteger = (fSetInteger) getAdr(&s, fmu, "fmiSetInteger");\r
- fmu->setBoolean = (fSetBoolean) getAdr(&s, fmu, "fmiSetBoolean");\r
- fmu->setString = (fSetString) getAdr(&s, fmu, "fmiSetString");\r
- fmu->getReal = (fGetReal) getAdr(&s, fmu, "fmiGetReal");\r
- fmu->getInteger = (fGetInteger) getAdr(&s, fmu, "fmiGetInteger");\r
- fmu->getBoolean = (fGetBoolean) getAdr(&s, fmu, "fmiGetBoolean");\r
- fmu->getString = (fGetString) getAdr(&s, fmu, "fmiGetString");\r
- return s; \r
-}\r
-\r
-/*static void printModelDescription(ModelDescription* md){\r
- Element* e = (Element*)md; \r
- int i;\r
- printf("%s\n", elmNames[e->type]);\r
- for (i=0; i<e->n; i+=2) \r
- printf(" %s=%s\n", e->attributes[i], e->attributes[i+1]);\r
-#ifdef FMI_COSIMULATION \r
- if (!md->cosimulation) {\r
- printf("error: No Implementation element found in model description. This FMU is not for Co-Simulation.\n");\r
- exit(EXIT_FAILURE);\r
- }\r
- e = md->cosimulation->capabilities;\r
- printf("%s\n", elmNames[e->type]);\r
- for (i=0; i<e->n; i+=2) \r
- printf(" %s=%s\n", e->attributes[i], e->attributes[i+1]);\r
-#endif // FMI_COSIMULATION \r
-}\r
-*/\r
-\r
-/*\r
- * return: 1 for successful laod or number for error.\r
- * -1. FMU path not found\r
- * -2. Unzip failed\r
- * -3. Loading model description failed\r
- * -4. FMU dll load failed\r
- */\r
-/*\r
-int loadFMU(FMU *fmu, const char* fmuFileName, const char* tmpPath) {\r
- char* fmuPath;\r
- char* xmlPath;\r
- char* dllPath;\r
- unsigned old_clock = clock();\r
- unsigned current_clock = 0;//will be assigned later\r
- \r
- // get absolute path to FMU, NULL if not found\r
- fmuPath = getFmuPath(fmuFileName);\r
- if (!fmuPath) return -1; // path not found\r
-\r
- // unzip the FMU to the tmpPath directory\r
- if (unzip(fmuPath, tmpPath)) return -2; // unzip failed\r
-\r
- // parse tmpPath\modelDescription.xml\r
- xmlPath = calloc(sizeof(char), strlen(tmpPath) + strlen(XML_FILE) + 1);\r
- sprintf(xmlPath, "%s%s", tmpPath, XML_FILE);\r
- fmu->modelDescription = parse(xmlPath);\r
- free(xmlPath);\r
- if (!fmu->modelDescription) return -3; // loading model description failed\r
-\r
- // printModelDescription(fmu.modelDescription);\r
- // fflush(stdout);\r
-\r
- // load the FMU dll\r
- dllPath = calloc(sizeof(char), strlen(tmpPath) + strlen(DLL_DIR) \r
- + strlen( getModelIdentifier(fmu->modelDescription)) + strlen(".dll") + 1);\r
- sprintf(dllPath,"%s%s%s.dll", tmpPath, DLL_DIR, getModelIdentifier(fmu->modelDescription));\r
- if (!loadDll(dllPath, fmu)) return -4; // loading dll failed\r
-\r
- free(dllPath);\r
- free(fmuPath);\r
-\r
- return 1;\r
-}\r
-*/\r
-\r
-static void doubleToCommaString(char* buffer, double r){\r
- char* comma;\r
- sprintf(buffer, "%.16g", r);\r
- comma = strchr(buffer, '.');\r
- if (comma) *comma = ',';\r
-}\r
-\r
-// output time and all non-alias variables in CSV format\r
-// if separator is ',', columns are separated by ',' and '.' is used for floating-point numbers.\r
-// otherwise, the given separator (e.g. ';' or '\t') is to separate columns, and ',' is used \r
-// as decimal dot in floating-point numbers.\r
-/*\r
-void outputRow(FMU *fmu, fmiComponent c, double time, FILE* file, char separator, boolean header) {\r
- int k;\r
- fmiReal r;\r
- fmiInteger i;\r
- fmiBoolean b;\r
- fmiString s;\r
- fmiValueReference vr;\r
- ScalarVariable** vars = fmu->modelDescription->modelVariables;\r
- char buffer[32];\r
- \r
- // print first column\r
- if (header) \r
- fprintf(file, "time"); \r
- else {\r
- if (separator==',') \r
- fprintf(file, "%.16g", time);\r
- else {\r
- // separator is e.g. ';' or '\t'\r
- doubleToCommaString(buffer, time);\r
- fprintf(file, "%s", buffer); \r
- }\r
- }\r
- \r
- // print all other columns\r
- for (k=0; vars[k]; k++) {\r
- ScalarVariable* sv = vars[k];\r
- if (getAlias(sv)!=enu_noAlias) continue;\r
- if (header) {\r
- // output names only\r
- if (separator==',') {\r
- // treat array element, e.g. print a[1, 2] as a[1.2]\r
- char* s = getName(sv);\r
- fprintf(file, "%c", separator);\r
- while (*s) {\r
- if (*s!=' ') fprintf(file, "%c", *s==',' ? '.' : *s);\r
- s++;\r
- }\r
- }\r
- else\r
- fprintf(file, "%c%s", separator, getName(sv));\r
- }\r
- else {\r
- // output values\r
- vr = getValueReference(sv);\r
- switch (sv->typeSpec->type){\r
- case elm_Real:\r
- fmu->getReal(c, &vr, 1, &r);\r
- if (separator==',') \r
- fprintf(file, ",%.16g", r);\r
- else {\r
- // separator is e.g. ';' or '\t'\r
- doubleToCommaString(buffer, r);\r
- fprintf(file, "%c%s", separator, buffer); \r
- }\r
- break;\r
- case elm_Integer:\r
- case elm_Enumeration:\r
- fmu->getInteger(c, &vr, 1, &i);\r
- fprintf(file, "%c%d", separator, i);\r
- break;\r
- case elm_Boolean:\r
- fmu->getBoolean(c, &vr, 1, &b);\r
- fprintf(file, "%c%d", separator, b);\r
- break;\r
- case elm_String:\r
- fmu->getString(c, &vr, 1, &s);\r
- fprintf(file, "%c%s", separator, s);\r
- break;\r
- default: \r
- fprintf(file, "%cNoValueForType=%d", separator,sv->typeSpec->type);\r
- }\r
- }\r
- } // for\r
- \r
- // terminate this row\r
- fprintf(file, "\n"); \r
-}\r
-*/\r
-\r
-static const char* fmiStatusToString(fmiStatus status){\r
- switch (status){\r
- case fmiOK: return "ok";\r
- case fmiWarning: return "warning";\r
- case fmiDiscard: return "discard";\r
- case fmiError: return "error";\r
- case fmiFatal: return "fatal";\r
-#ifdef FMI_COSIMULATION\r
- case fmiPending: return "fmiPending";\r
-#endif\r
- default: return "?";\r
- }\r
-}\r
-\r
-// search a fmu for the given variable\r
-// return NULL if not found or vr = fmiUndefinedValueReference\r
-static ScalarVariable* getSV(FMU* fmu, char type, fmiValueReference vr) {\r
- int i;\r
- Elm tp;\r
- ScalarVariable** vars = fmu->modelDescription->modelVariables;\r
- if (vr==fmiUndefinedValueReference) return NULL;\r
- switch (type) {\r
- case 'r': tp = elm_Real; break;\r
- case 'i': tp = elm_Integer; break;\r
- case 'b': tp = elm_Boolean; break;\r
- case 's': tp = elm_String; break; \r
- }\r
- for (i=0; vars[i]; i++) {\r
- ScalarVariable* sv = vars[i];\r
- if (vr==getValueReference(sv) && tp==sv->typeSpec->type) \r
- return sv;\r
- }\r
- return NULL;\r
-}\r
-\r
-// replace e.g. #r1365# by variable name and ## by # in message\r
-// copies the result to buffer\r
-static void replaceRefsInMessage(const char* msg, char* buffer, int nBuffer, FMU* fmu){\r
- int i=0; // position in msg\r
- int k=0; // position in buffer\r
- int n;\r
- char c = msg[i];\r
- while (c!='\0' && k < nBuffer) {\r
- if (c!='#') {\r
- buffer[k++]=c;\r
- i++;\r
- c = msg[i];\r
- }\r
- else {\r
- char* end = strchr(const_cast<char*>(msg+i+1), '#');\r
- if (!end) {\r
- printf("unmatched '#' in '%s'\n", msg);\r
- buffer[k++]='#';\r
- break;\r
- }\r
- n = end - (msg+i);\r
- if (n==1) {\r
- // ## detected, output #\r
- buffer[k++]='#';\r
- i += 2;\r
- c = msg[i];\r
- }\r
- else {\r
- char type = msg[i+1]; // one of ribs\r
- fmiValueReference vr;\r
- int nvr = sscanf(msg+i+2, "%u", &vr);\r
- if (nvr==1) {\r
- // vr of type detected, e.g. #r12#\r
- ScalarVariable* sv = getSV(fmu, type, vr);\r
- const char* name = sv ? getName(sv) : "?";\r
- sprintf(buffer+k, "%s", name);\r
- k += strlen(name);\r
- i += (n+1);\r
- c = msg[i]; \r
- }\r
- else {\r
- // could not parse the number\r
- printf("illegal value reference at position %d in '%s'\n", i+2, msg);\r
- buffer[k++]='#';\r
- break;\r
- }\r
- }\r
- }\r
- } // while\r
- buffer[k] = '\0';\r
-}\r
-\r
-#define MAX_MSG_SIZE 1000\r
-void fmuLogger(FMU *fmu, fmiComponent c, fmiString instanceName, fmiStatus status,\r
- fmiString category, fmiString message, ...) {\r
- char msg[MAX_MSG_SIZE];\r
-// char* copy;\r
- va_list argp;\r
-\r
- // replace C format strings\r
- va_start(argp, message);\r
- vsprintf(msg, message, argp);\r
- va_end(argp);\r
-\r
- // replace e.g. ## and #r12# \r
-// copy = strdup(msg);\r
-// replaceRefsInMessage(copy, msg, MAX_MSG_SIZE, fmu);\r
-// free(copy);\r
- \r
- // print the final message\r
- if (!instanceName) instanceName = "?";\r
- if (!category) category = "?";\r
- //printf("%s %s (%s): %s\n", fmiStatusToString(status), instanceName, category, msg);\r
- printf("%s\n", message);\r
-}\r
-\r
-int error(const char* message){\r
- printf("%s\n", message);\r
- return 0;\r
-}\r
-\r
-void parseArguments(int argc, char *argv[], char** fmuFileName, double* tEnd, double* h, int* loggingOn, char* csv_separator) {\r
- // parse command line arguments\r
- if (argc>1) {\r
- *fmuFileName = argv[1];\r
- }\r
- else {\r
- printf("error: no fmu file\n");\r
- printHelp(argv[0]);\r
- exit(EXIT_FAILURE);\r
- }\r
- if (argc>2) {\r
- if (sscanf(argv[2],"%lf", tEnd) != 1) {\r
- printf("error: The given end time (%s) is not a number\n", argv[2]);\r
- exit(EXIT_FAILURE);\r
- }\r
- }\r
- if (argc>3) {\r
- if (sscanf(argv[3],"%lf", h) != 1) {\r
- printf("error: The given stepsize (%s) is not a number\n", argv[3]);\r
- exit(EXIT_FAILURE);\r
- }\r
- }\r
- if (argc>4) {\r
- if (sscanf(argv[4],"%d", loggingOn) != 1 || *loggingOn<0 || *loggingOn>1) {\r
- printf("error: The given logging flag (%s) is not boolean\n", argv[4]);\r
- exit(EXIT_FAILURE);\r
- }\r
- }\r
- if (argc>5) {\r
- if (strlen(argv[5]) != 1) {\r
- printf("error: The given CSV separator char (%s) is not valid\n", argv[5]);\r
- exit(EXIT_FAILURE);\r
- }\r
- switch (argv[5][0]) {\r
- case 'c': *csv_separator = ','; break; // comma\r
- case 's': *csv_separator = ';'; break; // semicolon\r
- default: *csv_separator = argv[5][0]; break; // any other char\r
- }\r
- }\r
- if (argc>6) {\r
- printf("warning: Ignoring %d additional arguments: %s ...\n", argc-6, argv[6]);\r
- printHelp(argv[0]);\r
- }\r
-}\r
-\r
-void printHelp(const char* fmusim) {\r
- printf("command syntax: %s <model.fmu> <tEnd> <h> <loggingOn> <csv separator>\n", fmusim);\r
- printf(" <model.fmu> .... path to FMU, relative to current dir or absolute, required\n");\r
- printf(" <tEnd> ......... end time of simulation, optional, defaults to 1.0 sec\n");\r
- printf(" <h> ............ step size of simulation, optional, defaults to 0.1 sec\n");\r
- printf(" <loggingOn> .... 1 to activate logging, optional, defaults to 0\n");\r
- printf(" <csv separator>. separator in csv file, optional, c for ';', s for';', defaults to c\n");\r
-}\r
-\r
+/* -------------------------------------------------------------------------
+ * sim_support.c
+ * Functions used by both FMU simulators fmusim_me and fmusim_cs
+ * to parse command-line arguments, to unzip and load an fmu,
+ * to write CSV file, and more.
+ * Copyright 2011 QTronic GmbH. All rights reserved.
+ * -------------------------------------------------------------------------*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <time.h>
+#include <stdarg.h>
+
+#ifdef FMI_COSIMULATION
+#include "fmi_cs.h"
+#else
+#include "fmi_me.h"
+#endif
+
+// linux/unix DSO loading
+#ifndef _MSC_VER
+#include <dlfcn.h>
+#endif
+
+#include "sim_support.h"
+//#include "fmuExtract.h"
+
+#define MAX_PATH_SIZE 4096
+
+#ifdef _MSC_VER
+
+#include <windows.h>
+// 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_SIZE];
+ int n = GetFullPathName(fileName, MAX_PATH_SIZE, pathName, NULL);
+ return n ? strdup(pathName) : NULL;
+}
+
+int tmpPathRequests = 0;
+static char* getTmpPath() {
+ char tmpPath[BUFSIZE];
+ if(! GetTempPath(BUFSIZE, tmpPath)) {
+ printf ("error: Could not find temporary disk space\n");
+ return NULL;
+ }
+ if(tmpPathRequests % 2 == 0) {
+ strcat(tmpPath, "fmu\\");
+ tmpPathRequests++;
+ } else {
+ strcat(tmpPath, "fmu2\\");
+ tmpPathRequests = 0;
+ }
+
+ makedir(tmpPath);
+
+ return strdup(tmpPath);
+}
+#endif
+
+static void* getAdr(int* s, FMU *fmu, const char* functionName){
+ char name[BUFSIZE];
+ void* fp;
+ sprintf(name, "%s_%s", getModelIdentifier(fmu->modelDescription), functionName);
+#ifdef _MSC_VER
+ fp = GetProcAddress(fmu->dllHandle, name);
+#else
+ fp = dlsym(fmu->dllHandle, name);
+#endif
+ if (!fp) {
+ printf ("warning: Function %s not found in dll\n", name);
+ *s = 0; // mark dll load as 'failed'
+ }
+ return fp;
+}
+
+// Load the given dll and set function pointers in fmu
+// Return 0 to indicate failure
+static int loadDll(const char* dllPath, FMU *fmu) {
+ int s = 1;
+#ifdef _MSC_VER
+ HANDLE h = LoadLibraryEx(dllPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
+ if (!h) {
+ int error = GetLastError();
+ printf("error %d: Could not load %s\n", error, dllPath);
+ return 0; // failure
+ }
+ fmu->dllHandle = h;
+#else
+ void* h = dlopen(dllPath, RTLD_LAZY);
+ if (!h) {
+ char* error = dlerror();
+ printf("error %s: Could not load %s\n", error, dllPath);
+ return 0; // failure
+ }
+ fmu->dllHandle = h;
+#endif
+
+#ifdef FMI_COSIMULATION
+ fmu->getTypesPlatform = (fGetTypesPlatform) getAdr(&s, fmu, "fmiGetTypesPlatform");
+ if (s==0) {
+ s = 1; // work around bug for FMUs exported using Dymola 2012 and SimulationX 3.x
+ fmu->getTypesPlatform = (fGetTypesPlatform) getAdr(&s, fmu, "fmiGetModelTypesPlatform");
+ if (s==1) printf(" using fmiGetModelTypesPlatform instead\n", dllPath);
+ }
+ fmu->instantiateSlave = (fInstantiateSlave) getAdr(&s, fmu, "fmiInstantiateSlave");
+ fmu->initializeSlave = (fInitializeSlave) getAdr(&s, fmu, "fmiInitializeSlave");
+ fmu->terminateSlave = (fTerminateSlave) getAdr(&s, fmu, "fmiTerminateSlave");
+ fmu->resetSlave = (fResetSlave) getAdr(&s, fmu, "fmiResetSlave");
+ fmu->freeSlaveInstance = (fFreeSlaveInstance) getAdr(&s, fmu, "fmiFreeSlaveInstance");
+ fmu->setRealInputDerivatives = (fSetRealInputDerivatives) getAdr(&s, fmu, "fmiSetRealInputDerivatives");
+ fmu->getRealOutputDerivatives = (fGetRealOutputDerivatives) getAdr(&s, fmu, "fmiGetRealOutputDerivatives");
+ fmu->cancelStep = (fCancelStep) getAdr(&s, fmu, "fmiCancelStep");
+ fmu->doStep = (fDoStep) getAdr(&s, fmu, "fmiDoStep");
+ // SimulationX 3.4 and 3.5 do not yet export getStatus and getXStatus: do not count this as failure here
+ fmu->getStatus = (fGetStatus) getAdr(&x, fmu, "fmiGetStatus");
+ fmu->getRealStatus = (fGetRealStatus) getAdr(&x, fmu, "fmiGetRealStatus");
+ fmu->getIntegerStatus = (fGetIntegerStatus) getAdr(&x, fmu, "fmiGetIntegerStatus");
+ fmu->getBooleanStatus = (fGetBooleanStatus) getAdr(&x, fmu, "fmiGetBooleanStatus");
+ fmu->getStringStatus = (fGetStringStatus) getAdr(&x, fmu, "fmiGetStringStatus");
+
+#else // FMI for Model Exchange 1.0
+ fmu->getModelTypesPlatform = (fGetModelTypesPlatform) getAdr(&s, fmu, "fmiGetModelTypesPlatform");
+ fmu->instantiateModel = (fInstantiateModel) getAdr(&s, fmu, "fmiInstantiateModel");
+ fmu->freeModelInstance = (fFreeModelInstance) getAdr(&s, fmu, "fmiFreeModelInstance");
+ fmu->setTime = (fSetTime) getAdr(&s, fmu, "fmiSetTime");
+ fmu->setContinuousStates = (fSetContinuousStates)getAdr(&s, fmu, "fmiSetContinuousStates");
+ fmu->completedIntegratorStep = (fCompletedIntegratorStep)getAdr(&s, fmu, "fmiCompletedIntegratorStep");
+ fmu->initialize = (fInitialize) getAdr(&s, fmu, "fmiInitialize");
+ fmu->getDerivatives = (fGetDerivatives) getAdr(&s, fmu, "fmiGetDerivatives");
+ fmu->getEventIndicators = (fGetEventIndicators) getAdr(&s, fmu, "fmiGetEventIndicators");
+ fmu->eventUpdate = (fEventUpdate) getAdr(&s, fmu, "fmiEventUpdate");
+ fmu->getContinuousStates = (fGetContinuousStates)getAdr(&s, fmu, "fmiGetContinuousStates");
+ fmu->getNominalContinuousStates = (fGetNominalContinuousStates)getAdr(&s, fmu, "fmiGetNominalContinuousStates");
+ fmu->getStateValueReferences = (fGetStateValueReferences)getAdr(&s, fmu, "fmiGetStateValueReferences");
+ fmu->terminate = (fTerminate) getAdr(&s, fmu, "fmiTerminate");
+#endif
+ fmu->getVersion = (fGetVersion) getAdr(&s, fmu, "fmiGetVersion");
+ fmu->setDebugLogging = (fSetDebugLogging) getAdr(&s, fmu, "fmiSetDebugLogging");
+ fmu->setReal = (fSetReal) getAdr(&s, fmu, "fmiSetReal");
+ fmu->setInteger = (fSetInteger) getAdr(&s, fmu, "fmiSetInteger");
+ fmu->setBoolean = (fSetBoolean) getAdr(&s, fmu, "fmiSetBoolean");
+ fmu->setString = (fSetString) getAdr(&s, fmu, "fmiSetString");
+ fmu->getReal = (fGetReal) getAdr(&s, fmu, "fmiGetReal");
+ fmu->getInteger = (fGetInteger) getAdr(&s, fmu, "fmiGetInteger");
+ fmu->getBoolean = (fGetBoolean) getAdr(&s, fmu, "fmiGetBoolean");
+ fmu->getString = (fGetString) getAdr(&s, fmu, "fmiGetString");
+ return s;
+}
+
+/*static void printModelDescription(ModelDescription* md){
+ Element* e = (Element*)md;
+ int i;
+ printf("%s\n", elmNames[e->type]);
+ for (i=0; i<e->n; i+=2)
+ printf(" %s=%s\n", e->attributes[i], e->attributes[i+1]);
+#ifdef FMI_COSIMULATION
+ if (!md->cosimulation) {
+ printf("error: No Implementation element found in model description. This FMU is not for Co-Simulation.\n");
+ exit(EXIT_FAILURE);
+ }
+ e = md->cosimulation->capabilities;
+ printf("%s\n", elmNames[e->type]);
+ for (i=0; i<e->n; i+=2)
+ printf(" %s=%s\n", e->attributes[i], e->attributes[i+1]);
+#endif // FMI_COSIMULATION
+}
+*/
+
+/*
+ * return: 1 for successful laod or number for error.
+ * -1. FMU path not found
+ * -2. Unzip failed
+ * -3. Loading model description failed
+ * -4. FMU dll load failed
+ */
+/*
+int loadFMU(FMU *fmu, const char* fmuFileName, const char* tmpPath) {
+ char* fmuPath;
+ char* xmlPath;
+ char* dllPath;
+ unsigned old_clock = clock();
+ unsigned current_clock = 0;//will be assigned later
+
+ // get absolute path to FMU, NULL if not found
+ fmuPath = getFmuPath(fmuFileName);
+ if (!fmuPath) return -1; // path not found
+
+ // unzip the FMU to the tmpPath directory
+ if (unzip(fmuPath, tmpPath)) return -2; // unzip failed
+
+ // 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) return -3; // loading model description failed
+
+ // printModelDescription(fmu.modelDescription);
+ // fflush(stdout);
+
+ // load the FMU dll
+ dllPath = calloc(sizeof(char), strlen(tmpPath) + strlen(DLL_DIR)
+ + strlen( getModelIdentifier(fmu->modelDescription)) + strlen(".dll") + 1);
+ sprintf(dllPath,"%s%s%s.dll", tmpPath, DLL_DIR, getModelIdentifier(fmu->modelDescription));
+ if (!loadDll(dllPath, fmu)) return -4; // loading dll failed
+
+ free(dllPath);
+ free(fmuPath);
+
+ return 1;
+}
+*/
+
+static void doubleToCommaString(char* buffer, double r){
+ char* comma;
+ sprintf(buffer, "%.16g", r);
+ comma = strchr(buffer, '.');
+ if (comma) *comma = ',';
+}
+
+// output time and all non-alias 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, fmiComponent c, double time, FILE* file, char separator, boolean header) {
+ int k;
+ fmiReal r;
+ fmiInteger i;
+ fmiBoolean b;
+ fmiString s;
+ fmiValueReference vr;
+ ScalarVariable** vars = fmu->modelDescription->modelVariables;
+ 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; vars[k]; k++) {
+ ScalarVariable* sv = vars[k];
+ if (getAlias(sv)!=enu_noAlias) continue;
+ if (header) {
+ // output names only
+ if (separator==',') {
+ // treat array element, e.g. print a[1, 2] as a[1.2]
+ char* s = getName(sv);
+ fprintf(file, "%c", separator);
+ while (*s) {
+ if (*s!=' ') fprintf(file, "%c", *s==',' ? '.' : *s);
+ s++;
+ }
+ }
+ else
+ fprintf(file, "%c%s", separator, getName(sv));
+ }
+ else {
+ // output values
+ vr = getValueReference(sv);
+ switch (sv->typeSpec->type){
+ 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,sv->typeSpec->type);
+ }
+ }
+ } // for
+
+ // terminate this row
+ fprintf(file, "\n");
+}
+*/
+
+static const char* fmiStatusToString(fmiStatus status){
+ switch (status){
+ case fmiOK: return "ok";
+ case fmiWarning: return "warning";
+ case fmiDiscard: return "discard";
+ case fmiError: return "error";
+ case fmiFatal: return "fatal";
+#ifdef FMI_COSIMULATION
+ case fmiPending: return "fmiPending";
+#endif
+ default: return "?";
+ }
+}
+
+// search a fmu for the given variable
+// return NULL if not found or vr = fmiUndefinedValueReference
+static ScalarVariable* getSV(FMU* fmu, char type, fmiValueReference vr) {
+ int i;
+ Elm tp;
+ ScalarVariable** vars = fmu->modelDescription->modelVariables;
+ if (vr==fmiUndefinedValueReference) return NULL;
+ 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;
+ }
+ for (i=0; vars[i]; i++) {
+ ScalarVariable* sv = vars[i];
+ if (vr==getValueReference(sv) && tp==sv->typeSpec->type)
+ 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((char*)(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
+ fmiValueReference 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 ? getName(sv) : "?";
+ 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(FMU *fmu, fmiComponent c, fmiString instanceName, fmiStatus status,
+ fmiString category, fmiString 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, fmu);
+// free(copy);
+
+ // print the final message
+ if (!instanceName) instanceName = "?";
+ if (!category) category = "?";
+ //printf("%s %s (%s): %s\n", fmiStatusToString(status), instanceName, category, msg);
+ printf("%s\n", message);
+}
+
+int error(const char* message){
+ printf("%s\n", message);
+ return 0;
+}
+
+void parseArguments(int argc, char *argv[], char** fmuFileName, double* tEnd, double* h, int* loggingOn, char* csv_separator) {
+ // 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) {
+ printf("warning: Ignoring %d additional arguments: %s ...\n", argc-6, argv[6]);
+ printHelp(argv[0]);
+ }
+}
+
+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");
+}
+