|
|
@@ -0,0 +1,800 @@
|
|
|
+/* ---------------------------------------------------------------------------*
|
|
|
+ * Implementation of the FMI interface based on functions and macros to
|
|
|
+ * be defined by the includer of this file.
|
|
|
+ * If FMI_COSIMULATION is defined, this implements "FMI for Co-Simulation 1.0",
|
|
|
+ * otherwise "FMI for Model Exchange 1.0".
|
|
|
+ * The "FMI for Co-Simulation 1.0", implementation assumes that exactly the
|
|
|
+ * following capability flags are set to fmiTrue:
|
|
|
+ * canHandleVariableCommunicationStepSize, i.e. fmiDoStep step size can vary
|
|
|
+ * canHandleEvents, i.e. fmiDoStep step size can be zero
|
|
|
+ * and all other capability flags are set to default, i.e. to fmiFalse or 0.
|
|
|
+ *
|
|
|
+ * Revision history
|
|
|
+ * 07.02.2010 initial version for "Model Exchange 1.0" released in FMU SDK 1.0
|
|
|
+ * 05.03.2010 bug fix: fmiSetString now copies the passed string argument
|
|
|
+ * and fmiFreeModelInstance frees all string copies
|
|
|
+ * 11.12.2010 replaced calloc by functions.allocateMemory in fmiInstantiateModel
|
|
|
+ * 04.08.2011 added support for "FMI for Co-Simulation 1.0"
|
|
|
+ * 02.08.2013 fixed a bug in instantiateModel reported by Markus Ende, TH Nuernberg
|
|
|
+ * 02.04.2014 better time event handling
|
|
|
+ * 02.06.2014 copy instanceName and GUID at instantiation
|
|
|
+ *
|
|
|
+ * Copyright QTronic GmbH. All rights reserved.
|
|
|
+ * ---------------------------------------------------------------------------*/
|
|
|
+
|
|
|
+#ifdef __cplusplus
|
|
|
+extern "C" {
|
|
|
+#endif
|
|
|
+
|
|
|
+// array of value references of states
|
|
|
+#if NUMBER_OF_STATES>0
|
|
|
+fmiValueReference vrStates[NUMBER_OF_STATES] = STATES;
|
|
|
+#endif
|
|
|
+
|
|
|
+#ifndef max
|
|
|
+#define max(a,b) ((a)>(b) ? (a) : (b))
|
|
|
+#endif
|
|
|
+
|
|
|
+#ifndef DT_EVENT_DETECT
|
|
|
+#define DT_EVENT_DETECT 1e-10
|
|
|
+#endif
|
|
|
+
|
|
|
+// ---------------------------------------------------------------------------
|
|
|
+// Private helpers used below to validate function arguments
|
|
|
+// ---------------------------------------------------------------------------
|
|
|
+
|
|
|
+static fmiBoolean invalidNumber(ModelInstance* comp, const char* f, const char* arg, int n, int nExpected){
|
|
|
+ if (n != nExpected) {
|
|
|
+ comp->state = modelError;
|
|
|
+ comp->functions.logger(comp, comp->instanceName, fmiError, "error",
|
|
|
+ "%s: Invalid argument %s = %d. Expected %d.", f, arg, n, nExpected);
|
|
|
+ return fmiTrue;
|
|
|
+ }
|
|
|
+ return fmiFalse;
|
|
|
+}
|
|
|
+
|
|
|
+static fmiBoolean invalidState(ModelInstance* comp, const char* f, int statesExpected){
|
|
|
+ if (!comp)
|
|
|
+ return fmiTrue;
|
|
|
+ if (!(comp->state & statesExpected)) {
|
|
|
+ comp->state = modelError;
|
|
|
+ comp->functions.logger(comp, comp->instanceName, fmiError, "error",
|
|
|
+ "%s: Illegal call sequence.", f);
|
|
|
+ return fmiTrue;
|
|
|
+ }
|
|
|
+ return fmiFalse;
|
|
|
+}
|
|
|
+
|
|
|
+static fmiBoolean nullPointer(ModelInstance* comp, const char* f, const char* arg, const void* p){
|
|
|
+ if (!p) {
|
|
|
+ comp->state = modelError;
|
|
|
+ comp->functions.logger(comp, comp->instanceName, fmiError, "error",
|
|
|
+ "%s: Invalid argument %s = NULL.", f, arg);
|
|
|
+ return fmiTrue;
|
|
|
+ }
|
|
|
+ return fmiFalse;
|
|
|
+}
|
|
|
+
|
|
|
+static fmiBoolean vrOutOfRange(ModelInstance* comp, const char* f, fmiValueReference vr, int end) {
|
|
|
+ if (vr >= end) {
|
|
|
+ comp->functions.logger(comp, comp->instanceName, fmiError, "error",
|
|
|
+ "%s: Illegal value reference %u.", f, vr);
|
|
|
+ comp->state = modelError;
|
|
|
+ return fmiTrue;
|
|
|
+ }
|
|
|
+ return fmiFalse;
|
|
|
+}
|
|
|
+
|
|
|
+// ---------------------------------------------------------------------------
|
|
|
+// Private helpers used below to implement functions
|
|
|
+// ---------------------------------------------------------------------------
|
|
|
+
|
|
|
+fmiStatus setString(fmiComponent comp, fmiValueReference vr, fmiString value){
|
|
|
+ return fmiSetString(comp, &vr, 1, &value);
|
|
|
+}
|
|
|
+
|
|
|
+// fname is fmiInstantiateModel or fmiInstantiateSlave
|
|
|
+static fmiComponent instantiateModel(char* fname, fmiString instanceName, fmiString GUID,
|
|
|
+ fmiCallbackFunctions functions, fmiBoolean loggingOn) {
|
|
|
+ ModelInstance* comp;
|
|
|
+ if (!functions.logger)
|
|
|
+ return NULL; // we cannot even log this problem
|
|
|
+ if (!instanceName || strlen(instanceName)==0) {
|
|
|
+ functions.logger(NULL, "?", fmiError, "error",
|
|
|
+ "%s: Missing instance name.", fname);
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+ if (!GUID || strlen(GUID)==0) {
|
|
|
+ functions.logger(NULL, instanceName, fmiError, "error",
|
|
|
+ "%s: Missing GUID.", fname);
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+ if (!functions.allocateMemory || !functions.freeMemory){
|
|
|
+ functions.logger(NULL, instanceName, fmiError, "error",
|
|
|
+ "%s: Missing callback function.", fname);
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+ if (strcmp(GUID, MODEL_GUID)) {
|
|
|
+ functions.logger(NULL, instanceName, fmiError, "error",
|
|
|
+ "%s: Wrong GUID %s. Expected %s.", fname, GUID, MODEL_GUID);
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+ comp = (ModelInstance *)functions.allocateMemory(1, sizeof(ModelInstance));
|
|
|
+ if (comp) {
|
|
|
+ comp->r = (fmiReal *)functions.allocateMemory(NUMBER_OF_REALS, sizeof(fmiReal));
|
|
|
+ comp->i = (fmiInteger *)functions.allocateMemory(NUMBER_OF_INTEGERS, sizeof(fmiInteger));
|
|
|
+ comp->b = (fmiBoolean *)functions.allocateMemory(NUMBER_OF_BOOLEANS, sizeof(fmiBoolean));
|
|
|
+ comp->s = (fmiString *)functions.allocateMemory(NUMBER_OF_STRINGS, sizeof(fmiString));
|
|
|
+ comp->isPositive = (fmiBoolean *)functions.allocateMemory(NUMBER_OF_EVENT_INDICATORS, sizeof(fmiBoolean));
|
|
|
+ comp->instanceName = (char *)functions.allocateMemory(1 + strlen(instanceName), sizeof(char));
|
|
|
+ comp->GUID = (char *)functions.allocateMemory(1 + strlen(GUID), sizeof(char));
|
|
|
+ }
|
|
|
+ if (!comp || !comp->r || !comp->i || !comp->b || !comp->s || !comp->isPositive
|
|
|
+ || !comp->instanceName || !comp->GUID) {
|
|
|
+ functions.logger(NULL, instanceName, fmiError, "error",
|
|
|
+ "%s: Out of memory.", fname);
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+ if (loggingOn) functions.logger(NULL, instanceName, fmiOK, "log",
|
|
|
+ "%s: GUID=%s", fname, GUID);
|
|
|
+
|
|
|
+ strcpy((char *)comp->instanceName, (char *)instanceName);
|
|
|
+ strcpy((char *)comp->GUID, (char *)GUID);
|
|
|
+ comp->functions = functions;
|
|
|
+ comp->loggingOn = loggingOn;
|
|
|
+ comp->state = modelInstantiated;
|
|
|
+ setStartValues(comp); // to be implemented by the includer of this file
|
|
|
+ return comp;
|
|
|
+}
|
|
|
+
|
|
|
+// fname is fmiInitialize or fmiInitializeSlave
|
|
|
+static fmiStatus init(char* fname, fmiComponent c, fmiBoolean toleranceControlled, fmiReal relativeTolerance,
|
|
|
+ fmiEventInfo* eventInfo) {
|
|
|
+ ModelInstance* comp = (ModelInstance *)c;
|
|
|
+ if (invalidState(comp, fname, modelInstantiated))
|
|
|
+ return fmiError;
|
|
|
+ if (nullPointer(comp, fname, "eventInfo", eventInfo))
|
|
|
+ return fmiError;
|
|
|
+ if (comp->loggingOn) comp->functions.logger(c, comp->instanceName, fmiOK, "log",
|
|
|
+ "%s: toleranceControlled=%d relativeTolerance=%g",
|
|
|
+ fname, toleranceControlled, relativeTolerance);
|
|
|
+ eventInfo->iterationConverged = fmiTrue;
|
|
|
+ eventInfo->stateValueReferencesChanged = fmiFalse;
|
|
|
+ eventInfo->stateValuesChanged = fmiFalse;
|
|
|
+ eventInfo->terminateSimulation = fmiFalse;
|
|
|
+ eventInfo->upcomingTimeEvent = fmiFalse;
|
|
|
+ initialize(comp, eventInfo); // to be implemented by the includer of this file
|
|
|
+ comp->state = modelInitialized;
|
|
|
+ return fmiOK;
|
|
|
+}
|
|
|
+
|
|
|
+// fname is fmiTerminate or fmiTerminateSlave
|
|
|
+static fmiStatus terminate(char* fname, fmiComponent c){
|
|
|
+ ModelInstance* comp = (ModelInstance *)c;
|
|
|
+ if (invalidState(comp, fname, modelInitialized))
|
|
|
+ return fmiError;
|
|
|
+ if (comp->loggingOn) comp->functions.logger(c, comp->instanceName, fmiOK, "log", fname);
|
|
|
+ comp->state = modelTerminated;
|
|
|
+ return fmiOK;
|
|
|
+}
|
|
|
+
|
|
|
+// fname is freeModelInstance of freeSlaveInstance
|
|
|
+void freeInstance(char* fname, fmiComponent c) {
|
|
|
+ ModelInstance* comp = (ModelInstance *)c;
|
|
|
+ if (!comp) return;
|
|
|
+ if (comp->loggingOn) comp->functions.logger(c, comp->instanceName, fmiOK, "log", fname);
|
|
|
+ if (comp->r) comp->functions.freeMemory(comp->r);
|
|
|
+ if (comp->i) comp->functions.freeMemory(comp->i);
|
|
|
+ if (comp->b) comp->functions.freeMemory(comp->b);
|
|
|
+ if (comp->s) {
|
|
|
+ int i;
|
|
|
+ for (i=0; i<NUMBER_OF_STRINGS; i++){
|
|
|
+ if (comp->s[i]) comp->functions.freeMemory((void *)comp->s[i]);
|
|
|
+ }
|
|
|
+ comp->functions.freeMemory((void *)comp->s);
|
|
|
+ }
|
|
|
+ if (comp->isPositive) comp->functions.freeMemory(comp->isPositive);
|
|
|
+ if (comp->instanceName) comp->functions.freeMemory((void *)comp->instanceName);
|
|
|
+ if (comp->GUID) comp->functions.freeMemory((void *)comp->GUID);
|
|
|
+ comp->functions.freeMemory(comp);
|
|
|
+}
|
|
|
+
|
|
|
+// ---------------------------------------------------------------------------
|
|
|
+// FMI functions: class methods not depending of a specific model instance
|
|
|
+// ---------------------------------------------------------------------------
|
|
|
+
|
|
|
+const char* fmiGetVersion() {
|
|
|
+ return fmiVersion;
|
|
|
+}
|
|
|
+
|
|
|
+// ---------------------------------------------------------------------------
|
|
|
+// FMI functions: for FMI Model Exchange 1.0 and for FMI Co-Simulation 1.0
|
|
|
+// logging control, setters and getters for Real, Integer, Boolean, String
|
|
|
+// ---------------------------------------------------------------------------
|
|
|
+
|
|
|
+fmiStatus fmiSetDebugLogging(fmiComponent c, fmiBoolean loggingOn) {
|
|
|
+ ModelInstance* comp = (ModelInstance *)c;
|
|
|
+ if (invalidState(comp, "fmiSetDebugLogging", not_modelError))
|
|
|
+ return fmiError;
|
|
|
+ if (comp->loggingOn) comp->functions.logger(c, comp->instanceName, fmiOK, "log",
|
|
|
+ "fmiSetDebugLogging: loggingOn=%d", loggingOn);
|
|
|
+ comp->loggingOn = loggingOn;
|
|
|
+ return fmiOK;
|
|
|
+}
|
|
|
+
|
|
|
+fmiStatus fmiSetReal(fmiComponent c, const fmiValueReference vr[], size_t nvr, const fmiReal value[]){
|
|
|
+ int i;
|
|
|
+ ModelInstance* comp = (ModelInstance *)c;
|
|
|
+ if (invalidState(comp, "fmiSetReal", modelInstantiated|modelInitialized))
|
|
|
+ return fmiError;
|
|
|
+ if (nvr>0 && nullPointer(comp, "fmiSetReal", "vr[]", vr))
|
|
|
+ return fmiError;
|
|
|
+ if (nvr>0 && nullPointer(comp, "fmiSetReal", "value[]", value))
|
|
|
+ return fmiError;
|
|
|
+ if (comp->loggingOn) comp->functions.logger(c, comp->instanceName, fmiOK, "log",
|
|
|
+ "fmiSetReal: nvr = %d", nvr);
|
|
|
+ // no check whether setting the value is allowed in the current state
|
|
|
+ for (i=0; i<nvr; i++) {
|
|
|
+ if (vrOutOfRange(comp, "fmiSetReal", vr[i], NUMBER_OF_REALS))
|
|
|
+ return fmiError;
|
|
|
+ if (comp->loggingOn) comp->functions.logger(c, comp->instanceName, fmiOK, "log",
|
|
|
+ "fmiSetReal: #r%d# = %.16g", vr[i], value[i]);
|
|
|
+ comp->r[vr[i]] = value[i];
|
|
|
+ }
|
|
|
+ return fmiOK;
|
|
|
+}
|
|
|
+
|
|
|
+fmiStatus fmiSetInteger(fmiComponent c, const fmiValueReference vr[], size_t nvr, const fmiInteger value[]){
|
|
|
+ int i;
|
|
|
+ ModelInstance* comp = (ModelInstance *)c;
|
|
|
+ if (invalidState(comp, "fmiSetInteger", modelInstantiated|modelInitialized))
|
|
|
+ return fmiError;
|
|
|
+ if (nvr>0 && nullPointer(comp, "fmiSetInteger", "vr[]", vr))
|
|
|
+ return fmiError;
|
|
|
+ if (nvr>0 && nullPointer(comp, "fmiSetInteger", "value[]", value))
|
|
|
+ return fmiError;
|
|
|
+ if (comp->loggingOn)
|
|
|
+ comp->functions.logger(c, comp->instanceName, fmiOK, "log", "fmiSetInteger: nvr = %d", nvr);
|
|
|
+ for (i=0; i<nvr; i++) {
|
|
|
+ if (vrOutOfRange(comp, "fmiSetInteger", vr[i], NUMBER_OF_INTEGERS))
|
|
|
+ return fmiError;
|
|
|
+ if (comp->loggingOn) comp->functions.logger(c, comp->instanceName, fmiOK, "log",
|
|
|
+ "fmiSetInteger: #i%d# = %d", vr[i], value[i]);
|
|
|
+ comp->i[vr[i]] = value[i];
|
|
|
+ }
|
|
|
+ return fmiOK;
|
|
|
+}
|
|
|
+
|
|
|
+fmiStatus fmiSetBoolean(fmiComponent c, const fmiValueReference vr[], size_t nvr, const fmiBoolean value[]){
|
|
|
+ int i;
|
|
|
+ ModelInstance* comp = (ModelInstance *)c;
|
|
|
+ if (invalidState(comp, "fmiSetBoolean", modelInstantiated|modelInitialized))
|
|
|
+ return fmiError;
|
|
|
+ if (nvr>0 && nullPointer(comp, "fmiSetBoolean", "vr[]", vr))
|
|
|
+ return fmiError;
|
|
|
+ if (nvr>0 && nullPointer(comp, "fmiSetBoolean", "value[]", value))
|
|
|
+ return fmiError;
|
|
|
+ if (comp->loggingOn)
|
|
|
+ comp->functions.logger(c, comp->instanceName, fmiOK, "log", "fmiSetBoolean: nvr = %d", nvr);
|
|
|
+ for (i=0; i<nvr; i++) {
|
|
|
+ if (vrOutOfRange(comp, "fmiSetBoolean", vr[i], NUMBER_OF_BOOLEANS))
|
|
|
+ return fmiError;
|
|
|
+ if (comp->loggingOn) comp->functions.logger(c, comp->instanceName, fmiOK, "log",
|
|
|
+ "fmiSetBoolean: #b%d# = %s", vr[i], value[i] ? "true" : "false");
|
|
|
+ comp->b[vr[i]] = value[i];
|
|
|
+ }
|
|
|
+ return fmiOK;
|
|
|
+}
|
|
|
+
|
|
|
+fmiStatus fmiSetString(fmiComponent c, const fmiValueReference vr[], size_t nvr, const fmiString value[]){
|
|
|
+ int i;
|
|
|
+ ModelInstance* comp = (ModelInstance *)c;
|
|
|
+ if (invalidState(comp, "fmiSetString", modelInstantiated|modelInitialized))
|
|
|
+ return fmiError;
|
|
|
+ if (nvr>0 && nullPointer(comp, "fmiSetString", "vr[]", vr))
|
|
|
+ return fmiError;
|
|
|
+ if (nvr>0 && nullPointer(comp, "fmiSetString", "value[]", value))
|
|
|
+ return fmiError;
|
|
|
+ if (comp->loggingOn)
|
|
|
+ comp->functions.logger(c, comp->instanceName, fmiOK, "log", "fmiSetString: nvr = %d", nvr);
|
|
|
+ for (i=0; i<nvr; i++) {
|
|
|
+ char *string = (char *)comp->s[vr[i]];
|
|
|
+ if (vrOutOfRange(comp, "fmiSetString", vr[i], NUMBER_OF_STRINGS))
|
|
|
+ return fmiError;
|
|
|
+ if (comp->loggingOn) comp->functions.logger(c, comp->instanceName, fmiOK, "log",
|
|
|
+ "fmiSetString: #s%d# = '%s'", vr[i], value[i]);
|
|
|
+ if (value[i] == NULL) {
|
|
|
+ if (string) comp->functions.freeMemory(string);
|
|
|
+ comp->s[vr[i]] = NULL;
|
|
|
+ comp->functions.logger(comp, comp->instanceName, fmiWarning, "warning",
|
|
|
+ "fmiSetString: string argument value[%d] = NULL.", i);
|
|
|
+ } else {
|
|
|
+ if (string==NULL || strlen(string) < strlen(value[i])) {
|
|
|
+ if (string) comp->functions.freeMemory(string);
|
|
|
+ comp->s[vr[i]] = (char *)comp->functions.allocateMemory(1+strlen(value[i]), sizeof(char));
|
|
|
+ if (!comp->s[vr[i]]) {
|
|
|
+ comp->state = modelError;
|
|
|
+ comp->functions.logger(NULL, comp->instanceName, fmiError, "error", "fmiSetString: Out of memory.");
|
|
|
+ return fmiError;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ strcpy((char *)comp->s[vr[i]], (char *)value[i]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return fmiOK;
|
|
|
+}
|
|
|
+
|
|
|
+fmiStatus fmiGetReal(fmiComponent c, const fmiValueReference vr[], size_t nvr, fmiReal value[]) {
|
|
|
+ int i;
|
|
|
+ ModelInstance* comp = (ModelInstance *)c;
|
|
|
+ if (invalidState(comp, "fmiGetReal", not_modelError))
|
|
|
+ return fmiError;
|
|
|
+ if (nvr>0 && nullPointer(comp, "fmiGetReal", "vr[]", vr))
|
|
|
+ return fmiError;
|
|
|
+ if (nvr>0 && nullPointer(comp, "fmiGetReal", "value[]", value))
|
|
|
+ return fmiError;
|
|
|
+#if NUMBER_OF_REALS>0
|
|
|
+ for (i=0; i<nvr; i++) {
|
|
|
+ if (vrOutOfRange(comp, "fmiGetReal", vr[i], NUMBER_OF_REALS))
|
|
|
+ return fmiError;
|
|
|
+ value[i] = getReal(comp, vr[i]); // to be implemented by the includer of this file
|
|
|
+ if (comp->loggingOn) comp->functions.logger(c, comp->instanceName, fmiOK, "log",
|
|
|
+ "fmiGetReal: #r%u# = %.16g", vr[i], value[i]);
|
|
|
+ }
|
|
|
+#endif
|
|
|
+ return fmiOK;
|
|
|
+}
|
|
|
+
|
|
|
+fmiStatus fmiGetInteger(fmiComponent c, const fmiValueReference vr[], size_t nvr, fmiInteger value[]) {
|
|
|
+ int i;
|
|
|
+ ModelInstance* comp = (ModelInstance *)c;
|
|
|
+ if (invalidState(comp, "fmiGetInteger", not_modelError))
|
|
|
+ return fmiError;
|
|
|
+ if (nvr>0 && nullPointer(comp, "fmiGetInteger", "vr[]", vr))
|
|
|
+ return fmiError;
|
|
|
+ if (nvr>0 && nullPointer(comp, "fmiGetInteger", "value[]", value))
|
|
|
+ return fmiError;
|
|
|
+ for (i=0; i<nvr; i++) {
|
|
|
+ if (vrOutOfRange(comp, "fmiGetInteger", vr[i], NUMBER_OF_INTEGERS))
|
|
|
+ return fmiError;
|
|
|
+ value[i] = comp->i[vr[i]];
|
|
|
+ if (comp->loggingOn) comp->functions.logger(c, comp->instanceName, fmiOK, "log",
|
|
|
+ "fmiGetInteger: #i%u# = %d", vr[i], value[i]);
|
|
|
+ }
|
|
|
+ return fmiOK;
|
|
|
+}
|
|
|
+
|
|
|
+fmiStatus fmiGetBoolean(fmiComponent c, const fmiValueReference vr[], size_t nvr, fmiBoolean value[]) {
|
|
|
+ int i;
|
|
|
+ ModelInstance* comp = (ModelInstance *)c;
|
|
|
+ if (invalidState(comp, "fmiGetBoolean", not_modelError))
|
|
|
+ return fmiError;
|
|
|
+ if (nvr>0 && nullPointer(comp, "fmiGetBoolean", "vr[]", vr))
|
|
|
+ return fmiError;
|
|
|
+ if (nvr>0 && nullPointer(comp, "fmiGetBoolean", "value[]", value))
|
|
|
+ return fmiError;
|
|
|
+ for (i=0; i<nvr; i++) {
|
|
|
+ if (vrOutOfRange(comp, "fmiGetBoolean", vr[i], NUMBER_OF_BOOLEANS))
|
|
|
+ return fmiError;
|
|
|
+ value[i] = comp->b[vr[i]];
|
|
|
+ if (comp->loggingOn) comp->functions.logger(c, comp->instanceName, fmiOK, "log",
|
|
|
+ "fmiGetBoolean: #b%u# = %s", vr[i], value[i]? "true" : "false");
|
|
|
+ }
|
|
|
+ return fmiOK;
|
|
|
+}
|
|
|
+
|
|
|
+fmiStatus fmiGetString(fmiComponent c, const fmiValueReference vr[], size_t nvr, fmiString value[]) {
|
|
|
+ int i;
|
|
|
+ ModelInstance* comp = (ModelInstance *)c;
|
|
|
+ if (invalidState(comp, "fmiGetString", not_modelError))
|
|
|
+ return fmiError;
|
|
|
+ if (nvr>0 && nullPointer(comp, "fmiGetString", "vr[]", vr))
|
|
|
+ return fmiError;
|
|
|
+ if (nvr>0 && nullPointer(comp, "fmiGetString", "value[]", value))
|
|
|
+ return fmiError;
|
|
|
+ for (i=0; i<nvr; i++) {
|
|
|
+ if (vrOutOfRange(comp, "fmiGetString", vr[i], NUMBER_OF_STRINGS))
|
|
|
+ return fmiError;
|
|
|
+ value[i] = comp->s[vr[i]];
|
|
|
+ if (comp->loggingOn) comp->functions.logger(c, comp->instanceName, fmiOK, "log",
|
|
|
+ "fmiGetString: #s%u# = '%s'", vr[i], value[i]);
|
|
|
+ }
|
|
|
+ return fmiOK;
|
|
|
+}
|
|
|
+
|
|
|
+#ifdef FMI_COSIMULATION
|
|
|
+// ---------------------------------------------------------------------------
|
|
|
+// FMI functions: only for FMI Co-Simulation 1.0
|
|
|
+// ---------------------------------------------------------------------------
|
|
|
+
|
|
|
+const char* fmiGetTypesPlatform() {
|
|
|
+ return fmiPlatform;
|
|
|
+}
|
|
|
+
|
|
|
+fmiComponent fmiInstantiateSlave(fmiString instanceName, fmiString GUID,
|
|
|
+ fmiString fmuLocation, fmiString mimeType, fmiReal timeout, fmiBoolean visible,
|
|
|
+ fmiBoolean interactive, fmiCallbackFunctions functions, fmiBoolean loggingOn) {
|
|
|
+ // ignoring arguments: fmuLocation, mimeType, timeout, visible, interactive
|
|
|
+ return instantiateModel("fmiInstantiateSlave", instanceName, GUID, functions, loggingOn);
|
|
|
+}
|
|
|
+
|
|
|
+fmiStatus fmiInitializeSlave(fmiComponent c, fmiReal tStart, fmiBoolean StopTimeDefined, fmiReal tStop) {
|
|
|
+ ModelInstance* comp = (ModelInstance *)c;
|
|
|
+ fmiBoolean toleranceControlled = fmiFalse;
|
|
|
+ fmiReal relativeTolerance = 0;
|
|
|
+ fmiStatus flag = fmiOK;
|
|
|
+ comp->eventInfo.iterationConverged = 0;
|
|
|
+ while (flag==fmiOK && !comp->eventInfo.iterationConverged) {
|
|
|
+ // ignoring arguments: tStart, StopTimeDefined, tStop
|
|
|
+ flag = init("fmiInitializeSlave", c, toleranceControlled, relativeTolerance, &comp->eventInfo);
|
|
|
+ }
|
|
|
+ return flag;
|
|
|
+}
|
|
|
+
|
|
|
+fmiStatus fmiTerminateSlave(fmiComponent c) {
|
|
|
+ return terminate("fmiTerminateSlave", c);
|
|
|
+}
|
|
|
+
|
|
|
+fmiStatus fmiResetSlave(fmiComponent c) {
|
|
|
+ ModelInstance* comp = (ModelInstance *)c;
|
|
|
+ if (invalidState(comp, "fmiResetSlave", modelInitialized))
|
|
|
+ return fmiError;
|
|
|
+ if (comp->loggingOn) comp->functions.logger(c, comp->instanceName, fmiOK, "log", "fmiResetSlave");
|
|
|
+ comp->state = modelInstantiated;
|
|
|
+ setStartValues(comp); // to be implemented by the includer of this file
|
|
|
+ return fmiOK;
|
|
|
+}
|
|
|
+
|
|
|
+void fmiFreeSlaveInstance(fmiComponent c) {
|
|
|
+ ModelInstance* comp = (ModelInstance *)c;
|
|
|
+ if (invalidState(comp, "fmiFreeSlaveInstance", modelTerminated))
|
|
|
+ return;
|
|
|
+ freeInstance("fmiFreeSlaveInstance", c);
|
|
|
+}
|
|
|
+
|
|
|
+fmiStatus fmiSetRealInputDerivatives(fmiComponent c, const fmiValueReference vr[], size_t nvr,
|
|
|
+ const fmiInteger order[], const fmiReal value[]) {
|
|
|
+ ModelInstance* comp = (ModelInstance *)c;
|
|
|
+ fmiCallbackLogger log = comp->functions.logger;
|
|
|
+ if (invalidState(comp, "fmiSetRealInputDerivatives", modelInitialized))
|
|
|
+ return fmiError;
|
|
|
+ if (comp->loggingOn) log(c, comp->instanceName, fmiOK, "log", "fmiSetRealInputDerivatives: nvr= %d", nvr);
|
|
|
+ log(c, comp->instanceName, fmiError, "warning", "fmiSetRealInputDerivatives: ignoring function call."
|
|
|
+ " This model cannot interpolate inputs: canInterpolateInputs=\"fmiFalse\"");
|
|
|
+ return fmiWarning;
|
|
|
+}
|
|
|
+
|
|
|
+fmiStatus fmiGetRealOutputDerivatives(fmiComponent c, const fmiValueReference vr[], size_t nvr,
|
|
|
+ const fmiInteger order[], fmiReal value[]) {
|
|
|
+ int i;
|
|
|
+ ModelInstance* comp = (ModelInstance *)c;
|
|
|
+ fmiCallbackLogger log = comp->functions.logger;
|
|
|
+ if (invalidState(comp, "fmiGetRealOutputDerivatives", modelInitialized))
|
|
|
+ return fmiError;
|
|
|
+ if (comp->loggingOn) log(c, comp->instanceName, fmiOK, "log", "fmiGetRealOutputDerivatives: nvr= %d", nvr);
|
|
|
+ log(c, comp->instanceName, fmiError, "warning", "fmiGetRealOutputDerivatives: ignoring function call."
|
|
|
+ " This model cannot compute derivatives of outputs: MaxOutputDerivativeOrder=\"0\"");
|
|
|
+ for (i=0; i<nvr; i++) value[i] = 0;
|
|
|
+ return fmiWarning;
|
|
|
+}
|
|
|
+
|
|
|
+fmiStatus fmiCancelStep(fmiComponent c) {
|
|
|
+ ModelInstance* comp = (ModelInstance *)c;
|
|
|
+ fmiCallbackLogger log = comp->functions.logger;
|
|
|
+ if (invalidState(comp, "fmiCancelStep", modelInitialized))
|
|
|
+ return fmiError;
|
|
|
+ if (comp->loggingOn) log(c, comp->instanceName, fmiOK, "log", "fmiCancelStep");
|
|
|
+ log(c, comp->instanceName, fmiError, "error",
|
|
|
+ "fmiCancelStep: Can be called when fmiDoStep returned fmiPending."
|
|
|
+ " This is not the case.");
|
|
|
+ return fmiError;
|
|
|
+}
|
|
|
+
|
|
|
+fmiStatus fmiDoStep(fmiComponent c, fmiReal currentCommunicationPoint,
|
|
|
+ fmiReal communicationStepSize, fmiBoolean newStep) {
|
|
|
+ ModelInstance* comp = (ModelInstance *)c;
|
|
|
+ fmiCallbackLogger log = comp->functions.logger;
|
|
|
+ double h = communicationStepSize / 10;
|
|
|
+ int k,i;
|
|
|
+ const int n = 10; // how many Euler steps to perform for one do step
|
|
|
+ double prevState[max(NUMBER_OF_STATES, 1)];
|
|
|
+ double prevEventIndicators[max(NUMBER_OF_EVENT_INDICATORS, 1)];
|
|
|
+ int stateEvent = 0;
|
|
|
+
|
|
|
+ if (invalidState(comp, "fmiDoStep", modelInitialized))
|
|
|
+ return fmiError;
|
|
|
+
|
|
|
+ if (comp->loggingOn) log(c, comp->instanceName, fmiOK, "log", "fmiDoStep: "
|
|
|
+ "currentCommunicationPoint = %g, "
|
|
|
+ "communicationStepSize = %g, "
|
|
|
+ "newStep = fmi%s",
|
|
|
+ currentCommunicationPoint, communicationStepSize, newStep ? "True" : "False");
|
|
|
+
|
|
|
+ // Treat also case of zero step, i.e. during an event iteration
|
|
|
+ if (communicationStepSize == 0) {
|
|
|
+ return fmiOK;
|
|
|
+ }
|
|
|
+
|
|
|
+#if NUMBER_OF_EVENT_INDICATORS>0
|
|
|
+ // initialize previous event indicators with current values
|
|
|
+ for (i=0; i<NUMBER_OF_EVENT_INDICATORS; i++) {
|
|
|
+ prevEventIndicators[i] = getEventIndicator(comp, i);
|
|
|
+ }
|
|
|
+#endif
|
|
|
+
|
|
|
+ // break the step into n steps and do forward Euler.
|
|
|
+ comp->time = currentCommunicationPoint;
|
|
|
+ for (k=0; k<n; k++) {
|
|
|
+ comp->time += h;
|
|
|
+
|
|
|
+#if NUMBER_OF_STATES>0
|
|
|
+ for (i=0; i<NUMBER_OF_STATES; i++) {
|
|
|
+ prevState[i] = r(vrStates[i]);
|
|
|
+ }
|
|
|
+ for (i=0; i<NUMBER_OF_STATES; i++) {
|
|
|
+ fmiValueReference vr = vrStates[i];
|
|
|
+ r(vr) += h * getReal(comp, vr+1); // forward Euler step
|
|
|
+ }
|
|
|
+#endif
|
|
|
+
|
|
|
+#if NUMBER_OF_EVENT_INDICATORS>0
|
|
|
+ // check for state event
|
|
|
+ for (i=0; i<NUMBER_OF_EVENT_INDICATORS; i++) {
|
|
|
+ double ei = getEventIndicator(comp, i);
|
|
|
+ if (ei * prevEventIndicators[i] < 0) {
|
|
|
+ if (comp->loggingOn) comp->functions.logger(c, comp->instanceName, fmiOK, "log",
|
|
|
+ "fmiDoStep: state event at %g, z%d crosses zero -%c-", comp->time, i, ei<0 ? '\\' : '/');
|
|
|
+ stateEvent++;
|
|
|
+ }
|
|
|
+ prevEventIndicators[i] = ei;
|
|
|
+ }
|
|
|
+ if (stateEvent) {
|
|
|
+ eventUpdate(comp, &comp->eventInfo);
|
|
|
+ stateEvent = 0;
|
|
|
+ }
|
|
|
+#endif
|
|
|
+ // check for time event
|
|
|
+ if (comp->eventInfo.upcomingTimeEvent && (comp->time - comp->eventInfo.nextEventTime > -DT_EVENT_DETECT)) {
|
|
|
+ if (comp->loggingOn) comp->functions.logger(c, comp->instanceName, fmiOK, "log",
|
|
|
+ "fmiDoStep: time event detected at %g", comp->time);
|
|
|
+ eventUpdate(comp, &comp->eventInfo);
|
|
|
+ }
|
|
|
+
|
|
|
+ // terminate simulation, if requested by the model
|
|
|
+ if (comp->eventInfo.terminateSimulation) {
|
|
|
+ comp->functions.logger(c, comp->instanceName, fmiOK, "log",
|
|
|
+ "fmiDoStep: model requested termination at t=%g", comp->time);
|
|
|
+ return fmiError; // enforce termination of the simulation loop
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return fmiOK;
|
|
|
+}
|
|
|
+
|
|
|
+static fmiStatus getStatus(char* fname, fmiComponent c, const fmiStatusKind s) {
|
|
|
+ const char* statusKind[3] = {"fmiDoStepStatus","fmiPendingStatus","fmiLastSuccessfulTime"};
|
|
|
+ ModelInstance* comp = (ModelInstance *)c;
|
|
|
+ fmiCallbackLogger log = comp->functions.logger;
|
|
|
+ if (invalidState(comp, fname, modelInstantiated|modelInitialized))
|
|
|
+ return fmiError;
|
|
|
+ if (comp->loggingOn) log(c, comp->instanceName, fmiOK, "log", "$s: fmiStatusKind = %s", fname, statusKind[s]);
|
|
|
+ switch(s) {
|
|
|
+ case fmiDoStepStatus: log(c, comp->instanceName, fmiError, "error",
|
|
|
+ "%s: Can be called with fmiDoStepStatus when fmiDoStep returned fmiPending."
|
|
|
+ " This is not the case.", fname);
|
|
|
+ break;
|
|
|
+ case fmiPendingStatus: log(c, comp->instanceName, fmiError, "error",
|
|
|
+ "%s: Can be called with fmiPendingStatus when fmiDoStep returned fmiPending."
|
|
|
+ " This is not the case.", fname);
|
|
|
+ break;
|
|
|
+ case fmiLastSuccessfulTime: log(c, comp->instanceName, fmiError, "error",
|
|
|
+ "%s: Can be called with fmiLastSuccessfulTime when fmiDoStep returned fmiDiscard."
|
|
|
+ " This is not the case.", fname);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ return fmiError;
|
|
|
+}
|
|
|
+
|
|
|
+fmiStatus fmiGetStatus(fmiComponent c, const fmiStatusKind s, fmiStatus* value) {
|
|
|
+ return getStatus("fmiGetStatus", c, s);
|
|
|
+}
|
|
|
+
|
|
|
+fmiStatus fmiGetRealStatus(fmiComponent c, const fmiStatusKind s, fmiReal* value){
|
|
|
+ return getStatus("fmiGetRealStatus", c, s);
|
|
|
+}
|
|
|
+
|
|
|
+fmiStatus fmiGetIntegerStatus(fmiComponent c, const fmiStatusKind s, fmiInteger* value){
|
|
|
+ return getStatus("fmiGetIntegerStatus", c, s);
|
|
|
+}
|
|
|
+
|
|
|
+fmiStatus fmiGetBooleanStatus(fmiComponent c, const fmiStatusKind s, fmiBoolean* value){
|
|
|
+ return getStatus("fmiGetBooleanStatus", c, s);
|
|
|
+}
|
|
|
+
|
|
|
+fmiStatus fmiGetStringStatus(fmiComponent c, const fmiStatusKind s, fmiString* value){
|
|
|
+ return getStatus("fmiGetStringStatus", c, s);
|
|
|
+}
|
|
|
+
|
|
|
+#else
|
|
|
+// ---------------------------------------------------------------------------
|
|
|
+// FMI functions: only for Model Exchange 1.0
|
|
|
+// ---------------------------------------------------------------------------
|
|
|
+
|
|
|
+const char* fmiGetModelTypesPlatform() {
|
|
|
+ return fmiModelTypesPlatform;
|
|
|
+}
|
|
|
+
|
|
|
+fmiComponent fmiInstantiateModel(fmiString instanceName, fmiString GUID,
|
|
|
+ fmiCallbackFunctions functions, fmiBoolean loggingOn) {
|
|
|
+ return instantiateModel("fmiInstantiateModel", instanceName, GUID, functions, loggingOn);
|
|
|
+}
|
|
|
+
|
|
|
+fmiStatus fmiInitialize(fmiComponent c, fmiBoolean toleranceControlled, fmiReal relativeTolerance,
|
|
|
+ fmiEventInfo* eventInfo) {
|
|
|
+ return init("fmiInitialize", c, toleranceControlled, relativeTolerance, eventInfo);
|
|
|
+}
|
|
|
+
|
|
|
+fmiStatus fmiSetTime(fmiComponent c, fmiReal time) {
|
|
|
+ ModelInstance* comp = (ModelInstance *)c;
|
|
|
+ if (invalidState(comp, "fmiSetTime", modelInstantiated|modelInitialized))
|
|
|
+ return fmiError;
|
|
|
+ if (comp->loggingOn) comp->functions.logger(c, comp->instanceName, fmiOK, "log",
|
|
|
+ "fmiSetTime: time=%.16g", time);
|
|
|
+ comp->time = time;
|
|
|
+ return fmiOK;
|
|
|
+}
|
|
|
+
|
|
|
+fmiStatus fmiSetContinuousStates(fmiComponent c, const fmiReal x[], size_t nx){
|
|
|
+ ModelInstance* comp = (ModelInstance *)c;
|
|
|
+ int i;
|
|
|
+ if (invalidState(comp, "fmiSetContinuousStates", modelInitialized))
|
|
|
+ return fmiError;
|
|
|
+ if (invalidNumber(comp, "fmiSetContinuousStates", "nx", nx, NUMBER_OF_STATES))
|
|
|
+ return fmiError;
|
|
|
+ if (nullPointer(comp, "fmiSetContinuousStates", "x[]", x))
|
|
|
+ return fmiError;
|
|
|
+#if NUMBER_OF_STATES>0
|
|
|
+ for (i=0; i<nx; i++) {
|
|
|
+ fmiValueReference vr = vrStates[i];
|
|
|
+ if (comp->loggingOn) comp->functions.logger(c, comp->instanceName, fmiOK, "log",
|
|
|
+ "fmiSetContinuousStates: #r%d#=%.16g", vr, x[i]);
|
|
|
+ assert(vr<NUMBER_OF_REALS);
|
|
|
+ comp->r[vr] = x[i];
|
|
|
+ }
|
|
|
+#endif
|
|
|
+ return fmiOK;
|
|
|
+}
|
|
|
+
|
|
|
+fmiStatus fmiEventUpdate(fmiComponent c, fmiBoolean intermediateResults, fmiEventInfo* eventInfo) {
|
|
|
+ ModelInstance* comp = (ModelInstance *)c;
|
|
|
+ if (invalidState(comp, "fmiEventUpdate", modelInitialized))
|
|
|
+ return fmiError;
|
|
|
+ if (nullPointer(comp, "fmiEventUpdate", "eventInfo", eventInfo))
|
|
|
+ return fmiError;
|
|
|
+ if (comp->loggingOn) comp->functions.logger(c, comp->instanceName, fmiOK, "log",
|
|
|
+ "fmiEventUpdate: intermediateResults = %d", intermediateResults);
|
|
|
+ eventInfo->iterationConverged = fmiTrue;
|
|
|
+ eventInfo->stateValueReferencesChanged = fmiFalse;
|
|
|
+ eventInfo->stateValuesChanged = fmiFalse;
|
|
|
+ eventInfo->terminateSimulation = fmiFalse;
|
|
|
+ eventInfo->upcomingTimeEvent = fmiFalse;
|
|
|
+ eventUpdate(comp, eventInfo); // to be implemented by the includer of this file
|
|
|
+ return fmiOK;
|
|
|
+}
|
|
|
+
|
|
|
+fmiStatus fmiCompletedIntegratorStep(fmiComponent c, fmiBoolean* callEventUpdate){
|
|
|
+ ModelInstance* comp = (ModelInstance *)c;
|
|
|
+ if (invalidState(comp, "fmiCompletedIntegratorStep", modelInitialized))
|
|
|
+ return fmiError;
|
|
|
+ if (nullPointer(comp, "fmiCompletedIntegratorStep", "callEventUpdate", callEventUpdate))
|
|
|
+ return fmiError;
|
|
|
+ if (comp->loggingOn) comp->functions.logger(c, comp->instanceName, fmiOK, "log",
|
|
|
+ "fmiCompletedIntegratorStep");
|
|
|
+ *callEventUpdate = fmiFalse;
|
|
|
+ return fmiOK;
|
|
|
+}
|
|
|
+
|
|
|
+fmiStatus fmiGetStateValueReferences(fmiComponent c, fmiValueReference vrx[], size_t nx){
|
|
|
+ int i;
|
|
|
+ ModelInstance* comp = (ModelInstance *)c;
|
|
|
+ if (invalidState(comp, "fmiGetStateValueReferences", not_modelError))
|
|
|
+ return fmiError;
|
|
|
+ if (invalidNumber(comp, "fmiGetStateValueReferences", "nx", nx, NUMBER_OF_STATES))
|
|
|
+ return fmiError;
|
|
|
+ if (nullPointer(comp, "fmiGetStateValueReferences", "vrx[]", vrx))
|
|
|
+ return fmiError;
|
|
|
+#if NUMBER_OF_STATES>0
|
|
|
+ for (i=0; i<nx; i++) {
|
|
|
+ vrx[i] = vrStates[i];
|
|
|
+ if (comp->loggingOn) comp->functions.logger(c, comp->instanceName, fmiOK, "log",
|
|
|
+ "fmiGetStateValueReferences: vrx[%d] = %d", i, vrx[i]);
|
|
|
+ }
|
|
|
+#endif
|
|
|
+ return fmiOK;
|
|
|
+}
|
|
|
+
|
|
|
+fmiStatus fmiGetContinuousStates(fmiComponent c, fmiReal states[], size_t nx){
|
|
|
+ int i;
|
|
|
+ ModelInstance* comp = (ModelInstance *)c;
|
|
|
+ if (invalidState(comp, "fmiGetContinuousStates", not_modelError))
|
|
|
+ return fmiError;
|
|
|
+ if (invalidNumber(comp, "fmiGetContinuousStates", "nx", nx, NUMBER_OF_STATES))
|
|
|
+ return fmiError;
|
|
|
+ if (nullPointer(comp, "fmiGetContinuousStates", "states[]", states))
|
|
|
+ return fmiError;
|
|
|
+#if NUMBER_OF_STATES>0
|
|
|
+ for (i=0; i<nx; i++) {
|
|
|
+ fmiValueReference vr = vrStates[i];
|
|
|
+ states[i] = getReal(comp, vr); // to be implemented by the includer of this file
|
|
|
+ if (comp->loggingOn) comp->functions.logger(c, comp->instanceName, fmiOK, "log",
|
|
|
+ "fmiGetContinuousStates: #r%u# = %.16g", vr, states[i]);
|
|
|
+ }
|
|
|
+#endif
|
|
|
+ return fmiOK;
|
|
|
+}
|
|
|
+
|
|
|
+fmiStatus fmiGetNominalContinuousStates(fmiComponent c, fmiReal x_nominal[], size_t nx){
|
|
|
+ int i;
|
|
|
+ ModelInstance* comp = (ModelInstance *)c;
|
|
|
+ if (invalidState(comp, "fmiGetNominalContinuousStates", not_modelError))
|
|
|
+ return fmiError;
|
|
|
+ if (invalidNumber(comp, "fmiGetNominalContinuousStates", "nx", nx, NUMBER_OF_STATES))
|
|
|
+ return fmiError;
|
|
|
+ if (nullPointer(comp, "fmiGetNominalContinuousStates", "x_nominal[]", x_nominal))
|
|
|
+ return fmiError;
|
|
|
+ if (comp->loggingOn) comp->functions.logger(c, comp->instanceName, fmiOK, "log",
|
|
|
+ "fmiGetNominalContinuousStates: x_nominal[0..%d] = 1.0", nx-1);
|
|
|
+ for (i=0; i<nx; i++)
|
|
|
+ x_nominal[i] = 1;
|
|
|
+ return fmiOK;
|
|
|
+}
|
|
|
+
|
|
|
+fmiStatus fmiGetDerivatives(fmiComponent c, fmiReal derivatives[], size_t nx) {
|
|
|
+ int i;
|
|
|
+ ModelInstance* comp = (ModelInstance *)c;
|
|
|
+ if (invalidState(comp, "fmiGetDerivatives", not_modelError))
|
|
|
+ return fmiError;
|
|
|
+ if (invalidNumber(comp, "fmiGetDerivatives", "nx", nx, NUMBER_OF_STATES))
|
|
|
+ return fmiError;
|
|
|
+ if (nullPointer(comp, "fmiGetDerivatives", "derivatives[]", derivatives))
|
|
|
+ return fmiError;
|
|
|
+#if NUMBER_OF_STATES>0
|
|
|
+ for (i=0; i<nx; i++) {
|
|
|
+ fmiValueReference vr = vrStates[i] + 1;
|
|
|
+ derivatives[i] = getReal(comp, vr); // to be implemented by the includer of this file
|
|
|
+ if (comp->loggingOn) comp->functions.logger(c, comp->instanceName, fmiOK, "log",
|
|
|
+ "fmiGetDerivatives: #r%d# = %.16g", vr, derivatives[i]);
|
|
|
+ }
|
|
|
+#endif
|
|
|
+ return fmiOK;
|
|
|
+}
|
|
|
+
|
|
|
+fmiStatus fmiGetEventIndicators(fmiComponent c, fmiReal eventIndicators[], size_t ni) {
|
|
|
+ int i;
|
|
|
+ ModelInstance* comp = (ModelInstance *)c;
|
|
|
+ if (invalidState(comp, "fmiGetEventIndicators", not_modelError))
|
|
|
+ return fmiError;
|
|
|
+ if (invalidNumber(comp, "fmiGetEventIndicators", "ni", ni, NUMBER_OF_EVENT_INDICATORS))
|
|
|
+ return fmiError;
|
|
|
+#if NUMBER_OF_EVENT_INDICATORS>0
|
|
|
+ for (i=0; i<ni; i++) {
|
|
|
+ eventIndicators[i] = getEventIndicator(comp, i); // to be implemented by the includer of this file
|
|
|
+ if (comp->loggingOn) comp->functions.logger(c, comp->instanceName, fmiOK, "log",
|
|
|
+ "fmiGetEventIndicators: z%d = %.16g", i, eventIndicators[i]);
|
|
|
+ }
|
|
|
+#endif
|
|
|
+ return fmiOK;
|
|
|
+}
|
|
|
+
|
|
|
+fmiStatus fmiTerminate(fmiComponent c){
|
|
|
+ return terminate("fmiTerminate", c);
|
|
|
+}
|
|
|
+
|
|
|
+void fmiFreeModelInstance(fmiComponent c) {
|
|
|
+ freeInstance("fmiFreeModelInstance", c);
|
|
|
+}
|
|
|
+
|
|
|
+#endif // Model Exchange 1.0
|
|
|
+
|
|
|
+#ifdef __cplusplus
|
|
|
+} // closing brace for extern "C"
|
|
|
+#endif
|