2 Copyright (C) 2012 Modelon AB
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the BSD style license.
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 FMILIB_License.txt file for more details.
12 You should have received a copy of the FMILIB_License.txt file
13 along with this program. If not, contact Modelon AB <http://www.modelon.com>.
20 #include <FMI1/fmi1_xml_model_description.h>
21 #include <FMI1/fmi1_functions.h>
23 #include "fmi1_import_impl.h"
26 \brief Collect model information by counting the number of variables with specific properties and fillinf in fmi1_import_model_counts_t struct.
27 \param fmu - An fmu object as returned by fmi1_import_parse_xml().
28 \param counts - a pointer to a preallocated struct.
30 void fmi1_import_collect_model_counts(fmi1_import_t* fmu, fmi1_import_model_counts_t* counts) {
31 jm_vector(jm_voidp)* vars = fmi1_xml_get_variables_original_order(fmu->md);
33 memset(counts,0,sizeof(fmi1_import_model_counts_t));
35 nv = jm_vector_get_size(jm_voidp)(vars);
36 for(i = 0; i< nv; i++) {
37 fmi1_xml_variable_t* var = (fmi1_xml_variable_t*)jm_vector_get_item(jm_voidp)(vars, i);
38 switch (fmi1_xml_get_variability(var)) {
39 case fmi1_variability_enu_constant:
40 counts->num_constants++;
42 case fmi1_variability_enu_parameter:
43 counts->num_parameters++;
45 case fmi1_variability_enu_discrete:
46 counts->num_discrete++;
48 case fmi1_variability_enu_continuous:
49 counts->num_continuous++;
54 switch(fmi1_xml_get_causality(var)) {
55 case fmi1_causality_enu_none:
56 counts->num_causality_none++;
58 case fmi1_causality_enu_input:
61 case fmi1_causality_enu_output:
62 counts->num_outputs++;
64 case fmi1_causality_enu_internal:
65 counts->num_internal++;
69 switch(fmi1_xml_get_variable_base_type(var)) {
70 case fmi1_base_type_real:
71 counts->num_real_vars++;
73 case fmi1_base_type_int:
74 counts->num_integer_vars++;
76 case fmi1_base_type_bool:
77 counts->num_bool_vars++;
79 case fmi1_base_type_str:
80 counts->num_string_vars++;
82 case fmi1_base_type_enum:
83 counts->num_enum_vars++;
92 void fmi1_import_expand_variable_references_impl(fmi1_import_t* fmu, const char* msgIn);
94 void fmi1_import_expand_variable_references(fmi1_import_t* fmu, const char* msgIn, char* msgOut, size_t maxMsgSize) {
95 fmi1_import_expand_variable_references_impl(fmu, msgIn);
96 strncpy(msgOut, jm_vector_get_itemp(char)(&fmu->logMessageBufferExpanded,0),maxMsgSize);
97 msgOut[maxMsgSize - 1] = '\0';
100 /* Print msgIn into msgOut by expanding variable references of the form #<Type><VR># into variable names
101 and replacing '##' with a single # */
102 void fmi1_import_expand_variable_references_impl(fmi1_import_t* fmu, const char* msgIn){
103 jm_vector(char)* msgOut = &fmu->logMessageBufferExpanded;
104 fmi1_xml_model_description_t* md = fmu->md;
105 jm_callbacks* callbacks = fmu->callbacks;
107 const char* firstRef;
108 size_t i; /* next char index after curCh in msgIn*/
109 size_t msgLen = strlen(msgIn)+1; /* original message length including terminating 0 */
111 if(jm_vector_reserve(char)(msgOut, msgLen + 100) < msgLen + 100) {
112 jm_log(fmu->callbacks,"LOGGER", jm_log_level_warning, "Could not allocate memory for the log message");
113 jm_vector_resize(char)(msgOut, 6);
114 memcpy(jm_vector_get_itemp(char)(msgOut,0),"ERROR",6); /* at least 16 chars are always there */
118 /* check if there are any refs at all and copy the head of the string without references */
119 firstRef = strchr(msgIn, '#');
121 i = firstRef - msgIn;
122 jm_vector_resize(char)(msgOut, i);
124 memcpy(jm_vector_get_itemp(char)(msgOut, 0), msgIn, i);
129 jm_vector_resize(char)(msgOut, msgLen);
130 memcpy(jm_vector_get_itemp(char)(msgOut, 0), msgIn, msgLen);
135 jm_vector_push_back(char)(msgOut, curCh); /* copy in to out */
137 else if(msgIn[i] == '#') {
138 jm_vector_push_back(char)(msgOut, '#');
139 i++; /* skip the second # */
142 fmi1_value_reference_t vr = fmi1_undefined_value_reference;
143 char typeChar = msgIn[i++];
144 size_t pastePos = jm_vector_get_size(char)(msgOut);
145 fmi1_base_type_enu_t baseType;
147 fmi1_xml_variable_t* var;
152 baseType = fmi1_base_type_real;
155 baseType = fmi1_base_type_int;
158 baseType = fmi1_base_type_bool;
161 baseType = fmi1_base_type_str;
164 jm_vector_push_back(char)(msgOut, 0);
165 jm_log(callbacks,"LOGGER", jm_log_level_warning,
166 "Expected type specification character 'r', 'i', 'b' or 's' in log message here: '%s'",
167 jm_vector_get_itemp(char)(msgOut,0));
168 jm_vector_resize(char)(msgOut, msgLen);
169 memcpy(jm_vector_get_itemp(char)(msgOut,0),msgIn,msgLen);
173 while( isdigit(curCh) ) {
174 jm_vector_push_back(char)(msgOut, curCh);
177 num_digits = jm_vector_get_size(char)(msgOut) - pastePos;
178 jm_vector_push_back(char)(msgOut, 0);
179 if(num_digits == 0) {
180 jm_log(callbacks,"LOGGER", jm_log_level_warning, "Expected value reference in log message here: '%s'", jm_vector_get_itemp(char)(msgOut,0));
181 jm_vector_resize(char)(msgOut, msgLen);
182 jm_vector_resize(char)(msgOut, msgLen);
183 memcpy(jm_vector_get_itemp(char)(msgOut,0),msgIn,msgLen);
186 else if(curCh != '#') {
187 jm_log(callbacks,"LOGGER", jm_log_level_warning, "Expected terminating '#' in log message here: '%s'", jm_vector_get_itemp(char)(msgOut,0));
188 jm_vector_resize(char)(msgOut, msgLen);
189 jm_vector_resize(char)(msgOut, msgLen);
190 memcpy(jm_vector_get_itemp(char)(msgOut,0),msgIn,msgLen);
194 if(sscanf(jm_vector_get_itemp(char)(msgOut, pastePos), "%u",&vr) != 1) {
195 jm_log(callbacks,"LOGGER", jm_log_level_warning, "Could not decode value reference in log message here: '%s'", jm_vector_get_itemp(char)(msgOut,0));
196 jm_vector_resize(char)(msgOut, msgLen);
197 jm_vector_resize(char)(msgOut, msgLen);
198 memcpy(jm_vector_get_itemp(char)(msgOut,0),msgIn,msgLen);
201 var = fmi1_xml_get_variable_by_vr(md,baseType,vr);
203 jm_log(callbacks,"LOGGER", jm_log_level_warning, "Could not find variable referenced in log message here: '%s'", jm_vector_get_itemp(char)(msgOut,0));
204 jm_vector_resize(char)(msgOut, msgLen);
205 jm_vector_resize(char)(msgOut, msgLen);
206 memcpy(jm_vector_get_itemp(char)(msgOut,0),msgIn,msgLen);
209 name = fmi1_xml_get_variable_name(var);
210 nameLen = strlen(name);
211 if(jm_vector_resize(char)(msgOut, pastePos + nameLen) != pastePos + nameLen) {
212 jm_log(callbacks,"LOGGER", jm_log_level_warning, "Could not allocate memory for the log message");
213 jm_vector_resize(char)(msgOut, msgLen);
214 jm_vector_resize(char)(msgOut, msgLen);
215 memcpy(jm_vector_get_itemp(char)(msgOut,0),msgIn,msgLen);
218 memcpy(jm_vector_get_itemp(char)(msgOut, pastePos), name, nameLen);
222 jm_vector_push_back(char)(msgOut, 0);
225 jm_callbacks fmi1_import_active_fmu_store_callbacks;
227 jm_vector(jm_voidp) fmi1_import_active_fmu_store;
229 jm_vector(jm_voidp)* fmi1_import_active_fmu = 0;
231 void fmi1_log_forwarding(fmi1_component_t c, fmi1_string_t instanceName, fmi1_status_t status, fmi1_string_t category, fmi1_string_t message, ...) {
233 va_start (args, message);
234 fmi1_log_forwarding_v(c, instanceName, status, category, message, args);
238 void fmi1_log_forwarding_v(fmi1_component_t c, fmi1_string_t instanceName, fmi1_status_t status, fmi1_string_t category, fmi1_string_t message, va_list args) {
239 #define BUFSIZE JM_MAX_ERROR_MESSAGE_SIZE
240 char buffer[BUFSIZE], *buf, *curp, *msg;
241 const char* statusStr;
242 fmi1_import_t* fmu = 0;
243 jm_callbacks* cb = jm_get_default_callbacks();
244 jm_log_level_enu_t logLevel = jm_log_level_error;
245 if(fmi1_import_active_fmu) {
246 size_t n = jm_vector_get_size(jm_voidp)(fmi1_import_active_fmu);
248 for(i= 0; i < n; i++) {
249 fmu = (fmi1_import_t*)jm_vector_get_item(jm_voidp)(fmi1_import_active_fmu, i);
250 if(fmu->capi->c == c) {
255 if(i >= n) { /* Could not find matching FMU -> use default callbacks */
257 cb = jm_get_default_callbacks();
261 buf = jm_vector_get_itemp(char)(&fmu->logMessageBufferCoded,0);
267 case fmi1_status_discard:
268 case fmi1_status_pending:
270 logLevel = jm_log_level_info;
272 case fmi1_status_warning:
273 logLevel = jm_log_level_warning;
275 case fmi1_status_error:
276 logLevel = jm_log_level_error;
278 case fmi1_status_fatal:
280 logLevel = jm_log_level_fatal;
283 if(logLevel > cb->log_level) return;
289 curp += jm_snprintf(curp, 100, "[%s]", category);
291 statusStr = fmi1_status_to_string(status);
292 curp += jm_snprintf(curp, 100,"[FMU status:%s] ", statusStr);
295 int bufsize = jm_vector_get_size(char)(&fmu->logMessageBufferCoded);
299 JM_VA_COPY(argscp, args);
301 len = jm_vsnprintf(curp, bufsize -(curp-buf), message, args);
302 if(len > (bufsize -(curp-buf+1))) {
303 int offset = (curp-buf);
304 len = jm_vector_resize(char)(&fmu->logMessageBufferCoded, len + offset + 1) - offset;
305 buf = jm_vector_get_itemp(char)(&fmu->logMessageBufferCoded,0);
308 jm_vsnprintf(curp, len, message, argscp);
314 fmi1_import_expand_variable_references(fmu, buf, cb->errMessageBuffer,JM_MAX_ERROR_MESSAGE_SIZE);
315 msg = jm_vector_get_itemp(char)(&fmu->logMessageBufferExpanded,0);
318 jm_vsnprintf(curp, BUFSIZE -(curp-buf), message, args);
319 strncpy(cb->errMessageBuffer, buf, JM_MAX_ERROR_MESSAGE_SIZE);
320 cb->errMessageBuffer[JM_MAX_ERROR_MESSAGE_SIZE - 1] = '\0';
321 msg = cb->errMessageBuffer;
324 cb->logger(cb, instanceName, logLevel, msg);
328 void fmi1_default_callback_logger(fmi1_component_t c, fmi1_string_t instanceName, fmi1_status_t status, fmi1_string_t category, fmi1_string_t message, ...) {
331 char buf[BUFSIZE], *curp;
332 va_start (args, message);
336 curp += jm_snprintf(curp, 200, "[%s]", instanceName);
339 curp += jm_snprintf(curp, 200, "[%s]", category);
341 fprintf(stdout, "%s[status=%s]", buf, fmi1_status_to_string(status));
342 vfprintf (stdout, message, args);
343 fprintf(stdout, "\n");
347 void fmi1_logger(jm_callbacks* cb, jm_string module, jm_log_level_enu_t log_level, jm_string message) {
348 fmi1_callback_functions_t* c = (fmi1_callback_functions_t*)cb->context;
349 fmi1_status_t status;
350 if(!c ||!c->logger) return;
352 if(log_level > jm_log_level_all) {
354 status = fmi1_status_error;
356 else if(log_level >= jm_log_level_info)
357 status = fmi1_status_ok;
358 else if(log_level >= jm_log_level_warning)
359 status = fmi1_status_warning;
360 else if(log_level >= jm_log_level_error)
361 status = fmi1_status_error;
362 else if(log_level >= jm_log_level_fatal)
363 status = fmi1_status_fatal;
365 status = fmi1_status_ok;
368 c->logger( c, module, status, jm_log_level_to_string(log_level), message);
371 void fmi1_import_init_logger(jm_callbacks* cb, fmi1_callback_functions_t* fmiCallbacks) {
372 cb->logger = fmi1_logger;
373 cb->context = fmiCallbacks;