Eclipse SUMO - Simulation of Urban MObility
fmi2Functions.c
Go to the documentation of this file.
1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 // Copyright (C) 2020-2024 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials are made available under the
5 // terms of the Eclipse Public License 2.0 which is available at
6 // https://www.eclipse.org/legal/epl-2.0/
7 // This Source Code may also be made available under the following Secondary
8 // Licenses when the conditions for such availability set forth in the Eclipse
9 // Public License 2.0 are satisfied: GNU General Public License, version 2
10 // or later which is available at
11 // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 /****************************************************************************/
19 // Implementation of the FMI2 interface functions
20 /****************************************************************************/
21 
22 #ifdef _MSC_VER
23 // Avoid warnings in windows build because of strcpy instead of strcpy_s,
24 // because the latter is not available on all platforms
25 #define _CRT_SECURE_NO_WARNINGS
26 #pragma warning(disable:4820 4514 5045)
27 #endif
28 
29 #include <string.h>
30 #include <stdio.h>
31 #include <stdarg.h>
33 #include "sumo2fmi_bridge.h"
34 #include "libsumocpp2c.h"
35 
36 /* Explicit definition of unused parameters to avoid compiler warnings */
37 #define UNREFERENCED_PARAMETER(P) (P)
38 
39 /* **********************************************************************************************
40  * * IMPLEMENTATION OF GENERIC FUNCTIONALITY
41  * **********************************************************************************************/
42 const char* fmi2GetTypesPlatform(void) {
43  return fmi2TypesPlatform;
44 }
45 
46 const char* fmi2GetVersion(void) {
47  return fmi2Version;
48 }
49 
50 /* ***********************************************************************************************
51  * CREATION AND DESTRUCTION OF AN FMU
52  ***********************************************************************************************/
53 
54 /* Define what should be logged - if logging is enabled globally */
56 fmi2SetDebugLogging(fmi2Component c, fmi2Boolean loggingOn, size_t nCategories, const fmi2String categories[]) {
57 
58  ModelInstance* comp = (ModelInstance*)c;
59 
60  if (loggingOn) {
61  size_t i;
62  for (i = 0; i < nCategories; i++) {
63  if (categories[i] == NULL) {
64  sumo2fmi_logError(comp, "Log category[%d] must not be NULL", i);
65  return fmi2Error;
66  } else if (strcmp(categories[i], "logStatusError") == 0) {
67  comp->logErrors = true;
68  } else if (strcmp(categories[i], "logEvents") == 0) {
69  comp->logEvents = true;
70  } else {
71  sumo2fmi_logError(comp, "Log category[%d] must be one of logEvents or logStatusError but was %s", i, categories[i]);
72  return fmi2Error;
73  }
74  }
75  } else {
76  // Logging is disabled globally, no need for a more fine grained logging
77  comp->logEvents = false;
78  comp->logErrors = false;
79  }
80 
81  return fmi2OK;
82 }
83 
84 /* The function returns a new instance of an FMU. If a null pointer is returned, then instantiation
85  failed.*/
87 fmi2Instantiate(fmi2String instanceName, fmi2Type fmuType, fmi2String fmuGUID,
88  fmi2String fmuResourceLocation, const fmi2CallbackFunctions* functions,
89  fmi2Boolean visible, fmi2Boolean loggingOn) {
90  UNREFERENCED_PARAMETER(fmuType);
91  UNREFERENCED_PARAMETER(fmuGUID);
92  UNREFERENCED_PARAMETER(visible);
93 
94  allocateMemoryType funcAllocateMemory = (allocateMemoryType)functions->allocateMemory;
95  ModelInstance* comp = (ModelInstance*) funcAllocateMemory(1, sizeof(ModelInstance));
96 
97  if (comp) {
98  comp->componentEnvironment = functions->componentEnvironment;
99 
100  /* Callback functions for specific logging, malloc and free;
101  we need callback functions because we cannot know, which functions
102  the environment will provide for us */
103  comp->logger = (loggerType)functions->logger;
104  comp->allocateMemory = (allocateMemoryType)functions->allocateMemory;
105  comp->freeMemory = (freeMemoryType)functions->freeMemory;
106 
107  comp->instanceName = (char*)comp->allocateMemory(1 + strlen(instanceName), sizeof(char));
108  strcpy((char*)comp->instanceName, (char*)instanceName);
109 
110  if (fmuResourceLocation) {
111  comp->resourceLocation = (char*)comp->allocateMemory(1 + strlen(fmuResourceLocation), sizeof(char));
112  strcpy((char*)comp->resourceLocation, (char*)fmuResourceLocation);
113  } else {
114  comp->resourceLocation = NULL;
115  }
116 
117  comp->logEvents = loggingOn;
118  comp->logErrors = true; // always log errors
119  }
120 
121  return comp;
122 }
123 
124 /* Disposes the given instance, unloads the loaded model, and frees all the allocated memory
125 and other resources that have been allocated by the functions of the FMU interface. */
126 void
128  ModelInstance* comp = (ModelInstance*)c;
129 
130  /* Store the pointer to the freeMemory function, because we
131  are going to free comp as well */
132  freeMemoryType freeMemoryFunc = comp->freeMemory;
133 
134  /* We want to free everything that we allocated in fmi2Instantiate */
135  freeMemoryFunc((void*)comp->instanceName);
136  freeMemoryFunc((void*)comp->resourceLocation);
137  freeMemoryFunc((void*)comp->libsumoCallOptions);
138  freeMemoryFunc((void*)comp->getterParameters);
139  int i;
140  for (i = 0; i < comp->bufferArrayLength; i++) {
141  freeMemoryFunc((void*)comp->bufferArray[i]);
142  }
143  freeMemoryFunc((void*)comp->bufferArray);
144  freeMemoryFunc((void*)comp);
145 }
146 
148 fmi2SetupExperiment(fmi2Component c, fmi2Boolean toleranceDefined, fmi2Real tolerance,
149  fmi2Real startTime, fmi2Boolean stopTimeDefined, fmi2Real stopTime) {
150 
151  UNREFERENCED_PARAMETER(toleranceDefined);
152  UNREFERENCED_PARAMETER(tolerance);
153  UNREFERENCED_PARAMETER(stopTimeDefined);
154 
155  // ignore arguments: toleranceDefined, tolerance
156  ModelInstance* comp = (ModelInstance*)c;
157 
158  // Store the start and stop times of the experiment
159  comp->startTime = startTime;
160  comp->stopTime = stopTime;
161 
163 
164  return fmi2OK;
165 }
166 
167 // Will be called after instantiation and after initial variables have been set
171 
172  return fmi2OK;
173 }
174 
175 // Informs the FMU to exit Initialization Mode
178  ModelInstance* comp = (ModelInstance*)c;
179 
180  sumo2fmi_logEvent(comp, "Calling libsumo with the following options: \"%s\"", comp->libsumoCallOptions);
182 
183  return fmi2OK;
184 }
185 
186 // Informs the FMU that the simulation run is terminated
187 // --> let libsumo know, that we want to close the simulation
191 
192  libsumo_close();
193  return fmi2OK;
194 }
195 
196 // Is called by the environment to reset the FMU after a simulation run
200 
201  // Should we set some start values?
202  return fmi2OK;
203 }
204 
205 // Implementation of the getter features
207 fmi2GetReal(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, fmi2Real value[]) {
211  UNREFERENCED_PARAMETER(value);
212 
213  return fmi2Error;
214 }
215 
217 fmi2GetInteger(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, fmi2Integer value[]) {
218 
219  ModelInstance* comp = (ModelInstance*)c;
220 
221  // Check for null pointer errors
222  if (nvr > 0 && (!vr || !value)) {
223  return fmi2Error;
224  }
225 
226  fmi2Status status = fmi2OK;
227 
228  // Go through the list of arrays and save all requested values
229  size_t i;
230  for (i = 0; i < nvr; i++) {
231  fmi2Status s = sumo2fmi_getInteger(comp, vr[i], &(value[i]));
232  status = s > status ? s : status;
233 
234  if (status > fmi2Warning) {
235  return status;
236  }
237  }
238 
239  return status;
240 }
241 
243 fmi2GetBoolean(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, fmi2Boolean value[]) {
247  UNREFERENCED_PARAMETER(value);
248 
249  return fmi2Error;
250 }
251 
253 fmi2GetString(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, fmi2String value[]) {
254 
255  ModelInstance* comp = (ModelInstance*)c;
256 
257  // Check for null pointer errors
258  if (nvr > 0 && (!vr || !value)) {
259  return fmi2Error;
260  }
261 
262  fmi2Status status = fmi2OK;
263 
265  int b;
266  for (b = 0; b < comp->bufferArrayLength; b++) {
267  comp->freeMemory((void*)comp->bufferArray[b]);
268  }
269  comp->freeMemory((void*)comp->bufferArray);
270  comp->bufferArray = (fmi2String*)comp->allocateMemory(nvr, sizeof(fmi2String));
271  comp->bufferArrayLength = (int)nvr;
272 
273  // Go through the list of arrays and save all requested values
274  size_t i;
275  for (i = 0; i < nvr; i++) {
276  fmi2Status s = sumo2fmi_getString(comp, vr[i], &(comp->bufferArray[i]));
277  value[i] = comp->bufferArray[i];
278  if (value[i] == NULL) {
279  s = fmi2Error;
280  }
281 
282  status = s > status ? s : status;
283  if (status > fmi2Warning) {
284  return status;
285  }
286  }
287 
288  return status;
289 }
290 
291 // Implementation of the setter features
293 fmi2SetReal(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2Real value[]) {
297  UNREFERENCED_PARAMETER(value);
298  return fmi2Error;
299 }
300 
302 fmi2SetInteger(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2Integer value[]) {
306  UNREFERENCED_PARAMETER(value);
307 
308  return fmi2Error;
309 }
310 
312 fmi2SetBoolean(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2Boolean value[]) {
316  UNREFERENCED_PARAMETER(value);
317 
318  return fmi2Error;
319 }
320 
322 fmi2SetString(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2String value[]) {
323 
324  ModelInstance* comp = (ModelInstance*)c;
325  fmi2Status status = fmi2OK;
326 
327  size_t i;
328  for (i = 0; i < nvr; i++) {
329  fmi2Status s = sumo2fmi_setString(comp, vr[i], value[i]);
330  status = s > status ? s : status;
331  if (status > fmi2Warning) {
332  return status;
333  }
334  }
335 
336  return status;
337 }
338 
342  UNREFERENCED_PARAMETER(FMUstate);
343  return fmi2Error; /* Dummy implementation */
344 }
345 
349  UNREFERENCED_PARAMETER(FMUstate);
350  return fmi2Error; /* Dummy implementation */
351 }
352 
356  UNREFERENCED_PARAMETER(FMUstate);
357  return fmi2Error; /* Dummy implementation */
358 }
359 
363  UNREFERENCED_PARAMETER(FMUstate);
365  return fmi2Error; /* Dummy implementation */
366 }
367 
369 fmi2SerializeFMUstate(fmi2Component c, fmi2FMUstate FMUstate, fmi2Byte state[], size_t size) {
371  UNREFERENCED_PARAMETER(FMUstate);
372  UNREFERENCED_PARAMETER(state);
374  return fmi2Error; /* Dummy implementation */
375 }
376 
378 fmi2DeSerializeFMUstate(fmi2Component c, const fmi2Byte serializedState[], size_t size, fmi2FMUstate* FMUstate) {
380  UNREFERENCED_PARAMETER(serializedState);
382  UNREFERENCED_PARAMETER(FMUstate);
383  return fmi2Error; /* Dummy implementation */
384 }
385 
387 fmi2GetDirectionalDerivative(fmi2Component c, const fmi2ValueReference vUnknown_ref[], size_t nUnknown,
388  const fmi2ValueReference vKnown_ref[], size_t nKnown, const fmi2Real dvKnown[], fmi2Real dvUnknown[]) {
390  UNREFERENCED_PARAMETER(vUnknown_ref);
391  UNREFERENCED_PARAMETER(nUnknown);
392  UNREFERENCED_PARAMETER(vKnown_ref);
393  UNREFERENCED_PARAMETER(nKnown);
394  UNREFERENCED_PARAMETER(dvKnown);
395  UNREFERENCED_PARAMETER(dvUnknown);
396  return fmi2Error; /* Dummy implementation */
397 }
398 
399 /* Further functions for interpolation */
401 fmi2SetRealInputDerivatives(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2Integer order[], const fmi2Real value[]) {
405  UNREFERENCED_PARAMETER(order);
406  UNREFERENCED_PARAMETER(value);
407 
408  return fmi2Error; /* Ignoring - SUMO cannot interpolate inputs */
409 }
410 
412 fmi2GetRealOutputDerivatives(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2Integer order[], fmi2Real value[]) {
415  UNREFERENCED_PARAMETER(order);
416 
417  size_t i;
418  for (i = 0; i < nvr; i++) {
419  value[i] = 0; /* We cannot compute derivatives of outputs */
420  }
421  return fmi2Error;
422 }
423 
424 /* Stepping */
426 fmi2DoStep(fmi2Component c, fmi2Real currentCommunicationPoint, fmi2Real communicationStepSize, fmi2Boolean noSetFMUStatePriorToCurrentPoint) {
427  UNREFERENCED_PARAMETER(noSetFMUStatePriorToCurrentPoint);
428 
429  ModelInstance* comp = (ModelInstance*)c;
430 
431  if (communicationStepSize <= 0) {
432  return fmi2Error;
433  }
434 
435  return sumo2fmi_step(comp, currentCommunicationPoint + communicationStepSize);
436 }
437 
441 
442  return fmi2Error; /* We will never have a modelStepInProgress state */
443 }
444 
445 /* Status functions */
450  UNREFERENCED_PARAMETER(value);
451 
452  return fmi2Discard;
453 }
454 
459  UNREFERENCED_PARAMETER(value);
460 
461  return fmi2Discard;
462 }
463 
468  UNREFERENCED_PARAMETER(value);
469 
470  return fmi2Discard;
471 }
472 
477  UNREFERENCED_PARAMETER(value);
478 
479  return fmi2Discard;
480 }
481 
486  UNREFERENCED_PARAMETER(value);
487 
488  return fmi2Discard;
489 }
fmi2Status
@ fmi2OK
@ fmi2Error
@ fmi2Discard
@ fmi2Warning
fmi2StatusKind
fmi2Status fmi2SetInteger(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2Integer value[])
fmi2Status fmi2SetFMUstate(fmi2Component c, fmi2FMUstate FMUstate)
fmi2Status fmi2EnterInitializationMode(fmi2Component c)
fmi2Status fmi2GetInteger(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, fmi2Integer value[])
fmi2Status fmi2GetBoolean(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, fmi2Boolean value[])
const char * fmi2GetTypesPlatform(void)
Definition: fmi2Functions.c:42
fmi2Status fmi2GetIntegerStatus(fmi2Component c, const fmi2StatusKind s, fmi2Integer *value)
fmi2Status fmi2SerializedFMUstateSize(fmi2Component c, fmi2FMUstate FMUstate, size_t *size)
fmi2Status fmi2GetBooleanStatus(fmi2Component c, const fmi2StatusKind s, fmi2Boolean *value)
fmi2Status fmi2FreeFMUstate(fmi2Component c, fmi2FMUstate *FMUstate)
fmi2Status fmi2CancelStep(fmi2Component c)
fmi2Status fmi2Reset(fmi2Component c)
fmi2Status fmi2SetupExperiment(fmi2Component c, fmi2Boolean toleranceDefined, fmi2Real tolerance, fmi2Real startTime, fmi2Boolean stopTimeDefined, fmi2Real stopTime)
fmi2Status fmi2GetRealOutputDerivatives(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2Integer order[], fmi2Real value[])
fmi2Status fmi2SetRealInputDerivatives(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2Integer order[], const fmi2Real value[])
fmi2Status fmi2GetStatus(fmi2Component c, const fmi2StatusKind s, fmi2Status *value)
fmi2Component fmi2Instantiate(fmi2String instanceName, fmi2Type fmuType, fmi2String fmuGUID, fmi2String fmuResourceLocation, const fmi2CallbackFunctions *functions, fmi2Boolean visible, fmi2Boolean loggingOn)
Definition: fmi2Functions.c:87
fmi2Status fmi2SetReal(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2Real value[])
fmi2Status fmi2ExitInitializationMode(fmi2Component c)
const char * fmi2GetVersion(void)
Definition: fmi2Functions.c:46
fmi2Status fmi2SetDebugLogging(fmi2Component c, fmi2Boolean loggingOn, size_t nCategories, const fmi2String categories[])
Definition: fmi2Functions.c:56
fmi2Status fmi2SerializeFMUstate(fmi2Component c, fmi2FMUstate FMUstate, fmi2Byte state[], size_t size)
fmi2Status fmi2SetString(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2String value[])
fmi2Status fmi2SetBoolean(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2Boolean value[])
fmi2Status fmi2GetFMUstate(fmi2Component c, fmi2FMUstate *FMUstate)
fmi2Status fmi2GetStringStatus(fmi2Component c, const fmi2StatusKind s, fmi2String *value)
#define UNREFERENCED_PARAMETER(P)
Definition: fmi2Functions.c:37
fmi2Status fmi2GetReal(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, fmi2Real value[])
fmi2Status fmi2GetDirectionalDerivative(fmi2Component c, const fmi2ValueReference vUnknown_ref[], size_t nUnknown, const fmi2ValueReference vKnown_ref[], size_t nKnown, const fmi2Real dvKnown[], fmi2Real dvUnknown[])
void fmi2FreeInstance(fmi2Component c)
fmi2Status fmi2GetRealStatus(fmi2Component c, const fmi2StatusKind s, fmi2Real *value)
fmi2Status fmi2DeSerializeFMUstate(fmi2Component c, const fmi2Byte serializedState[], size_t size, fmi2FMUstate *FMUstate)
fmi2Status fmi2GetString(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, fmi2String value[])
fmi2Status fmi2DoStep(fmi2Component c, fmi2Real currentCommunicationPoint, fmi2Real communicationStepSize, fmi2Boolean noSetFMUStatePriorToCurrentPoint)
fmi2Status fmi2Terminate(fmi2Component c)
#define fmi2Version
int fmi2Integer
#define fmi2TypesPlatform
void * fmi2FMUstate
double fmi2Real
unsigned int fmi2ValueReference
char fmi2Byte
void * fmi2Component
int fmi2Boolean
const fmi2Char * fmi2String
void libsumo_load(char *callOptions)
void libsumo_close(void)
char * getterParameters
Parameters stored for the next (libsumo) getter call. Workaround for FMIv2 not allowing input values ...
const char * resourceLocation
fmi2String * bufferArray
allocateMemoryType allocateMemory
const char * instanceName
freeMemoryType freeMemory
char * libsumoCallOptions
fmi2CallbackAllocateMemory allocateMemory
fmi2CallbackLogger logger
fmi2CallbackFreeMemory freeMemory
fmi2ComponentEnvironment componentEnvironment
fmi2Status sumo2fmi_getString(ModelInstance *comp, const fmi2ValueReference vr, fmi2String *value)
void sumo2fmi_set_startValues(ModelInstance *comp)
fmi2Status sumo2fmi_step(ModelInstance *comp, double tNext)
fmi2Status sumo2fmi_getInteger(ModelInstance *comp, const fmi2ValueReference vr, int *value)
void sumo2fmi_logError(ModelInstance *comp, const char *message,...)
fmi2Status sumo2fmi_setString(ModelInstance *comp, fmi2ValueReference vr, fmi2String value)
void sumo2fmi_logEvent(ModelInstance *comp, const char *message,...)
void *(* allocateMemoryType)(size_t nobj, size_t size)
void(* freeMemoryType)(void *obj)
void(* loggerType)(void *componentEnvironment, const char *instanceName, int status, const char *category, const char *message,...)