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.org/sumo
3 // Copyright (C) 2020-2022 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* fmi2GetVersion(void) {
43  return fmi2Version;
44 }
45 
46 const char* fmi2GetTypesPlatform(void) {
47  return fmi2TypesPlatform;
48 }
49 
50 /* ***********************************************************************************************
51  * CREATION AND DESTRUCTION OF AN FMU
52  ***********************************************************************************************/
53 
54 /* The function returns a new instance of an FMU. If a null pointer is returned, then instantiation
55  failed.*/
57 fmi2Instantiate(fmi2String instanceName, fmi2Type fmuType, fmi2String fmuGUID,
58  fmi2String fmuResourceLocation, const fmi2CallbackFunctions *functions,
59  fmi2Boolean visible, fmi2Boolean loggingOn)
60 {
61  UNREFERENCED_PARAMETER(fmuType);
62  UNREFERENCED_PARAMETER(fmuGUID);
63  UNREFERENCED_PARAMETER(visible);
64 
65  allocateMemoryType funcAllocateMemory = (allocateMemoryType)functions->allocateMemory;
66  ModelInstance* comp = (ModelInstance *) funcAllocateMemory(1, sizeof(ModelInstance));
67 
68  if (comp) {
69  comp->componentEnvironment = functions->componentEnvironment;
70 
71  /* Callback functions for specific logging, malloc and free;
72  we need callback functions because we cannot know, which functions
73  the environment will provide for us */
74  comp->logger = (loggerType)functions->logger;
75  comp->allocateMemory = (allocateMemoryType)functions->allocateMemory;
76  comp->freeMemory = (freeMemoryType)functions->freeMemory;
77 
78  comp->instanceName = (char *)comp->allocateMemory(1 + strlen(instanceName), sizeof(char));
79  strcpy((char *)comp->instanceName, (char *)instanceName);
80 
81  if (fmuResourceLocation) {
82  comp->resourceLocation = (char *)comp->allocateMemory(1 + strlen(fmuResourceLocation), sizeof(char));
83  strcpy((char *)comp->resourceLocation, (char *)fmuResourceLocation);
84  } else {
85  comp->resourceLocation = NULL;
86  }
87 
88  comp->logEvents = loggingOn;
89  comp->logErrors = true; // always log errors
90  }
91 
92  return comp;
93 }
94 
95 /* Disposes the given instance, unloads the loaded model, and frees all the allocated memory
96 and other resources that have been allocated by the functions of the FMU interface. */
97 void
99  ModelInstance *comp = (ModelInstance *)c;
100 
101  /* Store the pointer to the freeMemory function, because we
102  are going to free comp as well */
103  freeMemoryType freeMemoryFunc = comp->freeMemory;
104 
105  /* We want to free everything that we allocated in fmi2Instantiate */
106  freeMemoryFunc((void *)comp->instanceName);
107  freeMemoryFunc((void *)comp->resourceLocation);
108  freeMemoryFunc((void *)comp->libsumoCallOptions);
109  freeMemoryFunc((void *)comp->getterParameters);
110  int i;
111  for (i = 0; i < comp->bufferArrayLength; i++) {
112  freeMemoryFunc((void *)comp->bufferArray[i]);
113  }
114  freeMemoryFunc((void *)comp->bufferArray);
115  freeMemoryFunc((void *)comp);
116 }
117 
118 /* Define what should be logged - if logging is enabled globally */
120 fmi2SetDebugLogging(fmi2Component c, fmi2Boolean loggingOn, size_t nCategories, const fmi2String categories[]) {
121 
122  ModelInstance *comp = (ModelInstance *)c;
123 
124  if (loggingOn) {
125  size_t i;
126  for (i = 0; i < nCategories; i++) {
127  if (categories[i] == NULL) {
128  sumo2fmi_logError(comp, "Log category[%d] must not be NULL", i);
129  return fmi2Error;
130  } else if (strcmp(categories[i], "logStatusError") == 0) {
131  comp->logErrors = true;
132  } else if (strcmp(categories[i], "logEvents") == 0) {
133  comp->logEvents = true;
134  } else {
135  sumo2fmi_logError(comp, "Log category[%d] must be one of logEvents or logStatusError but was %s", i, categories[i]);
136  return fmi2Error;
137  }
138  }
139  } else {
140  // Logging is disabled globally, no need for a more fine grained logging
141  comp->logEvents = false;
142  comp->logErrors = false;
143  }
144 
145  return fmi2OK;
146 }
147 
149 fmi2SetupExperiment(fmi2Component c, fmi2Boolean toleranceDefined, fmi2Real tolerance,
150  fmi2Real startTime, fmi2Boolean stopTimeDefined, fmi2Real stopTime) {
151 
152  UNREFERENCED_PARAMETER(toleranceDefined);
153  UNREFERENCED_PARAMETER(tolerance);
154  UNREFERENCED_PARAMETER(stopTimeDefined);
155 
156  // ignore arguments: toleranceDefined, tolerance
157  ModelInstance *comp = (ModelInstance *)c;
158 
159  // Store the start and stop times of the experiment
160  comp->startTime = startTime;
161  comp->stopTime = stopTime;
162 
164 
165  return fmi2OK;
166 }
167 
168 // Will be called after instantiation and after initial variables have been set
172 
173  return fmi2OK;
174 }
175 
176 // Informs the FMU to exit Initialization Mode
179  ModelInstance *comp = (ModelInstance *)c;
180 
181  sumo2fmi_logEvent(comp, "Calling libsumo with the following options: \"%s\"", comp->libsumoCallOptions);
183 
184  return fmi2OK;
185 }
186 
187 // Informs the FMU that the simulation run is terminated
188 // --> let libsumo know, that we want to close the simulation
192 
193  libsumo_close();
194  return fmi2OK;
195 }
196 
197 // Is called by the environment to reset the FMU after a simulation run
201 
202  // Should we set some start values?
203  return fmi2OK;
204 }
205 
206 // Implementation of the getter features
208 fmi2GetInteger(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, fmi2Integer value[]) {
209 
210  ModelInstance *comp = (ModelInstance *)c;
211 
212  // Check for null pointer errors
213  if (nvr > 0 && (!vr || !value)) {
214  return fmi2Error;
215  }
216 
217  fmi2Status status = fmi2OK;
218 
219  // Go through the list of arrays and save all requested values
220  size_t i;
221  for (i = 0; i < nvr; i++) {
222  fmi2Status s = sumo2fmi_getInteger(comp, vr[i], &(value[i]));
223  status = s > status ? s : status;
224 
225  if (status > fmi2Warning) {
226  return status;
227  }
228  }
229 
230  return status;
231 }
232 
234 fmi2GetReal(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, fmi2Real value[]) {
238  UNREFERENCED_PARAMETER(value);
239 
240  return fmi2Error;
241 }
242 
244 fmi2GetBoolean(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, fmi2Boolean value[]) {
248  UNREFERENCED_PARAMETER(value);
249 
250  return fmi2Error;
251 }
252 
254 fmi2GetString(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, fmi2String value[]) {
255 
256  ModelInstance *comp = (ModelInstance *)c;
257 
258  // Check for null pointer errors
259  if (nvr > 0 && (!vr || !value)) {
260  return fmi2Error;
261  }
262 
263  fmi2Status status = fmi2OK;
264 
266  int b;
267  for (b = 0; b < comp->bufferArrayLength; b++) {
268  comp->freeMemory((void *)comp->bufferArray[b]);
269  }
270  comp->freeMemory((void *)comp->bufferArray);
271  comp->bufferArray = (fmi2String *)comp->allocateMemory(nvr, sizeof(fmi2String));
272  comp->bufferArrayLength = (int)nvr;
273 
274  // Go through the list of arrays and save all requested values
275  size_t i;
276  for (i = 0; i < nvr; i++) {
277  fmi2Status s = sumo2fmi_getString(comp, vr[i], &(comp->bufferArray[i]));
278  value[i] = comp->bufferArray[i];
279  if (value[i] == NULL) {
280  s = fmi2Error;
281  }
282 
283  status = s > status ? s : status;
284  if (status > fmi2Warning) {
285  return status;
286  }
287  }
288 
289  return status;
290 }
291 
292 // Implementation of the setter features
293 
295 fmi2SetInteger(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2Integer value[]) {
299  UNREFERENCED_PARAMETER(value);
300 
301  return fmi2Error;
302 }
303 
305 fmi2SetReal (fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2Real value[]) {
309  UNREFERENCED_PARAMETER(value);
310  return fmi2Error;
311 }
312 
314 fmi2SetBoolean(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2Boolean value[]) {
318  UNREFERENCED_PARAMETER(value);
319 
320  return fmi2Error;
321 }
322 
324 fmi2SetString(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2String value[]) {
325 
326  ModelInstance *comp = (ModelInstance *)c;
327  fmi2Status status = fmi2OK;
328 
329  size_t i;
330  for (i = 0; i < nvr; i++) {
331  fmi2Status s = sumo2fmi_setString(comp, vr[i], value[i]);
332  status = s > status ? s : status;
333  if (status > fmi2Warning) return status;
334  }
335 
336  return status;
337 }
338 
339 /* Further functions for interpolation */
341 fmi2SetRealInputDerivatives(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2Integer order[], const fmi2Real value[]) {
345  UNREFERENCED_PARAMETER(order);
346  UNREFERENCED_PARAMETER(value);
347 
348  return fmi2Error; /* Ignoring - SUMO cannot interpolate inputs */
349 }
350 
352 fmi2GetRealOutputDerivatives(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2Integer order[], fmi2Real value[]) {
355  UNREFERENCED_PARAMETER(order);
356 
357  size_t i;
358  for (i = 0; i < nvr; i++) {
359  value[i] = 0; /* We cannot compute derivatives of outputs */
360  }
361  return fmi2Error;
362 }
363 
364 /* Stepping */
366 fmi2DoStep(fmi2Component c, fmi2Real currentCommunicationPoint, fmi2Real communicationStepSize, fmi2Boolean noSetFMUStatePriorToCurrentPoint) {
367  UNREFERENCED_PARAMETER(noSetFMUStatePriorToCurrentPoint);
368 
369  ModelInstance *comp = (ModelInstance *)c;
370 
371  if (communicationStepSize <= 0) {
372  return fmi2Error;
373  }
374 
375  return sumo2fmi_step(comp, currentCommunicationPoint + communicationStepSize);
376 }
377 
381 
382  return fmi2Error; /* We will never have a modelStepInProgress state */
383 }
384 
385 /* Status functions */
390  UNREFERENCED_PARAMETER(value);
391 
392  return fmi2Discard;
393 }
394 
399  UNREFERENCED_PARAMETER(value);
400 
401  return fmi2Discard;
402 }
403 
408  UNREFERENCED_PARAMETER(value);
409 
410  return fmi2Discard;
411 }
412 
417  UNREFERENCED_PARAMETER(value);
418 
419  return fmi2Discard;
420 }
421 
426  UNREFERENCED_PARAMETER(value);
427 
428  return fmi2Discard;
429 }
fmi2Status
@ fmi2OK
@ fmi2Error
@ fmi2Discard
@ fmi2Warning
fmi2StatusKind
fmi2Status fmi2SetInteger(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2Integer value[])
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:46
fmi2Status fmi2GetIntegerStatus(fmi2Component c, const fmi2StatusKind s, fmi2Integer *value)
fmi2Status fmi2GetBooleanStatus(fmi2Component c, const fmi2StatusKind s, fmi2Boolean *value)
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:57
fmi2Status fmi2SetReal(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2Real value[])
fmi2Status fmi2ExitInitializationMode(fmi2Component c)
const char * fmi2GetVersion(void)
Definition: fmi2Functions.c:42
fmi2Status fmi2SetDebugLogging(fmi2Component c, fmi2Boolean loggingOn, size_t nCategories, const fmi2String categories[])
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 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[])
void fmi2FreeInstance(fmi2Component c)
Definition: fmi2Functions.c:98
fmi2Status fmi2GetRealStatus(fmi2Component c, const fmi2StatusKind s, fmi2Real *value)
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
double fmi2Real
unsigned int fmi2ValueReference
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,...)