1 | /* |
2 | * |
3 | * Copyright 1994-2019 The MathWorks, Inc. |
4 | * |
5 | * File: rt_logging.c |
6 | * |
7 | * Abstract: |
8 | * Real-Time Workshop data logging routines using circular buffers of |
9 | * fixed size. The buffers are allocated at start, filled in at each |
10 | * major time step and finally written to a MAT-file at the end of the |
11 | * simulation. |
12 | * |
13 | * This file handles redefining the following standard MathWorks types |
14 | * (see tmwtypes.h): |
15 | * [u]int8_T to be int32_T (logged as Matlab [u]int32) |
16 | * [u]int16_T to be int32_T (logged as Matlab [u]int32) |
17 | * real_T to be real32_T (logged as Matlab single) |
18 | * |
19 | */ |
20 | |
21 | #include <stdlib.h> |
22 | #include <string.h> |
23 | #include <stdio.h> |
24 | #include <limits.h> |
25 | #include <math.h> |
26 | |
27 | |
28 | #if !defined(MAT_FILE) || (defined(MAT_FILE) && MAT_FILE == 1) |
29 | |
30 | #include <stddef.h> /* size_t */ |
31 | #include "rt_logging.h" |
32 | #ifndef IS_RAPID_ACCEL |
33 | #include "rt_mxclassid.h" |
34 | #endif |
35 | #include "rtw_matlogging.h" |
36 | |
37 | #ifndef TMW_NAME_LENGTH_MAX |
38 | #define TMW_NAME_LENGTH_MAX 64 |
39 | #endif |
40 | #define mxMAXNAM TMW_NAME_LENGTH_MAX /* maximum name length */ |
41 | #define matUNKNOWN 0 |
42 | #define matINT8 1 |
43 | #define matUINT8 2 |
44 | #define matINT16 3 |
45 | #define matUINT16 4 |
46 | #define matINT32 5 |
47 | #define matUINT32 6 |
48 | #define matFLOAT 7 |
49 | #define matDOUBLE 9 |
50 | #define matINT64 12 |
51 | #define matUINT64 13 |
52 | #define matMATRIX 14 |
53 | |
54 | #define matLOGICAL_BIT 0x200 |
55 | #define matCOMPLEX_BIT 0x800 |
56 | |
57 | #define matKEY 0x4D49 |
58 | #define matVERSION 0x0100 |
59 | #define matVERSION_INFO_OFFSET 124L |
60 | |
61 | #define matINT64_ALIGN(e) ( ( ((unsigned)(e))+7 ) & (~7) ) |
62 | #define matTAG_SIZE (sizeof(int32_T) << 1) |
63 | |
64 | #ifndef DEFAULT_BUFFER_SIZE |
65 | #define DEFAULT_BUFFER_SIZE 1024 /* used if maxRows=0 and Tfinal=0.0 */ |
66 | #endif |
67 | |
68 | #define FREE(m) if (m != NULL) free(m) |
69 | |
70 | /* Logical definitions */ |
71 | #if (!defined(__cplusplus)) |
72 | # ifndef false |
73 | # define false (0U) |
74 | # endif |
75 | # ifndef true |
76 | # define true (1U) |
77 | # endif |
78 | #endif |
79 | |
80 | /*==========* |
81 | * typedefs * |
82 | *==========*/ |
83 | |
84 | typedef struct LogInfo_Tag { |
85 | LogVar *t; /* Time log variable */ |
86 | void *x; /* State log variable */ |
87 | int_T ny; /* Length of "y" log variables */ |
88 | void **y; /* Output log vars */ |
89 | void *xFinal; /* Final state log variable */ |
90 | |
91 | LogVar *logVarsList; /* Linked list of all LogVars */ |
92 | StructLogVar *structLogVarsList; /* Linked list of all StructLogVars */ |
93 | |
94 | boolean_T haveLogVars; /* Are logging one or more vars? */ |
95 | } LogInfo; |
96 | |
97 | typedef struct MatItem_tag { |
98 | int32_T type; |
99 | uint32_T nbytes; |
100 | const void *data; |
101 | } MatItem; |
102 | |
103 | typedef enum { |
104 | DATA_ITEM, |
105 | MATRIX_ITEM, |
106 | STRUCT_LOG_VAR_ITEM, |
107 | SIGNALS_STRUCT_ITEM |
108 | } ItemDataKind; |
109 | |
110 | /*===========* |
111 | * Constants * |
112 | *===========*/ |
113 | |
114 | static const char_T rtMemAllocError[] = "Memory allocation error"; |
115 | |
116 | #define ZEROS32 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" |
117 | |
118 | #if mxMAXNAM==32 |
119 | |
120 | #define ZERO_PAD |
121 | |
122 | #elif mxMAXNAM==64 |
123 | |
124 | #define ZERO_PAD ZEROS32 |
125 | |
126 | #elif mxMAXNAM==128 |
127 | |
128 | #define ZERO_PAD ZEROS32 ZEROS32 ZEROS32 |
129 | |
130 | #else |
131 | |
132 | #error "Cannot Handle mxMAXNAM other than 32,64, and 128" |
133 | |
134 | #endif |
135 | /* field names: for variable-size signal logging */ |
136 | static const char_T rtStructLogVarFieldNames[] = |
137 | "time\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" ZERO_PAD |
138 | "signals\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" ZERO_PAD |
139 | "blockName\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" ZERO_PAD; |
140 | static const char_T rtLocalLoggingSignalsStructFieldNames[] = |
141 | "values\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" ZERO_PAD |
142 | "valueDimensions\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" ZERO_PAD |
143 | "dimensions\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" ZERO_PAD |
144 | "label\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" ZERO_PAD |
145 | "title\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" ZERO_PAD |
146 | "plotStyle\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" ZERO_PAD; |
147 | static const char_T rtGlobalLoggingSignalsStructFieldNames[] = |
148 | "values\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" ZERO_PAD |
149 | "valueDimensions\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" ZERO_PAD |
150 | "dimensions\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" ZERO_PAD |
151 | "label\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" ZERO_PAD |
152 | "blockName\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" ZERO_PAD |
153 | "stateName\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" ZERO_PAD |
154 | "inReferencedModel\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" ZERO_PAD; |
155 | #define TIME_FIELD_NAME (rtStructLogVarFieldNames[0*mxMAXNAM]) |
156 | #define SIGNALS_FIELD_NAME (rtStructLogVarFieldNames[1*mxMAXNAM]) |
157 | #define BLOCKNAME_FIELD_NAME (rtStructLogVarFieldNames[2*mxMAXNAM]) |
158 | |
159 | #define VALUES_FIELD_NAME (rtLocalLoggingSignalsStructFieldNames[0*mxMAXNAM]) |
160 | #define VALUEDIMENSIONS_FIELD_NAME (rtLocalLoggingSignalsStructFieldNames[1*mxMAXNAM]) |
161 | #define DIMENSION_FIELD_NAME (rtLocalLoggingSignalsStructFieldNames[2*mxMAXNAM]) |
162 | #define LABEL_FIELD_NAME (rtLocalLoggingSignalsStructFieldNames[3*mxMAXNAM]) |
163 | #define TITLE_FIELD_NAME (rtLocalLoggingSignalsStructFieldNames[4*mxMAXNAM]) |
164 | #define PLOTSTYLE_FIELD_NAME (rtLocalLoggingSignalsStructFieldNames[5*mxMAXNAM]) |
165 | |
166 | #define STATENAME_FIELD_NAME (rtGlobalLoggingSignalsStructFieldNames[5*mxMAXNAM]) |
167 | #define CROSS_MDL_REF_FIELD_NAME (rtGlobalLoggingSignalsStructFieldNames[6*mxMAXNAM]) |
168 | |
169 | /* field names: for fixed-size signal logging */ |
170 | static const char_T rtLocalLoggingSignalsStructFieldNames_noValDims[] = |
171 | "values\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" ZERO_PAD |
172 | "dimensions\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" ZERO_PAD |
173 | "label\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" ZERO_PAD |
174 | "title\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" ZERO_PAD |
175 | "plotStyle\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" ZERO_PAD; |
176 | static const char_T rtGlobalLoggingSignalsStructFieldNames_noValDims[] = |
177 | "values\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" ZERO_PAD |
178 | "dimensions\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" ZERO_PAD |
179 | "label\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" ZERO_PAD |
180 | "blockName\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" ZERO_PAD |
181 | "stateName\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" ZERO_PAD |
182 | "inReferencedModel\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" ZERO_PAD; |
183 | |
184 | extern real_T rtInf; /* declared by rt_nonfinite.c */ |
185 | extern real_T rtNaN; |
186 | extern real32_T rtNaNF; |
187 | |
188 | /*================* |
189 | * Local routines * |
190 | *================*/ |
191 | |
192 | /* Function: rt_GetSizeofDataType ============================================== |
193 | * Abstract: |
194 | * Get the element size in bytes given the data type id. |
195 | */ |
196 | static size_t rt_GetSizeofDataType(BuiltInDTypeId dTypeID) |
197 | { |
198 | size_t elSz = 0; /* unknown */ |
199 | |
200 | switch (dTypeID) { |
201 | case SS_DOUBLE: |
202 | elSz = sizeof(real_T); |
203 | break; |
204 | case SS_SINGLE: |
205 | elSz = sizeof(real32_T); |
206 | break; |
207 | case SS_INT8: |
208 | elSz = sizeof(int8_T); |
209 | break; |
210 | case SS_UINT8: |
211 | elSz = sizeof(uint8_T); |
212 | break; |
213 | case SS_INT16: |
214 | elSz = sizeof(int16_T); |
215 | break; |
216 | case SS_UINT16: |
217 | elSz = sizeof(uint16_T); |
218 | break; |
219 | case SS_INT32: |
220 | elSz = sizeof(int32_T); |
221 | break; |
222 | case SS_UINT32: |
223 | elSz = sizeof(uint32_T); |
224 | break; |
225 | case SS_BOOLEAN: |
226 | elSz = sizeof(boolean_T); |
227 | break; |
228 | } |
229 | return(elSz); |
230 | |
231 | } /* end rt_GetSizeofDataType */ |
232 | |
233 | |
234 | /* Function: rt_GetSizeofComplexType =========================================== |
235 | * Abstract: |
236 | * Get the element size in bytes given the data type id. |
237 | */ |
238 | static size_t rt_GetSizeofComplexType(BuiltInDTypeId dTypeID) |
239 | { |
240 | size_t elSz = 2*rt_GetSizeofDataType(dTypeID); |
241 | |
242 | switch (dTypeID) { |
243 | case SS_DOUBLE: |
244 | #ifdef CREAL_T |
245 | elSz = sizeof(creal_T); |
246 | #endif |
247 | break; |
248 | case SS_SINGLE: |
249 | #ifdef CREAL_T |
250 | elSz = sizeof(creal32_T); |
251 | #endif |
252 | break; |
253 | case SS_INT8: |
254 | #ifdef CINT8_T |
255 | elSz = sizeof(cint8_T); |
256 | #endif |
257 | break; |
258 | case SS_UINT8: |
259 | #ifdef CUINT8_T |
260 | elSz = sizeof(cuint8_T); |
261 | #endif |
262 | break; |
263 | case SS_INT16: |
264 | #ifdef CINT16_T |
265 | elSz = sizeof(cint16_T); |
266 | #endif |
267 | break; |
268 | case SS_UINT16: |
269 | #ifdef CUINT16_T |
270 | elSz = sizeof(cuint16_T); |
271 | #endif |
272 | break; |
273 | case SS_INT32: |
274 | #ifdef CINT32_T |
275 | elSz = sizeof(cint32_T); |
276 | #endif |
277 | break; |
278 | case SS_UINT32: |
279 | #ifdef CUINT32_T |
280 | elSz = sizeof(cuint32_T); |
281 | #endif |
282 | break; |
283 | case SS_BOOLEAN: |
284 | elSz = sizeof(boolean_T); |
285 | break; |
286 | } |
287 | |
288 | return(elSz); |
289 | |
290 | } /* end rt_GetSizeofComplexType */ |
291 | |
292 | |
293 | /* Function: rt_GetDataTypeConvertInfo ========================================= |
294 | * Abstract: |
295 | * Directly copy if pointer to structure is non-NULL, otherwise set to |
296 | * default. |
297 | */ |
298 | static RTWLogDataTypeConvert rt_GetDataTypeConvertInfo( |
299 | const RTWLogDataTypeConvert *pDataTypeConvertInfo, |
300 | BuiltInDTypeId dTypeID |
301 | ) |
302 | { |
303 | RTWLogDataTypeConvert dataTypeConvertInfoCopy; |
304 | |
305 | if (pDataTypeConvertInfo == NULL) { |
306 | dataTypeConvertInfoCopy.conversionNeeded = 0; |
307 | dataTypeConvertInfoCopy.dataTypeIdLoggingTo = dTypeID; |
308 | dataTypeConvertInfoCopy.dataTypeIdOriginal = (DTypeId)dTypeID; |
309 | dataTypeConvertInfoCopy.bitsPerChunk = 0; |
310 | dataTypeConvertInfoCopy.numOfChunk = 0; |
311 | dataTypeConvertInfoCopy.isSigned = 0; |
312 | dataTypeConvertInfoCopy.fracSlope = 1.0; |
313 | dataTypeConvertInfoCopy.fixedExp = 0; |
314 | dataTypeConvertInfoCopy.bias = 0.0; |
315 | } else { |
316 | dataTypeConvertInfoCopy = *pDataTypeConvertInfo; |
317 | } |
318 | |
319 | return dataTypeConvertInfoCopy; |
320 | |
321 | } /* end rt_GetDataTypeConvertInfo */ |
322 | |
323 | |
324 | /* Function: rt_GetDblValueFromOverSizedData =================================== |
325 | * Abstract: |
326 | */ |
327 | static double rt_GetDblValueFromOverSizedData( |
328 | const void *pVoid, |
329 | int bitsPerChunk, |
330 | int numOfChunk, |
331 | unsigned int isSigned, |
332 | double fracSlope, |
333 | int fixedExp, |
334 | double bias) |
335 | { |
336 | double retValue = 0; |
337 | |
338 | double *dblValue = (double *) calloc(numOfChunk, sizeof(double)); |
339 | |
340 | int i; |
341 | double isSignedNeg; |
342 | |
343 | if(isSigned) { |
344 | const chunk_T *pData = (const chunk_T *) (pVoid); |
345 | for (i = 0; i <numOfChunk; i++) { |
346 | dblValue[i] = (double)(pData[i]); |
347 | } |
348 | } else { |
349 | const uchunk_T *pData = (const uchunk_T *) (pVoid); |
350 | for (i = 0; i <numOfChunk; i++) { |
351 | dblValue[i] = (double)(pData[i]); |
352 | } |
353 | } |
354 | |
355 | /* |
356 | Assuming multi chunks b_n ... b_2 b_1 b_0, and the length of each chunk is N. |
357 | Suppose b_i is the i-th chunk's value. |
358 | Then for unsigned data or data with one chunk: we have |
359 | retValue = b_n * 2^(n*N) + ... + b_1 * 2^N + b_0 * 2^0; |
360 | But for signed data, we have |
361 | retValue = b_n * 2^(n*N) + ... + b_1 * 2^N + b_0 * 2^0+ (b_0<0) * 2^N + |
362 | ... (b_(n-1) <0) * 2^(n*N) |
363 | = (b_n + (b_(n-1)<0)) * 2^(n*N) +... + (b_1 + (b_0<0)) * 2^N + b_0 * 2^0; |
364 | Together: |
365 | retValue = |
366 | (b_n + isSigned * (b_(n-1)<0)) * 2^(n*N) +... + (b_1 + isSigned * (b_0<0)) * 2^N + b_0 * 2^0; |
367 | */ |
368 | |
369 | retValue = dblValue[numOfChunk - 1]; |
370 | |
371 | for(i = numOfChunk - 1; i > 0; i--) { |
372 | isSignedNeg = dblValue[i - 1] < 0 ? (double)isSigned : 0; |
373 | retValue = retValue + isSignedNeg; |
374 | |
375 | retValue = ldexp(retValue, bitsPerChunk)+ dblValue[i-1]; |
376 | } |
377 | retValue = ldexp( fracSlope * retValue, fixedExp ) + bias; |
378 | |
379 | FREE(dblValue); |
380 | return (retValue); |
381 | |
382 | } /* end rt_GetDblValueFromOverSizedData */ |
383 | |
384 | |
385 | /* Function: rt_GetNonBoolMxIdFromDTypeId ====================================== |
386 | * Abstract: |
387 | * Get the mx???_CLASS given the simulink builtin data type id. |
388 | */ |
389 | static mxClassID rt_GetNonBoolMxIdFromDTypeId(BuiltInDTypeId dTypeID) |
390 | { |
391 | mxClassID mxID; |
392 | |
393 | switch (dTypeID) { |
394 | case SS_DOUBLE: |
395 | mxID = (sizeof(real_T)==4? mxSINGLE_CLASS: mxDOUBLE_CLASS); |
396 | break; |
397 | case SS_SINGLE: |
398 | mxID = mxSINGLE_CLASS; |
399 | break; |
400 | case SS_INT8: |
401 | switch (sizeof(int8_T)) { |
402 | case 4: /* polyspace DEFECT:DEAD_CODE [Not a defect:Unset] |
403 | "Needed for when PWS maps int8_T into 32-bits" */ |
404 | mxID = mxINT32_CLASS; |
405 | break; |
406 | case 2: /* polyspace DEFECT:DEAD_CODE [Not a defect:Unset] |
407 | "Needed for when PWS maps int8_T into 16-bits" */ |
408 | mxID = mxINT16_CLASS; |
409 | break; |
410 | case 1: |
411 | mxID = mxINT8_CLASS; |
412 | break; |
413 | default: /* polyspace DEFECT:DEAD_CODE [Not a defect:Unset] |
414 | "Needed to handle an unknown data type ID" */ |
415 | mxID = mxUNKNOWN_CLASS; |
416 | break; |
417 | } |
418 | break; |
419 | case SS_UINT8: |
420 | switch (sizeof(uint8_T)) { |
421 | case 4: /* polyspace DEFECT:DEAD_CODE [Not a defect:Unset] |
422 | "Needed for when PWS maps uint8_T into 32-bits" */ |
423 | mxID = mxUINT32_CLASS; |
424 | break; |
425 | case 2: /* polyspace DEFECT:DEAD_CODE [Not a defect:Unset] |
426 | "Needed for when PWS maps uint8_T into 16-bits" */ |
427 | mxID = mxUINT16_CLASS; |
428 | break; |
429 | case 1: |
430 | mxID = mxUINT8_CLASS; |
431 | break; |
432 | default: /* polyspace DEFECT:DEAD_CODE [Not a defect:Unset] |
433 | "Needed to handle an unknown data type ID" */ |
434 | mxID = mxUNKNOWN_CLASS; |
435 | break; |
436 | } |
437 | break; |
438 | case SS_INT16: |
439 | mxID = (sizeof(int16_T)==4? mxINT32_CLASS: mxINT16_CLASS); |
440 | break; |
441 | case SS_UINT16: |
442 | mxID = (sizeof(uint16_T)==4? mxUINT32_CLASS: mxUINT16_CLASS); |
443 | break; |
444 | case SS_INT32: |
445 | mxID = mxINT32_CLASS; |
446 | break; |
447 | case SS_UINT32: |
448 | mxID = mxUINT32_CLASS; |
449 | break; |
450 | /*case SS_BOOLEAN: |
451 | mxID = (sizeof(boolean_T)==4? mxUINT32_CLASS: mxLOGICAL_CLASS); |
452 | break;*/ |
453 | default: |
454 | mxID = mxUNKNOWN_CLASS; |
455 | break; |
456 | } |
457 | |
458 | return(mxID); |
459 | |
460 | } /* end rt_GetNonBoolMxIdFromDTypeId */ |
461 | |
462 | |
463 | |
464 | #ifdef __cplusplus |
465 | extern "C" { |
466 | #endif |
467 | |
468 | |
469 | /* Function: rt_GetMxIdFromDTypeIdForRSim ====================================== |
470 | * Abstract: |
471 | * Get the mx???_CLASS given the simulink builtin data type id. |
472 | */ |
473 | mxClassID rt_GetMxIdFromDTypeIdForRSim(BuiltInDTypeId dTypeID) |
474 | { |
475 | mxClassID mxID; |
476 | |
477 | if (dTypeID == SS_BOOLEAN) { |
478 | switch (sizeof(boolean_T)) { |
479 | case 4: /* polyspace DEFECT:DEAD_CODE [Not a defect:Unset] |
480 | "Needed for when PWS maps boolean_T into 32-bits" */ |
481 | mxID = mxUINT32_CLASS; |
482 | break; |
483 | case 2: /* polyspace DEFECT:DEAD_CODE [Not a defect:Unset] |
484 | "Needed for when PWS maps boolean_T into 16-bits" */ |
485 | mxID = mxUINT16_CLASS; |
486 | break; |
487 | default: |
488 | mxID = mxLOGICAL_CLASS; |
489 | break; |
490 | } |
491 | } else { |
492 | mxID = rt_GetNonBoolMxIdFromDTypeId(dTypeID); |
493 | } |
494 | |
495 | return(mxID); |
496 | |
497 | } /* end rt_GetMxIdFromDTypeIdForRSim */ |
498 | |
499 | |
500 | #ifdef __cplusplus |
501 | } |
502 | #endif |
503 | |
504 | |
505 | |
506 | |
507 | #ifdef __cplusplus |
508 | extern "C" { |
509 | #endif |
510 | |
511 | |
512 | /* Function: rt_GetMxIdFromDTypeId ============================================= |
513 | * Abstract: |
514 | * Get the mx???_CLASS given the simulink builtin data type id. |
515 | */ |
516 | mxClassID rt_GetMxIdFromDTypeId(BuiltInDTypeId dTypeID) |
517 | { |
518 | mxClassID mxID; |
519 | |
520 | if (dTypeID == SS_BOOLEAN) { |
521 | switch (sizeof(boolean_T)) { |
522 | case 4: /* polyspace DEFECT:DEAD_CODE [Not a defect:Unset] |
523 | "Needed for when PWS maps boolean_T into 32-bits" */ |
524 | mxID = mxUINT32_CLASS; |
525 | break; |
526 | case 2: /* polyspace DEFECT:DEAD_CODE [Not a defect:Unset] |
527 | "Needed for when PWS maps boolean_T into 16-bits" */ |
528 | mxID = mxUINT16_CLASS; |
529 | break; |
530 | default: |
531 | mxID = mxUINT8_CLASS; |
532 | break; |
533 | } |
534 | } else { |
535 | mxID = rt_GetNonBoolMxIdFromDTypeId(dTypeID); |
536 | } |
537 | return(mxID); |
538 | |
539 | } /* end rt_GetMxIdFromDTypeId */ |
540 | |
541 | |
542 | #ifdef __cplusplus |
543 | } |
544 | #endif |
545 | |
546 | |
547 | |
548 | /* Function: rt_GetMatIdFromMxId =============================================== |
549 | * Abstract: |
550 | * Get the MatId given the mxClassID. |
551 | */ |
552 | static int_T rt_GetMatIdFromMxId(mxClassID mxID) |
553 | { |
554 | int_T matID; |
555 | |
556 | switch (mxID) { |
557 | case mxCELL_CLASS: |
558 | case mxSTRUCT_CLASS: |
559 | case mxOBJECT_CLASS: |
560 | matID = -1; |
561 | break; |
562 | case mxCHAR_CLASS: |
563 | matID = matUINT16; |
564 | break; |
565 | case mxDOUBLE_CLASS: |
566 | matID = matDOUBLE; |
567 | break; |
568 | case mxSINGLE_CLASS: |
569 | matID = matFLOAT; |
570 | break; |
571 | case mxINT8_CLASS: |
572 | matID = matINT8; |
573 | break; |
574 | case mxUINT8_CLASS: |
575 | matID = matUINT8; |
576 | break; |
577 | case mxINT16_CLASS: |
578 | matID = matINT16; |
579 | break; |
580 | case mxUINT16_CLASS: |
581 | matID = matUINT16; |
582 | break; |
583 | case mxINT32_CLASS: |
584 | matID = matINT32; |
585 | break; |
586 | case mxUINT32_CLASS: |
587 | matID = matUINT32; |
588 | break; |
589 | case mxINT64_CLASS: |
590 | matID = matINT64; |
591 | break; |
592 | case mxUINT64_CLASS: |
593 | matID = matUINT64; |
594 | break; |
595 | default: |
596 | matID = matUNKNOWN; |
597 | break; |
598 | } |
599 | return(matID); |
600 | |
601 | } /* end rt_GetMatIdFromMxId */ |
602 | |
603 | |
604 | /* Forward declaration */ |
605 | static int_T rt_WriteItemToMatFile(FILE *fp, |
606 | MatItem *pItem, |
607 | ItemDataKind dataKind); |
608 | |
609 | |
610 | /* Function: rt_ProcessMatItem ================================================= |
611 | * Abstract: |
612 | * This routine along with rt_WriteItemToMatFile() write out a specified |
613 | * mat-item the .mat file. Note that if the input argument |
614 | * cmd == 0, then this function just calculates the size of the item. |
615 | * cmd <> 0, this function writes the mat-item to the file. |
616 | * Return values is |
617 | * -1 : coding/logic error |
618 | * 0 : upon success |
619 | * > 0 : upon write failure (1) |
620 | */ |
621 | static int_T rt_ProcessMatItem(FILE *fp, |
622 | MatItem *pItem, |
623 | ItemDataKind itemKind, |
624 | int_T cmd) |
625 | { |
626 | mxClassID mxID = mxUNKNOWN_CLASS; |
627 | uint32_T arrayFlags[2] = {0, 0}; |
628 | int32_T *dims = NULL; |
629 | int32_T _dims[3] = {0, 0, 0}; |
630 | int32_T nDims = 2; |
631 | int32_T nBytesInItem = 0; |
632 | const char_T *itemName; |
633 | MatItem item; |
634 | int_T retStat = 0; |
635 | |
636 | switch (itemKind) { |
637 | case DATA_ITEM: { |
638 | (void)fprintf(stderr,"Unexpected itemKind = DATA_ITEM in " |
639 | "rt_ProcessMatItem @A\n"); |
640 | retStat = -1; |
641 | goto EXIT_POINT; |
642 | } |
643 | case MATRIX_ITEM: { |
644 | const MatrixData *var = (const MatrixData *) pItem->data; |
645 | |
646 | mxID = var->mxID; |
647 | arrayFlags[0] = mxID; |
648 | arrayFlags[0] |= var->logical; |
649 | arrayFlags[0] |= var->complex; |
650 | if (var->nDims < 2) { |
651 | dims = _dims; |
652 | dims[0] = var->nRows; |
653 | dims[1] = var->nCols; |
654 | nDims = 2; |
655 | } else { |
656 | int32_T k; |
657 | dims = (int32_T*)malloc(sizeof(int32_T)*(var->nDims+1)); |
658 | for (k = 0; k < var->nDims; k++) { |
659 | dims[k] = var->dims[k]; |
660 | } |
661 | dims[var->nDims] = var->nRows; |
662 | nDims = var->nDims + 1; |
663 | } |
664 | itemName = var->name; |
665 | break; |
666 | } |
667 | case STRUCT_LOG_VAR_ITEM: { |
668 | const StructLogVar *var = (const StructLogVar *) pItem->data; |
669 | |
670 | mxID = mxSTRUCT_CLASS; |
671 | arrayFlags[0] = mxID; |
672 | dims = _dims; |
673 | dims[0] = 1; |
674 | dims[1] = 1; |
675 | itemName = var->name; |
676 | break; |
677 | } |
678 | case SIGNALS_STRUCT_ITEM: { |
679 | const SignalsStruct *var = (const SignalsStruct *) pItem->data; |
680 | |
681 | mxID = mxSTRUCT_CLASS; |
682 | arrayFlags[0] = mxID; |
683 | dims = _dims; |
684 | dims[0] = 1; |
685 | dims[1] = var->numSignals; |
686 | itemName = &SIGNALS_FIELD_NAME; |
687 | break; |
688 | } |
689 | default: |
690 | (void)fprintf(stderr,"Unexpected itemKind=%d in rt_ProcessMatItem @B\n", |
691 | itemKind); |
692 | retStat = -1; |
693 | goto EXIT_POINT; |
694 | } |
695 | |
696 | /* array flags */ |
697 | item.nbytes = 2*sizeof(uint32_T); |
698 | if (cmd) { |
699 | item.type = matUINT32; |
700 | item.data = arrayFlags; |
701 | if (rt_WriteItemToMatFile(fp,&item, DATA_ITEM)) { |
702 | retStat = 1; |
703 | goto EXIT_POINT; |
704 | } |
705 | } else { |
706 | /*LINTED E_CAST_INT_TO_SMALL_INT*/ |
707 | nBytesInItem += matINT64_ALIGN(matTAG_SIZE + item.nbytes); |
708 | } |
709 | /* dimensions */ |
710 | /*LINTED E_ASSIGN_INT_TO_SMALL_INT*/ |
711 | item.nbytes = nDims*sizeof(int32_T); |
712 | if (cmd) { |
713 | item.type = matINT32; |
714 | item.data = dims; |
715 | if (rt_WriteItemToMatFile(fp,&item, DATA_ITEM)) { |
716 | retStat = 1; |
717 | goto EXIT_POINT; |
718 | } |
719 | } else { |
720 | /*LINTED E_CAST_INT_TO_SMALL_INT*/ |
721 | nBytesInItem += matINT64_ALIGN(matTAG_SIZE + item.nbytes); |
722 | } |
723 | /* name */ |
724 | item.nbytes = (int32_T)strlen(itemName); |
725 | if (cmd) { |
726 | item.type = matINT8; |
727 | item.data = (const char_T*) itemName; |
728 | if (rt_WriteItemToMatFile(fp,&item, DATA_ITEM)) { |
729 | retStat = 1; |
730 | goto EXIT_POINT; |
731 | } |
732 | } else { |
733 | nBytesInItem += (item.nbytes <= 4) ? /*LINTED E_CAST_INT_TO_SMALL_INT*/ |
734 | matTAG_SIZE : matINT64_ALIGN(matTAG_SIZE + item.nbytes); |
735 | } |
736 | |
737 | if (itemKind == MATRIX_ITEM) { |
738 | const MatrixData *var = (const MatrixData*) pItem->data; |
739 | int_T matID = rt_GetMatIdFromMxId(mxID); |
740 | size_t elSize = var->elSize; |
741 | |
742 | /* data */ |
743 | item.nbytes = (int32_T)(var->nRows * var->nCols * elSize); |
744 | if (cmd) { |
745 | item.type = matID; |
746 | item.data = var->re; |
747 | if (rt_WriteItemToMatFile(fp, &item, DATA_ITEM)) { |
748 | retStat = 1; |
749 | goto EXIT_POINT; |
750 | } |
751 | } else { |
752 | nBytesInItem += (item.nbytes <= 4) ? /*LINTED*/ |
753 | matTAG_SIZE : matINT64_ALIGN(matTAG_SIZE + item.nbytes); |
754 | } |
755 | /* imaginary part */ |
756 | if (var->complex) { |
757 | item.nbytes = (int32_T)(var->nRows * var->nCols * elSize); |
758 | if (cmd) { |
759 | item.type = matID; |
760 | item.data = var->im; |
761 | if (rt_WriteItemToMatFile(fp, &item, DATA_ITEM)) { |
762 | retStat = 1; |
763 | goto EXIT_POINT; |
764 | } |
765 | } else { |
766 | nBytesInItem += (item.nbytes <= 4) ? /*LINTED*/ |
767 | matTAG_SIZE : matINT64_ALIGN(matTAG_SIZE + item.nbytes); |
768 | } |
769 | } |
770 | } else { /* some type of structure item */ |
771 | const char_T *fieldNames; |
772 | int_T sizeofFieldNames; |
773 | |
774 | /* field names */ |
775 | switch (itemKind) { |
776 | case STRUCT_LOG_VAR_ITEM: { |
777 | const StructLogVar *var = (const StructLogVar *) pItem->data; |
778 | fieldNames = rtStructLogVarFieldNames; |
779 | sizeofFieldNames = var->numActiveFields * mxMAXNAM; |
780 | break; |
781 | } |
782 | case SIGNALS_STRUCT_ITEM: { |
783 | const SignalsStruct *var = (const SignalsStruct *) pItem->data; |
784 | fieldNames = var->fieldNames; |
785 | sizeofFieldNames = var->numActiveFields * mxMAXNAM; |
786 | break; |
787 | } |
788 | default: /* polyspace DEFECT:DEAD_CODE [Not a defect:Unset] |
789 | "Needed to handle an unknown itemKind" */ |
790 | (void)fprintf(stderr, "Unexpected itemKind=%d in " |
791 | "rt_ProcessMatItem @C\n", itemKind); |
792 | retStat = -1; |
793 | goto EXIT_POINT; |
794 | } |
795 | |
796 | /* write field names */ |
797 | if (cmd) { |
798 | int32_T tmpInt = mxMAXNAM; |
799 | |
800 | item.nbytes = sizeof(int32_T); |
801 | item.type = matINT32; |
802 | item.data = &tmpInt; |
803 | if (rt_WriteItemToMatFile(fp,&item, DATA_ITEM)) { |
804 | retStat = 1; |
805 | goto EXIT_POINT; |
806 | } |
807 | |
808 | item.nbytes = sizeofFieldNames; |
809 | item.type = matINT8; |
810 | item.data = (const char_T*) fieldNames; |
811 | if (rt_WriteItemToMatFile(fp,&item, DATA_ITEM)) { |
812 | retStat = 1; |
813 | goto EXIT_POINT; |
814 | } |
815 | } else { |
816 | /*LINTED E_CAST_INT_TO_SMALL_INT*/ |
817 | nBytesInItem += matINT64_ALIGN( matTAG_SIZE + matTAG_SIZE + |
818 | sizeofFieldNames ); |
819 | } |
820 | |
821 | /* process each field of the structure */ |
822 | switch (itemKind) { |
823 | case STRUCT_LOG_VAR_ITEM: { |
824 | const StructLogVar *var = pItem->data; |
825 | |
826 | /* time */ |
827 | { |
828 | const void *data = var->time; |
829 | |
830 | if (var->logTime) { /* time is a LogVar, get the MatrixData */ |
831 | data = &(((const LogVar*) (var->time))->data); |
832 | } |
833 | |
834 | item.type = matMATRIX; |
835 | item.data = data; |
836 | if (cmd) { |
837 | if (rt_WriteItemToMatFile(fp,&item,MATRIX_ITEM)){ |
838 | retStat = 1; |
839 | goto EXIT_POINT; |
840 | } |
841 | } else { |
842 | if (rt_ProcessMatItem(fp, &item, MATRIX_ITEM,0)){ |
843 | retStat = 1; |
844 | goto EXIT_POINT; |
845 | } |
846 | nBytesInItem += item.nbytes + matTAG_SIZE; |
847 | } |
848 | } |
849 | |
850 | /* signals */ |
851 | item.type = matMATRIX; |
852 | item.data = &(var->signals); |
853 | if (cmd) { |
854 | if (rt_WriteItemToMatFile(fp,&item,SIGNALS_STRUCT_ITEM)) { |
855 | retStat = 1; |
856 | goto EXIT_POINT; |
857 | } |
858 | } else { |
859 | if (rt_ProcessMatItem(fp, &item, SIGNALS_STRUCT_ITEM,0)) { |
860 | retStat = 1; |
861 | goto EXIT_POINT; |
862 | } |
863 | nBytesInItem += item.nbytes + matTAG_SIZE; |
864 | } |
865 | |
866 | /* block name */ |
867 | if (var->blockName != NULL) { |
868 | item.type = matMATRIX; |
869 | item.data = var->blockName; |
870 | if (cmd) { |
871 | if (rt_WriteItemToMatFile(fp, &item, MATRIX_ITEM)) { |
872 | retStat = 1; |
873 | goto EXIT_POINT; |
874 | } |
875 | } else { |
876 | if (rt_ProcessMatItem(fp, &item, MATRIX_ITEM, 0)) { |
877 | retStat = 1; |
878 | goto EXIT_POINT; |
879 | } |
880 | nBytesInItem += item.nbytes + matTAG_SIZE; |
881 | } |
882 | } |
883 | break; |
884 | } |
885 | case SIGNALS_STRUCT_ITEM: { |
886 | const SignalsStruct *var = pItem->data; |
887 | const LogVar *values = var->values; |
888 | const MatrixData *dimensions = var->dimensions; |
889 | const MatrixData *labels = var->labels; |
890 | const MatrixData *plotStyles = var->plotStyles; |
891 | const MatrixData *titles = var->titles; |
892 | const MatrixData *blockNames = var->blockNames; |
893 | const MatrixData *stateNames = var->stateNames; |
894 | const MatrixData *crossMdlRef = var->crossMdlRef; |
895 | const boolean_T logValueDimensions = var->logValueDimensions; |
896 | int_T i; |
897 | |
898 | for (i = 0; i < var->numSignals; i++) { |
899 | /* values */ |
900 | item.type = matMATRIX; |
901 | item.data = &(values->data); |
902 | if (cmd) { |
903 | if (rt_WriteItemToMatFile(fp, &item,MATRIX_ITEM)) { |
904 | retStat = 1; |
905 | goto EXIT_POINT; |
906 | } |
907 | } else { |
908 | if (rt_ProcessMatItem(fp, &item, MATRIX_ITEM, 0)) { |
909 | retStat = 1; |
910 | goto EXIT_POINT; |
911 | } |
912 | nBytesInItem += item.nbytes + matTAG_SIZE; |
913 | } |
914 | |
915 | if(logValueDimensions) |
916 | { |
917 | /* valueDimensions */ |
918 | /* Since the functions rt_WriteItemToMatFile and |
919 | rt_ProcessMatItem deal with MatrixData, |
920 | convert valDims to tempData, and fill up the |
921 | necessary fields. |
922 | */ |
923 | MatrixData tempData; |
924 | (void)memcpy(tempData.name, &VALUEDIMENSIONS_FIELD_NAME, mxMAXNAM); |
925 | tempData.nRows = values->valDims->nRows; |
926 | tempData.nCols = values->valDims->nCols; |
927 | tempData.nDims = 1; |
928 | tempData._dims[0] = values->valDims->nCols; |
929 | tempData.re = values->valDims->dimsData; |
930 | tempData.im = NULL; |
931 | tempData.dTypeID = SS_DOUBLE; |
932 | tempData.elSize = sizeof(real_T); |
933 | tempData.mxID = mxDOUBLE_CLASS; |
934 | tempData.logical = 0; |
935 | tempData.complex = 0; |
936 | tempData.frameData = 0; |
937 | tempData.frameSize = 1; |
938 | |
939 | item.type = matMATRIX; |
940 | item.data = &tempData; /*values->valDims;*/ |
941 | |
942 | if (cmd) { |
943 | if (rt_WriteItemToMatFile(fp, &item,MATRIX_ITEM)) { |
944 | retStat = 1; |
945 | goto EXIT_POINT; |
946 | } |
947 | } else { |
948 | if (rt_ProcessMatItem(fp, &item, MATRIX_ITEM, 0)) { |
949 | retStat = 1; |
950 | goto EXIT_POINT; |
951 | } |
952 | nBytesInItem += item.nbytes + matTAG_SIZE; |
953 | } |
954 | } |
955 | values = values->next; |
956 | |
957 | /* dimensions */ |
958 | if (dimensions != NULL) { |
959 | item.type = matMATRIX; |
960 | item.data = &(dimensions[i]); |
961 | if (cmd) { |
962 | if (rt_WriteItemToMatFile(fp,&item, MATRIX_ITEM)) { |
963 | retStat = 1; |
964 | goto EXIT_POINT; |
965 | } |
966 | } else { |
967 | if (rt_ProcessMatItem(fp, &item, MATRIX_ITEM, 0)) { |
968 | retStat = 1; |
969 | goto EXIT_POINT; |
970 | } |
971 | nBytesInItem += item.nbytes + matTAG_SIZE; |
972 | } |
973 | } |
974 | |
975 | /* label */ |
976 | item.type = matMATRIX; |
977 | item.data = &(labels[i]); |
978 | if (cmd) { |
979 | if (rt_WriteItemToMatFile(fp, &item,MATRIX_ITEM)) { |
980 | retStat = 1; |
981 | goto EXIT_POINT; |
982 | } |
983 | } else { |
984 | if (rt_ProcessMatItem(fp, &item, MATRIX_ITEM, 0)) { |
985 | retStat = 1; |
986 | goto EXIT_POINT; |
987 | } |
988 | nBytesInItem += item.nbytes + matTAG_SIZE; |
989 | } |
990 | /* title */ |
991 | if (titles != NULL) { |
992 | item.type = matMATRIX; |
993 | item.data = &(titles[i]); |
994 | if (cmd) { |
995 | if (rt_WriteItemToMatFile(fp, &item, MATRIX_ITEM)) { |
996 | retStat = 1; |
997 | goto EXIT_POINT; |
998 | } |
999 | } else { |
1000 | if (rt_ProcessMatItem(fp, &item, MATRIX_ITEM, 0)) { |
1001 | retStat = 1; |
1002 | goto EXIT_POINT; |
1003 | } |
1004 | nBytesInItem += item.nbytes + matTAG_SIZE; |
1005 | } |
1006 | } |
1007 | /* plot style */ |
1008 | if (plotStyles != NULL) { |
1009 | item.type = matMATRIX; |
1010 | item.data = &(plotStyles[i]); |
1011 | if (cmd) { |
1012 | if (rt_WriteItemToMatFile(fp,&item, MATRIX_ITEM)) { |
1013 | retStat = 1; |
1014 | goto EXIT_POINT; |
1015 | } |
1016 | } else { |
1017 | if (rt_ProcessMatItem(fp, &item, MATRIX_ITEM, 0)) { |
1018 | retStat = 1; |
1019 | goto EXIT_POINT; |
1020 | } |
1021 | nBytesInItem += item.nbytes + matTAG_SIZE; |
1022 | } |
1023 | } |
1024 | /* block name */ |
1025 | if (blockNames != NULL) { |
1026 | item.type = matMATRIX; |
1027 | item.data = &(blockNames[i]); |
1028 | if (cmd) { |
1029 | if (rt_WriteItemToMatFile(fp, &item, MATRIX_ITEM)) { |
1030 | retStat = 1; |
1031 | goto EXIT_POINT; |
1032 | } |
1033 | } else { |
1034 | if (rt_ProcessMatItem(fp, &item, MATRIX_ITEM, 0)) { |
1035 | retStat = 1; |
1036 | goto EXIT_POINT; |
1037 | } |
1038 | nBytesInItem += item.nbytes + matTAG_SIZE; |
1039 | } |
1040 | } |
1041 | /* state name */ |
1042 | if (stateNames != NULL) { |
1043 | item.type = matMATRIX; |
1044 | item.data = &(stateNames[i]); |
1045 | if (cmd) { |
1046 | if (rt_WriteItemToMatFile(fp, &item, MATRIX_ITEM)) { |
1047 | retStat = 1; |
1048 | goto EXIT_POINT; |
1049 | } |
1050 | } else { |
1051 | if (rt_ProcessMatItem(fp, &item, MATRIX_ITEM, 0)) { |
1052 | retStat = 1; |
1053 | goto EXIT_POINT; |
1054 | } |
1055 | nBytesInItem += item.nbytes + matTAG_SIZE; |
1056 | } |
1057 | } |
1058 | /* crossMdlRef */ |
1059 | if (crossMdlRef != NULL) { |
1060 | item.type = matMATRIX; |
1061 | item.data = &(crossMdlRef[i]); |
1062 | if (cmd) { |
1063 | if (rt_WriteItemToMatFile(fp, &item, MATRIX_ITEM)) { |
1064 | retStat = 1; |
1065 | goto EXIT_POINT; |
1066 | } |
1067 | } else { |
1068 | if (rt_ProcessMatItem(fp, &item, MATRIX_ITEM, 0)) { |
1069 | retStat = 1; |
1070 | goto EXIT_POINT; |
1071 | } |
1072 | nBytesInItem += item.nbytes + matTAG_SIZE; |
1073 | } |
1074 | } |
1075 | } /* for i=1:numSignals */ |
1076 | break; |
1077 | } |
1078 | default: /* polyspace DEFECT:DEAD_CODE [Not a defect:Unset] |
1079 | "Needed to handle an unknown itemKind" */ |
1080 | (void)fprintf(stderr, "Unexpected itemKind=%d in " |
1081 | "rt_ProcessMatItem @D\n", itemKind); |
1082 | retStat = -1; |
1083 | goto EXIT_POINT; |
1084 | } |
1085 | } /* end struct item */ |
1086 | |
1087 | if (!cmd) { |
1088 | pItem->nbytes = nBytesInItem; |
1089 | } |
1090 | |
1091 | EXIT_POINT: |
1092 | if (dims != _dims) { |
1093 | FREE(dims); |
1094 | } |
1095 | return(retStat); |
1096 | |
1097 | } /* end rt_ProcessMatItem */ |
1098 | |
1099 | |
1100 | /* Function: rt_WriteItemToMatFile ============================================= |
1101 | * Abstract: |
1102 | * Entry function for writing out a mat item to the mat file. |
1103 | * |
1104 | * Return values is |
1105 | * == 0 : upon success |
1106 | * <> 0 : upon failure |
1107 | */ |
1108 | static int_T rt_WriteItemToMatFile(FILE *fp, |
1109 | MatItem *pItem, |
1110 | ItemDataKind itemKind) |
1111 | { |
1112 | /* Determine the item size */ |
1113 | if (pItem->type == matMATRIX) { |
1114 | if (rt_ProcessMatItem(fp, pItem, itemKind, 0)) return(1); |
1115 | } |
1116 | |
1117 | /* Write the item tag and data */ |
1118 | if (pItem->nbytes > 4) { |
1119 | int32_T nAlignBytes; |
1120 | |
1121 | if (fwrite(pItem, 1, matTAG_SIZE, fp) != matTAG_SIZE) return(1); |
1122 | |
1123 | if (pItem->type == matMATRIX) { |
1124 | if (rt_ProcessMatItem(fp, pItem, itemKind, 1)) return(1); |
1125 | } else { |
1126 | if ( fwrite(pItem->data, 1, pItem->nbytes, fp) != |
1127 | ((size_t) pItem->nbytes) ) { |
1128 | return(1); |
1129 | } |
1130 | } |
1131 | |
1132 | /* Add offset for 8-byte alignment */ |
1133 | nAlignBytes = matINT64_ALIGN(pItem->nbytes) - pItem->nbytes; |
1134 | if (nAlignBytes > 0) { |
1135 | int pad[2] = {0, 0}; |
1136 | if ( fwrite(pad,1,nAlignBytes,fp) != ((size_t) nAlignBytes) ) { |
1137 | return(1); |
1138 | } |
1139 | } |
1140 | } else { |
1141 | MatItem item = {0, 0, NULL}; |
1142 | item.type = ((uint32_T)(pItem->type))|(((uint32_T)(pItem->nbytes))<<16); |
1143 | (void)memcpy(&item.nbytes, pItem->data, pItem->nbytes); |
1144 | if (fwrite(&item, 1, matTAG_SIZE, fp) != matTAG_SIZE) return(1); |
1145 | } |
1146 | |
1147 | return(0); |
1148 | |
1149 | } /* end rt_WriteItemToMatFile */ |
1150 | |
1151 | |
1152 | /* Function: rt_WriteMat5FileHeader ============================================ |
1153 | * Abstract: |
1154 | * Function to write the mat file header. |
1155 | * Return values is |
1156 | * == 0 : upon success |
1157 | * <> 0 : upon failure |
1158 | */ |
1159 | static int_T rt_WriteMat5FileHeader(FILE *fp) |
1160 | { |
1161 | int_T nbytes; |
1162 | int_T nspaces; |
1163 | int_T i, n; |
1164 | unsigned short ver[2]; |
1165 | char_T spaces[16]; |
1166 | const char_T *matversion = "MATLAB 5.0 MAT-file"; |
1167 | |
1168 | (void)memset(spaces, ' ', sizeof(spaces)); |
1169 | |
1170 | n = (int_T)strlen(matversion); |
1171 | nbytes = (int_T)fwrite(matversion, 1, n, fp); |
1172 | /*LINTED E_ASSIGN_INT_TO_SMALL_INT*/ |
1173 | nspaces = matVERSION_INFO_OFFSET - nbytes; |
1174 | /*LINTED E_ASSIGN_INT_TO_SMALL_INT*/ |
1175 | n = nspaces % sizeof(spaces); |
1176 | nbytes += (int_T)fwrite(spaces, 1, n, fp); |
1177 | /*LINTED E_ASSIGN_INT_TO_SMALL_INT*/ |
1178 | n = nspaces / sizeof(spaces); |
1179 | for (i = 0; i < n; ++i) { |
1180 | nbytes += (int_T)fwrite(spaces, 1, sizeof(spaces), fp); |
1181 | } |
1182 | if (nbytes == matVERSION_INFO_OFFSET) { |
1183 | ver[0] = matVERSION; |
1184 | ver[1] = matKEY; |
1185 | nbytes += (int_T)fwrite(ver, 1, sizeof(ver), fp); |
1186 | } |
1187 | return(nbytes != matVERSION_INFO_OFFSET + sizeof(ver)); |
1188 | |
1189 | } /* end rt_WriteMat5FileHeader */ |
1190 | |
1191 | |
1192 | /* Function: rt_FixupLogVar ==================================================== |
1193 | * Abstract: |
1194 | * Make the logged variable suitable for MATLAB. |
1195 | */ |
1196 | static const char_T *rt_FixupLogVar(LogVar *var,int verbose) |
1197 | { |
1198 | int_T nCols = var->data.nCols; |
1199 | int_T maxRows = var->data.nRows; |
1200 | int_T nDims = var->data.nDims; |
1201 | size_t elSize = var->data.elSize; |
1202 | int_T nRows = (var->wrapped ? maxRows : var->rowIdx); |
1203 | |
1204 | var->nDataPoints = var->rowIdx + var->wrapped * maxRows; |
1205 | |
1206 | if (var->wrapped > 1 || (var->wrapped == 1 && var->rowIdx != 0)) { |
1207 | /* |
1208 | * Warn the user the circular buffer has wrapped, implying that |
1209 | * some data has been lost. |
1210 | */ |
1211 | if( verbose) { |
1212 | (void)fprintf(stdout, |
1213 | "*** Log variable %s has wrapped %d times\n" |
1214 | " using a circular buffer of size %d\n", |
1215 | var->data.name, var->wrapped, var->data.nRows); |
1216 | } |
1217 | if (var->usingDefaultBufSize) { |
1218 | /* |
1219 | * If wrapping occurred using the default buffer size, |
1220 | * let the user know what size buffer to use in the |
1221 | * future to avoid wrapping. If the default buffer |
1222 | * size was not used, the user has no control to specify |
1223 | * the correct value. Wrapping may occur when not using |
1224 | * the default buffer if we allocated too small a buffer |
1225 | * size for this logvar. One common case is a toWorkspace |
1226 | * block inside of an iterative subsystem - we can not take |
1227 | * the number of iterations into account (they may be |
1228 | * variable) when allocating the buffer. In this case, |
1229 | * just warn the buffer wrapped and don't tell user they |
1230 | * can override the buffer size. |
1231 | */ |
1232 | if( verbose ) { |
1233 | (void)fprintf(stdout, |
1234 | "*** To avoid wrapping, explicitly specify a\n" |
1235 | " buffer size of %d in your Simulink model\n" |
1236 | " by adding OPTS=\"-DDEFAULT_BUFFER_SIZE=%d\"\n" |
1237 | " as an argument to the ConfigSet MakeCommand\n" |
1238 | " parameter\n", |
1239 | var->nDataPoints, var->nDataPoints); |
1240 | } |
1241 | } |
1242 | } |
1243 | |
1244 | if (nDims < 2 && nCols > 1) { /* Transpose? */ |
1245 | /* Don't need to transpose valueDimensions */ |
1246 | int_T nEl = nRows*nCols; |
1247 | char *src = var->data.re; |
1248 | char *pmT; |
1249 | int_T k; |
1250 | |
1251 | /********************************** |
1252 | * If memory cannot be allocated, * |
1253 | * write to a temporary buffer * |
1254 | **********************************/ |
1255 | if ((pmT = malloc(nEl*elSize)) == NULL) { |
1256 | FILE *fptr; |
1257 | char fName[mxMAXNAM+13]; |
1258 | |
1259 | (void)sprintf(fName, "%s%s", var->data.name, "_rtw_tmw.tmw"); |
1260 | if ((fptr=fopen(fName,"w+b")) == NULL) { |
1261 | (void)fprintf(stderr,"*** Error opening %s",fName); |
1262 | return("unable to open data file\n"); |
1263 | } |
1264 | |
1265 | /**************************** |
1266 | * Write the data to a file * |
1267 | ****************************/ |
1268 | for (k=0; k<nEl; k++) { |
1269 | int_T kT = nCols*(k%nRows) + (k/nRows); |
1270 | char *dst = src + kT*elSize; |
1271 | (void)fwrite(dst, elSize, 1, fptr); |
1272 | } |
1273 | if (var->data.complex) { |
1274 | char *pmiT = var->data.re; |
1275 | src = var->data.im; |
1276 | for (k=0; k<nEl; k++) { |
1277 | int_T kT = nRows*(k%nCols) + (k/nCols); |
1278 | char *dst = pmiT + kT*elSize; |
1279 | (void)memcpy(dst, src, elSize); |
1280 | src += elSize; |
1281 | } |
1282 | var->data.re = var->data.im; |
1283 | var->data.im = pmiT; |
1284 | } |
1285 | |
1286 | /******************************* |
1287 | * Read the data from the file * |
1288 | *******************************/ |
1289 | (void)rewind(fptr); |
1290 | (void)fread(var->data.re, elSize, nEl, fptr); |
1291 | (void)fclose(fptr); |
1292 | (void)remove(fName); |
1293 | } else { |
1294 | for (k=0; k<nEl; k++) { |
1295 | int_T kT = nRows*(k%nCols) + (k/nCols); |
1296 | char *dst = pmT + kT*elSize; |
1297 | (void)memcpy(dst, src, elSize); |
1298 | src += elSize; |
1299 | } |
1300 | if (var->data.complex) { |
1301 | char *pmiT = var->data.re; |
1302 | src = var->data.im; |
1303 | for (k=0; k<nEl; k++) { |
1304 | int_T kT = nRows*(k%nCols) + (k/nCols); |
1305 | char *dst = pmiT + kT*elSize; |
1306 | (void)memcpy(dst, src, elSize); |
1307 | src += elSize; |
1308 | } |
1309 | var->data.re = var->data.im; |
1310 | var->data.im = pmiT; |
1311 | } |
1312 | FREE(var->data.re); |
1313 | var->data.re = pmT; |
1314 | } |
1315 | } /* Transpose? */ |
1316 | |
1317 | if (var->wrapped > 0 && var->rowIdx != 0 ) { /* Rotate? */ |
1318 | char_T *buffer = var->data.re; |
1319 | int_T done = 0; /* done: 0 (1) rotate real (imag) part. */ |
1320 | |
1321 | do { |
1322 | char_T *col = buffer; |
1323 | int_T rowOffset = (int_T)((nDims == 1) ? (elSize) : (elSize * nCols)); |
1324 | int_T colOffset = (int_T)((nDims == 1)? (nRows*elSize) : elSize); |
1325 | int_T zeroIdx = var->rowIdx; |
1326 | int_T j; |
1327 | |
1328 | for (j = 0 ; j < nCols; ++j, col += colOffset) { |
1329 | int_T swapCount; |
1330 | int_T srcIdx; |
1331 | int_T dstIdx; |
1332 | int_T tmpIdx; |
1333 | MatReal tmp; |
1334 | |
1335 | for (tmpIdx=0, swapCount=0; swapCount < nRows; tmpIdx++) { |
1336 | (void)memcpy(&tmp, col + tmpIdx*rowOffset, elSize); |
1337 | |
1338 | dstIdx=tmpIdx; |
1339 | srcIdx = ((dstIdx + zeroIdx) % nRows); |
1340 | while (srcIdx != tmpIdx) { |
1341 | (void)memcpy(col + dstIdx*rowOffset, |
1342 | col + srcIdx*rowOffset, |
1343 | elSize); |
1344 | ++swapCount; |
1345 | dstIdx = srcIdx; |
1346 | srcIdx = ((dstIdx + zeroIdx) % nRows); |
1347 | |
1348 | } |
1349 | (void)memcpy(col + dstIdx*rowOffset, &tmp, elSize); |
1350 | ++swapCount; |
1351 | } |
1352 | } |
1353 | done ++; |
1354 | /* need to rotate the imaginary part */ |
1355 | } while ((done == 1) && ((buffer = var->data.im) != NULL)); |
1356 | |
1357 | var->rowIdx = 0; |
1358 | } /* Rotate? */ |
1359 | |
1360 | /* |
1361 | * We might have allocated more number of rows than the number of data |
1362 | * points that have been logged, in which case set nRows to nDataPoints |
1363 | * so that only these values get saved. |
1364 | */ |
1365 | if (var->nDataPoints < var->data.nRows) { |
1366 | var->data.nRows = var->nDataPoints; |
1367 | if(var->valDims != NULL){ |
1368 | size_t elSizeValDims = sizeof(real_T); |
1369 | int_T k; |
1370 | real_T *dimsData = var->valDims->dimsData + nRows; |
1371 | /* |
1372 | Keep nRows of values and that of valueDimensions consistent |
1373 | for variable-size signals. |
1374 | */ |
1375 | var->valDims->nRows = var->data.nRows; |
1376 | /* |
1377 | Also need to move data when shrinking the array size, |
1378 | because valueDimensions data is stored in array format. |
1379 | e.g. maxRows = 4; nRows = 2; nDims = 3; |
1380 | Before fixing up the logVar, the locations of data are as below: |
1381 | (x, y, z -- useful data / o -- junk) |
1382 | a[0] = x a[4] = y a[8] = z |
1383 | a[1] = x a[5] = y a[9] = z |
1384 | a[2] = o a[6] = o a[10]= o |
1385 | a[3] = o a[7] = o a[11]= o |
1386 | After fixing up the logVar, we want the data to be stored as: |
1387 | a[0] = x a[4] = z a[8] = o |
1388 | a[1] = x a[5] = z a[9] = o |
1389 | a[2] = y a[6] = o a[10]= o |
1390 | a[3] = y a[7] = o a[11]= o |
1391 | */ |
1392 | for(k = 1; k < nDims; k++){ |
1393 | (void) memmove(dimsData, |
1394 | var->valDims->dimsData + k*maxRows, |
1395 | elSizeValDims * nRows); |
1396 | dimsData += nRows; |
1397 | } |
1398 | } |
1399 | } |
1400 | return(NULL); |
1401 | |
1402 | } /* end rt_FixupLogVar */ |
1403 | |
1404 | |
1405 | /* Function: rt_LoadModifiedLogVarName ========================================= |
1406 | * Abstract: |
1407 | * The name of the logged variable is obtained from the input argument |
1408 | * varName and the nameModifier which is obtained from the simstruct. If |
1409 | * the nameModifier begins with an '_', then nameModifier is post-pended to |
1410 | * varName to obtain the name of the logged variable. If the first |
1411 | * character does not begin with an '_', then the nameModifier is |
1412 | * pre-pended to varName. |
1413 | * |
1414 | * Examples: |
1415 | * a) varName = "tout" & nameModifier = "_rt" => logVarName = "tout_rt" |
1416 | * b) varName = "tout" & nameModifier = "rt_" => logVarName = "rt_tout" |
1417 | * c) varName = "tout" & nameModifier = "none" => logVarName = "tout" |
1418 | */ |
1419 | static void rt_LoadModifiedLogVarName(const RTWLogInfo *li, /* in */ |
1420 | const char *varName, /* in */ |
1421 | char *logVarName) /* out */ |
1422 | { |
1423 | int_T nameLen; |
1424 | const char_T *nameModifier = rtliGetLogVarNameModifier(li); |
1425 | |
1426 | if (nameModifier != NULL && strcmp(nameModifier,"none")==0) { |
1427 | nameModifier = NULL; |
1428 | } |
1429 | |
1430 | logVarName[mxMAXNAM-1] = '\0'; |
1431 | if (nameModifier == NULL) { |
1432 | (void)strncpy(logVarName, varName, mxMAXNAM-1); |
1433 | } else if (nameModifier[0] == '_') { |
1434 | (void)strncpy(logVarName, varName, mxMAXNAM-1); |
1435 | nameLen = (int_T)strlen(logVarName); |
1436 | (void)strncat(logVarName, nameModifier, (size_t)mxMAXNAM-1-nameLen); |
1437 | } else { |
1438 | (void)strncpy(logVarName, nameModifier, mxMAXNAM-1); |
1439 | nameLen = (int_T)strlen(logVarName); |
1440 | (void)strncat(logVarName, varName, (size_t)mxMAXNAM-1-nameLen); |
1441 | } |
1442 | |
1443 | } /* end rt_LoadModifiedLogVarName */ |
1444 | |
1445 | |
1446 | /* Function: rt_GetActualDTypeID =============================================== |
1447 | * Abstract: |
1448 | * Given a built-in data type id, return the actual data type id. |
1449 | * The only time these are different is when real_T has been mapped |
1450 | * to a single. |
1451 | */ |
1452 | #if defined(_MSC_VER) |
1453 | #pragma warning(push) |
1454 | #pragma warning(disable: 4127) |
1455 | #endif |
1456 | static BuiltInDTypeId rt_GetActualDTypeID(BuiltInDTypeId dTypeID) |
1457 | { |
1458 | /*LINTED E_FALSE_LOGICAL_EXPR*/ |
1459 | if (dTypeID == SS_DOUBLE && sizeof(real_T) != 8) { /* polyspace DEFECT:DEAD_CODE |
1460 | [Not a defect:Unset] |
1461 | "Needed for when real_T has been |
1462 | mapped to a single" */ |
1463 | return(SS_SINGLE); |
1464 | } else { |
1465 | return(dTypeID); |
1466 | } |
1467 | |
1468 | } /* end rt_GetActualDTypeID */ |
1469 | #if defined(_MSC_VER) |
1470 | #pragma warning(pop) |
1471 | #endif |
1472 | |
1473 | |
1474 | /* Function: rt_DestroyLogVar ================================================== |
1475 | * Abstract: |
1476 | * Destroy the log var linked list. |
1477 | */ |
1478 | static void rt_DestroyLogVar(LogVar *head) |
1479 | { |
1480 | while(head) { |
1481 | LogVar *var = head; |
1482 | head = var->next; |
1483 | FREE(var->data.re); |
1484 | FREE(var->data.im); |
1485 | if (var->data.dims != var->data._dims) { |
1486 | FREE(var->data.dims); |
1487 | } |
1488 | /* free valDims if necessary */ |
1489 | if(var->valDims != NULL) { |
1490 | FREE(var->valDims->dimsData); |
1491 | FREE(var->valDims); |
1492 | } |
1493 | /* free coords, strides and currStrides if necessary */ |
1494 | FREE(var->coords); |
1495 | FREE(var->strides); |
1496 | FREE(var->currStrides); |
1497 | |
1498 | FREE(var); |
1499 | } |
1500 | |
1501 | } /* end rt_DestroyLogVar */ |
1502 | |
1503 | |
1504 | /* Function: rt_DestroyStructLogVar ============================================ |
1505 | * Abstract: |
1506 | * Destroy the struct log var linked list. |
1507 | */ |
1508 | static void rt_DestroyStructLogVar(StructLogVar *head) |
1509 | { |
1510 | while(head) { |
1511 | StructLogVar *var = head; |
1512 | |
1513 | head = var->next; |
1514 | |
1515 | if (var->logTime) { /* time is LogVar */ |
1516 | rt_DestroyLogVar(var->time); |
1517 | } else { /* time is MatrixData */ |
1518 | FREE(var->time); |
1519 | } |
1520 | rt_DestroyLogVar(var->signals.values); |
1521 | FREE(var->signals.labels); |
1522 | FREE(var->signals.plotStyles); |
1523 | FREE(var->signals.dimensions); |
1524 | FREE(var->signals.titles); |
1525 | FREE(var->signals.blockNames); |
1526 | FREE(var->signals.stateNames); |
1527 | FREE(var->signals.crossMdlRef); |
1528 | FREE(var->blockName); |
1529 | FREE(var); |
1530 | } |
1531 | |
1532 | } /* end rt_DestroyStructLogVar */ |
1533 | |
1534 | |
1535 | /* Function: rt_InitSignalsStruct ============================================== |
1536 | * Abstract: |
1537 | * Initialize the signals structure in the struct log variable. |
1538 | * |
1539 | * Returns: |
1540 | * == NULL => success. |
1541 | * ~= NULL => failure, the return value is a pointer to the error |
1542 | * message, which is also set in the simstruct. |
1543 | */ |
1544 | static const char_T *rt_InitSignalsStruct(RTWLogInfo *li, |
1545 | const real_T startTime, |
1546 | const real_T finalTime, |
1547 | const real_T inStepSize, |
1548 | const char_T **errStatus, |
1549 | StructLogVar *var, |
1550 | int_T maxRows, |
1551 | int_T decimation, |
1552 | real_T sampleTime, |
1553 | const RTWLogSignalInfo *sigInfo) |
1554 | { |
1555 | int_T i, sigIdx; |
1556 | SignalsStruct *sig = &(var->signals); |
1557 | int_T nSignals = sigInfo->numSignals; |
1558 | const int_T *numCols = sigInfo->numCols; |
1559 | const int_T *numDims = sigInfo->numDims; |
1560 | const int_T *dims = sigInfo->dims; |
1561 | const BuiltInDTypeId *dTypes = sigInfo->dataTypes; |
1562 | const int_T *cSgnls = sigInfo->complexSignals; |
1563 | const int_T *fData = sigInfo->frameData; |
1564 | const char_T **labels = sigInfo->labels.cptr; |
1565 | const int_T *plotStyles = sigInfo->plotStyles; |
1566 | const char_T *titles = sigInfo->titles; |
1567 | const int_T *titleLen = sigInfo->titleLengths; |
1568 | const char_T **blockNames = sigInfo->blockNames.cptr; |
1569 | const char_T **stateNames = sigInfo->stateNames.cptr; |
1570 | const boolean_T *crossMdlRef = sigInfo->crossMdlRef; |
1571 | |
1572 | void **currSigDims = sigInfo->currSigDims; |
1573 | int_T *currSigDimsSize = sigInfo->currSigDimsSize; |
1574 | LogVar *prevValues = NULL; |
1575 | int_T dimsOffset = 0; |
1576 | boolean_T *isVarDims = sigInfo->isVarDims; |
1577 | /* if any signal is variable-size, the field 'valueDimensions' is needed */ |
1578 | boolean_T logValueDimensions = false; |
1579 | const RTWLogDataTypeConvert *pDTConvInfo = sigInfo->dataTypeConvert; |
1580 | |
1581 | /* reset error status */ |
1582 | *errStatus = NULL; |
1583 | |
1584 | sig->numActiveFields = 1; |
1585 | sig->numSignals = nSignals; |
1586 | |
1587 | sig->isVarDims = isVarDims; |
1588 | /* check whether we need valueDimensions field*/ |
1589 | for (i=0; i<nSignals; i++){ |
1590 | if(isVarDims[i]){ |
1591 | logValueDimensions = true; |
1592 | break; |
1593 | } |
1594 | } |
1595 | |
1596 | /* values */ |
1597 | dimsOffset = 0; |
1598 | for (i = 0; i < nSignals; i++) { |
1599 | BuiltInDTypeId dt = (dTypes) ? dTypes[i] : SS_DOUBLE; |
1600 | int_T cs = (cSgnls) ? cSgnls[i] : 0; |
1601 | int_T fd = (fData) ? fData[i] : 0; |
1602 | int_T nd = (numDims) ? numDims[i] : 1; |
1603 | |
1604 | const RTWLogDataTypeConvert *pDTConvInfoCur = |
1605 | (pDTConvInfo) ? (pDTConvInfo+i) : 0; |
1606 | |
1607 | LogVar *values = NULL; |
1608 | LogValDimsStat logValDimsStat; |
1609 | |
1610 | if(!logValueDimensions){ |
1611 | logValDimsStat = NO_LOGVALDIMS; |
1612 | } |
1613 | else{ |
1614 | logValDimsStat = isVarDims[i] ? LOGVALDIMS_VARDIMS : |
1615 | LOGVALDIMS_EMPTYMX; |
1616 | } |
1617 | |
1618 | values = rt_CreateLogVarWithConvert(li, startTime, finalTime, |
1619 | inStepSize, errStatus, |
1620 | &VALUES_FIELD_NAME, |
1621 | dt, |
1622 | pDTConvInfoCur, |
1623 | 0, cs, fd, |
1624 | numCols[i],nd, |
1625 | dims + dimsOffset, |
1626 | logValDimsStat, |
1627 | currSigDims + dimsOffset, |
1628 | currSigDimsSize + dimsOffset, |
1629 | maxRows,decimation,sampleTime, 0); |
1630 | |
1631 | if (values == NULL) goto ERROR_EXIT; |
1632 | |
1633 | if (sig->values == NULL) { |
1634 | sig->values = values; |
1635 | } else { |
1636 | if (prevValues == NULL) goto ERROR_EXIT; |
1637 | prevValues->next = values; |
1638 | } |
1639 | prevValues = values; |
1640 | dimsOffset += nd; |
1641 | } |
1642 | |
1643 | if(logValueDimensions){ |
1644 | ++sig->numActiveFields; |
1645 | sig->logValueDimensions = true; |
1646 | } |
1647 | else{ |
1648 | sig->logValueDimensions = false; |
1649 | } |
1650 | |
1651 | /* Dimensions */ |
1652 | { |
1653 | real_T *data; |
1654 | size_t nbytes; |
1655 | int_T dataLen = 0; |
1656 | BuiltInDTypeId dTypeId = rt_GetActualDTypeID(SS_DOUBLE); |
1657 | size_t dataOffset = nSignals*sizeof(MatrixData); |
1658 | uint_T overhang = (uint_T)(dataOffset % sizeof(real_T)); |
1659 | |
1660 | if (overhang) { /* polyspace DEFECT:DEAD_CODE [Not a defect:Unset] |
1661 | "Needed for possible padding determination. */ |
1662 | dataOffset += (sizeof(real_T) - overhang); |
1663 | } |
1664 | for (i=0; i< nSignals; i++) { |
1665 | int_T nd = (numDims) ? numDims[i] : 1; |
1666 | dataLen += nd; |
1667 | } |
1668 | nbytes = dataOffset + dataLen*sizeof(real_T); |
1669 | |
1670 | if ( (sig->dimensions = calloc(nbytes, 1)) == NULL ) goto ERROR_EXIT; |
1671 | |
1672 | data = (real_T*) (((char_T*) (sig->dimensions)) + dataOffset); |
1673 | |
1674 | for (i = 0; i < dataLen; i++) { |
1675 | data[i] = dims[i]; /* cannot memcpy double <- int */ |
1676 | } |
1677 | |
1678 | for (i = 0; i < nSignals; i++) { |
1679 | MatrixData *mtxData = &(sig->dimensions[i]); |
1680 | int_T nd = (numDims) ? numDims[i] : 1; |
1681 | |
1682 | (void)memcpy(mtxData->name, &DIMENSION_FIELD_NAME, mxMAXNAM); |
1683 | |
1684 | mtxData->nRows = 1; |
1685 | mtxData->nCols = nd; |
1686 | |
1687 | mtxData->nDims = 1; /* assume */ |
1688 | mtxData->dims = mtxData->_dims; |
1689 | mtxData->dims[0] = mtxData->nCols; |
1690 | |
1691 | mtxData->re = data; |
1692 | mtxData->im = NULL; |
1693 | mtxData->dTypeID = dTypeId; |
1694 | mtxData->mxID = rt_GetMxIdFromDTypeId(dTypeId); |
1695 | mtxData->elSize = rt_GetSizeofDataType(dTypeId); |
1696 | mtxData->logical = 0U; |
1697 | mtxData->complex = 0U; |
1698 | |
1699 | data += nd; |
1700 | } |
1701 | ++sig->numActiveFields; |
1702 | } |
1703 | |
1704 | /* labels */ |
1705 | if (labels != NULL) { |
1706 | unsigned short *data; |
1707 | size_t nbytes; |
1708 | int_T dataLen = 0; |
1709 | size_t dataOffset = nSignals * sizeof(MatrixData); |
1710 | uint_T overhang = (uint_T)(dataOffset % sizeof(short)); |
1711 | int_T dataIdx = 0; |
1712 | |
1713 | for (i=0;i<nSignals;i++) { |
1714 | if (labels[i] != NULL){ |
1715 | dataLen = dataLen + (int_T)strlen(labels[i]); |
1716 | } |
1717 | } |
1718 | |
1719 | if (overhang) { /* polyspace DEFECT:DEAD_CODE [Not a defect:Unset] |
1720 | "Needed for possible padding determination. */ |
1721 | dataOffset += (sizeof(short) - overhang); |
1722 | } |
1723 | nbytes = dataOffset + dataLen*sizeof(short); |
1724 | |
1725 | if ( (sig->labels = calloc(nbytes, 1)) == NULL ) goto ERROR_EXIT; |
1726 | |
1727 | data = (unsigned short*) (((char_T*) (sig->labels)) + dataOffset); |
1728 | for(sigIdx=0;sigIdx<nSignals;sigIdx++) { |
1729 | int_T labelLen = (labels[sigIdx]==NULL) ? 0 : (int_T)strlen(labels[sigIdx]); |
1730 | for (i = 0; i < labelLen; i++) { |
1731 | data[dataIdx++] = (uint8_T)labels[sigIdx][i]; |
1732 | } |
1733 | } |
1734 | |
1735 | for (i = 0; i < nSignals; i++) { |
1736 | MatrixData *mtxData = &(sig->labels[i]); |
1737 | int_T labelLen = (int_T)strlen(labels[i]); |
1738 | |
1739 | (void)memcpy(mtxData->name, &LABEL_FIELD_NAME, mxMAXNAM); |
1740 | mtxData->nRows = (labelLen) ? 1 : 0; |
1741 | mtxData->nCols = labelLen; |
1742 | |
1743 | mtxData->re = data; |
1744 | mtxData->im = NULL; |
1745 | |
1746 | mtxData->nDims = 1; /* assume */ |
1747 | mtxData->dims = mtxData->_dims; |
1748 | mtxData->dims[0] = mtxData->nCols; |
1749 | |
1750 | mtxData->dTypeID = SS_INT16; |
1751 | mtxData->mxID = mxCHAR_CLASS; |
1752 | mtxData->elSize = sizeof(short); |
1753 | mtxData->logical = 0U; |
1754 | mtxData->complex = 0U; |
1755 | |
1756 | data += labelLen; |
1757 | } |
1758 | ++sig->numActiveFields; |
1759 | } |
1760 | |
1761 | /* plot styles */ |
1762 | if (plotStyles != NULL) { |
1763 | real_T *data; |
1764 | size_t nbytes; |
1765 | int_T dataLen = 0; |
1766 | BuiltInDTypeId dTypeId = rt_GetActualDTypeID(SS_DOUBLE); |
1767 | /*LINTED E_ASSIGN_INT_TO_SMALL_INT*/ |
1768 | size_t dataOffset = nSignals*sizeof(MatrixData); |
1769 | /*LINTED E_ASSIGN_INT_TO_SMALL_INT*/ |
1770 | uint_T overhang = (uint_T)(dataOffset % sizeof(real_T)); |
1771 | |
1772 | if (overhang) { /* polyspace DEFECT:DEAD_CODE [Not a defect:Unset] |
1773 | "Needed for possible padding determination. */ |
1774 | dataOffset += (sizeof(real_T) - overhang); |
1775 | } |
1776 | for (i=0; i< nSignals; i++) { |
1777 | dataLen += numCols[i]; |
1778 | } |
1779 | /*LINTED E_ASSIGN_INT_TO_SMALL_INT*/ |
1780 | nbytes = dataOffset + dataLen*sizeof(real_T); |
1781 | |
1782 | if ( (sig->plotStyles = calloc(nbytes, 1)) == NULL ) goto ERROR_EXIT; |
1783 | |
1784 | /*LINTED E_BAD_PTR_CAST_ALIGN*/ |
1785 | data = (real_T*) (((char_T*) (sig->plotStyles)) + dataOffset); |
1786 | |
1787 | for (i = 0; i < dataLen; i++) { |
1788 | data[i] = plotStyles[i]; |
1789 | } |
1790 | |
1791 | dimsOffset = 0; |
1792 | for (i = 0; i < nSignals; i++) { |
1793 | MatrixData *mtxData = &(sig->plotStyles[i]); |
1794 | |
1795 | (void)memcpy(mtxData->name, &PLOTSTYLE_FIELD_NAME, mxMAXNAM); |
1796 | |
1797 | mtxData->nRows = (numCols[i]) ? 1 : 0; |
1798 | mtxData->nCols = numCols[i]; |
1799 | |
1800 | mtxData->nDims = numDims[i]; |
1801 | |
1802 | if(mtxData->nDims > 2) { |
1803 | if ((mtxData->dims = calloc(mtxData->nDims, sizeof(int_T))) == NULL) goto ERROR_EXIT; |
1804 | } else { |
1805 | mtxData->dims = mtxData->_dims; |
1806 | } |
1807 | |
1808 | mtxData->dims[0] = *(dims + dimsOffset); |
1809 | if(mtxData->nDims >= 2) { |
1810 | int32_T j; |
1811 | for (j=1; j<mtxData->nDims; j++) { |
1812 | mtxData->dims[j] = *(dims + dimsOffset + j); |
1813 | } |
1814 | } |
1815 | |
1816 | mtxData->re = data; |
1817 | mtxData->im = NULL; |
1818 | mtxData->dTypeID = dTypeId; |
1819 | mtxData->mxID = rt_GetMxIdFromDTypeId(dTypeId); |
1820 | mtxData->elSize = rt_GetSizeofDataType(dTypeId); |
1821 | mtxData->logical = 0U; |
1822 | mtxData->complex = 0U; |
1823 | |
1824 | data += numCols[i]; |
1825 | dimsOffset += numDims[i]; |
1826 | } |
1827 | ++sig->numActiveFields; |
1828 | } |
1829 | |
1830 | /* titles */ |
1831 | if (titles != NULL) { |
1832 | unsigned short *data; |
1833 | size_t nbytes; |
1834 | int_T dataLen = (int_T)strlen(titles); |
1835 | /*LINTED E_ASSIGN_INT_TO_SMALL_INT*/ |
1836 | size_t dataOffset = nSignals * sizeof(MatrixData); |
1837 | /*LINTED E_ASSIGN_INT_TO_SMALL_INT*/ |
1838 | uint_T overhang = (uint_T)(dataOffset % sizeof(short)); |
1839 | |
1840 | if (overhang) { /* polyspace DEFECT:DEAD_CODE [Not a defect:Unset] |
1841 | "Needed for possible padding determination. */ |
1842 | dataOffset += (sizeof(short) - overhang); |
1843 | } |
1844 | /*LINTED E_ASSIGN_INT_TO_SMALL_INT*/ |
1845 | nbytes = dataOffset + dataLen*sizeof(short); |
1846 | |
1847 | if ( (sig->titles = calloc(nbytes, 1)) == NULL ) goto ERROR_EXIT; |
1848 | |
1849 | /*LINTED E_BAD_PTR_CAST_ALIGN*/ |
1850 | data = (unsigned short*) (((char_T*) (sig->titles)) + dataOffset); |
1851 | for (i = 0; i < dataLen; i++) { |
1852 | data[i] = titles[i]; |
1853 | } |
1854 | |
1855 | for (i = 0; i < nSignals; i++) { |
1856 | MatrixData *mtxData = &(sig->titles[i]); |
1857 | |
1858 | (void)memcpy(mtxData->name, &TITLE_FIELD_NAME, mxMAXNAM); |
1859 | if (titleLen) { |
1860 | mtxData->nRows = (titleLen[i]) ? 1 : 0; |
1861 | mtxData->nCols = titleLen[i]; |
1862 | } else { |
1863 | mtxData->nRows = (dataLen) ? 1 : 0; |
1864 | mtxData->nCols = dataLen; |
1865 | } |
1866 | |
1867 | mtxData->nDims = 1; /* assume */ |
1868 | mtxData->dims = mtxData->_dims; |
1869 | mtxData->dims[0] = mtxData->nCols; |
1870 | |
1871 | mtxData->re = data; |
1872 | mtxData->im = NULL; |
1873 | mtxData->dTypeID = SS_INT16; |
1874 | mtxData->mxID = mxCHAR_CLASS; |
1875 | mtxData->elSize = sizeof(short); |
1876 | mtxData->logical = 0U; |
1877 | mtxData->complex = 0U; |
1878 | |
1879 | data += ((titleLen) ? titleLen[i] : dataLen); |
1880 | } |
1881 | ++sig->numActiveFields; |
1882 | } |
1883 | |
1884 | /* block names */ |
1885 | if (blockNames != NULL) { |
1886 | unsigned short *data; |
1887 | size_t nbytes; |
1888 | int_T dataLen = 0; |
1889 | size_t dataOffset = nSignals * sizeof(MatrixData); |
1890 | uint_T overhang = (uint_T)(dataOffset % sizeof(short)); |
1891 | int_T dataIdx = 0; |
1892 | |
1893 | for (i=0;i<nSignals;i++) { |
1894 | if (blockNames[i] != NULL) { |
1895 | dataLen = dataLen + (int_T)strlen(blockNames[i]); |
1896 | } |
1897 | } |
1898 | |
1899 | if (overhang) { /* polyspace DEFECT:DEAD_CODE [Not a defect:Unset] |
1900 | "Needed for possible padding determination. */ |
1901 | dataOffset += (sizeof(short) - overhang); |
1902 | } |
1903 | |
1904 | nbytes = dataOffset + dataLen*sizeof(short); |
1905 | |
1906 | if ( (sig->blockNames = calloc(nbytes, 1)) == NULL ) goto ERROR_EXIT; |
1907 | |
1908 | data = (unsigned short*) (((char_T*) (sig->blockNames)) + dataOffset); |
1909 | |
1910 | for(sigIdx=0;sigIdx<nSignals;sigIdx++) { |
1911 | int_T nameLen = (blockNames[sigIdx]==NULL) ? 0 : |
1912 | (int_T)strlen(blockNames[sigIdx]); |
1913 | for (i = 0; i < nameLen; i++) { |
1914 | data[dataIdx++] = (uint8_T)blockNames[sigIdx][i]; |
1915 | } |
1916 | } |
1917 | |
1918 | for (i = 0; i < nSignals; i++) { |
1919 | MatrixData *mtxData = &(sig->blockNames[i]); |
1920 | int_T blockNameLen = (int_T)strlen(blockNames[i]); |
1921 | |
1922 | (void)memcpy(mtxData->name, &BLOCKNAME_FIELD_NAME, mxMAXNAM); |
1923 | mtxData->nRows = (blockNameLen) ? 1 : 0; |
1924 | mtxData->nCols = blockNameLen; |
1925 | |
1926 | mtxData->nDims = 1; /* assume */ |
1927 | mtxData->dims = mtxData->_dims; |
1928 | mtxData->dims[0] = mtxData->nCols; |
1929 | |
1930 | mtxData->re = data; |
1931 | mtxData->im = NULL; |
1932 | mtxData->dTypeID = SS_INT16; |
1933 | mtxData->mxID = mxCHAR_CLASS; |
1934 | mtxData->elSize = sizeof(short); |
1935 | mtxData->logical = 0U; |
1936 | mtxData->complex = 0U; |
1937 | |
1938 | data += blockNameLen; |
1939 | } |
1940 | ++sig->numActiveFields; |
1941 | if(logValueDimensions){ |
1942 | sig->fieldNames = rtGlobalLoggingSignalsStructFieldNames; |
1943 | } |
1944 | else{ |
1945 | sig->fieldNames = rtGlobalLoggingSignalsStructFieldNames_noValDims; |
1946 | } |
1947 | |
1948 | } else { |
1949 | if(logValueDimensions){ |
1950 | sig->fieldNames = rtLocalLoggingSignalsStructFieldNames; |
1951 | } |
1952 | else{ |
1953 | sig->fieldNames = rtLocalLoggingSignalsStructFieldNames_noValDims; |
1954 | } |
1955 | |
1956 | } |
1957 | |
1958 | /* state names */ |
1959 | if (stateNames != NULL) { |
1960 | unsigned short *data; |
1961 | size_t nbytes; |
1962 | int_T dataLen = 0; |
1963 | size_t dataOffset = nSignals * sizeof(MatrixData); |
1964 | uint_T overhang = (uint_T)(dataOffset % sizeof(short)); |
1965 | int_T dataIdx = 0; |
1966 | |
1967 | for (i=0;i<nSignals;i++) { |
1968 | if (stateNames[i] != NULL) { |
1969 | dataLen = dataLen + (int_T)strlen(stateNames[i]); |
1970 | } |
1971 | } |
1972 | |
1973 | if (overhang) { /* polyspace DEFECT:DEAD_CODE [Not a defect:Unset] |
1974 | "Needed for possible padding determination. */ |
1975 | dataOffset += (sizeof(short) - overhang); |
1976 | } |
1977 | |
1978 | nbytes = dataOffset + dataLen*sizeof(short); |
1979 | |
1980 | if ( (sig->stateNames = calloc(nbytes, 1)) == NULL ) goto ERROR_EXIT; |
1981 | |
1982 | data = (unsigned short*) (((char_T*) (sig->stateNames)) + dataOffset); |
1983 | |
1984 | for(sigIdx=0;sigIdx<nSignals;sigIdx++) { |
1985 | int_T nameLen = (stateNames[sigIdx]==NULL) ? 0 : |
1986 | (int_T)strlen(stateNames[sigIdx]); |
1987 | for (i = 0; i < nameLen; i++) { |
1988 | data[dataIdx++] = (uint8_T)stateNames[sigIdx][i]; |
1989 | } |
1990 | } |
1991 | |
1992 | for (i = 0; i < nSignals; i++) { |
1993 | MatrixData *mtxData = &(sig->stateNames[i]); |
1994 | int_T stateNameLen = (int_T)strlen(stateNames[i]); |
1995 | |
1996 | (void)memcpy(mtxData->name, &STATENAME_FIELD_NAME, mxMAXNAM); |
1997 | mtxData->nRows = (stateNameLen) ? 1 : 0; |
1998 | mtxData->nCols = stateNameLen; |
1999 | |
2000 | mtxData->nDims = 1; /* assume */ |
2001 | mtxData->dims = mtxData->_dims; |
2002 | mtxData->dims[0] = mtxData->nCols; |
2003 | |
2004 | mtxData->re = data; |
2005 | mtxData->im = NULL; |
2006 | mtxData->dTypeID = SS_INT16; |
2007 | mtxData->mxID = mxCHAR_CLASS; |
2008 | mtxData->elSize = sizeof(short); |
2009 | mtxData->logical = 0U; |
2010 | mtxData->complex = 0U; |
2011 | |
2012 | data += stateNameLen; |
2013 | } |
2014 | ++sig->numActiveFields; |
2015 | |
2016 | if(logValueDimensions){ |
2017 | sig->fieldNames = rtGlobalLoggingSignalsStructFieldNames; |
2018 | } |
2019 | else{ |
2020 | sig->fieldNames = rtGlobalLoggingSignalsStructFieldNames_noValDims; |
2021 | } |
2022 | |
2023 | } |
2024 | |
2025 | /* CrossMdlRef */ |
2026 | if (crossMdlRef != NULL) { |
2027 | real_T *data; |
2028 | size_t nbytes; |
2029 | size_t dataOffset = nSignals * sizeof(MatrixData); |
2030 | uint_T overhang = (uint_T)(dataOffset % sizeof(real_T)); |
2031 | |
2032 | if (overhang) { /* polyspace DEFECT:DEAD_CODE [Not a defect:Unset] |
2033 | "Needed for possible padding determination. */ |
2034 | dataOffset += (sizeof(real_T) - overhang); |
2035 | } |
2036 | |
2037 | nbytes = dataOffset + nSignals*sizeof(real_T); |
2038 | |
2039 | if ( (sig->crossMdlRef = calloc(nbytes, 1)) == NULL ) goto ERROR_EXIT; |
2040 | |
2041 | data = (real_T*) (((char_T*) (sig->crossMdlRef)) + dataOffset); |
2042 | |
2043 | for(sigIdx=0;sigIdx<nSignals;sigIdx++) { |
2044 | data[sigIdx] = crossMdlRef[sigIdx]; |
2045 | } |
2046 | |
2047 | for (i = 0; i < nSignals; i++) { |
2048 | MatrixData *mtxData = &(sig->crossMdlRef[i]); |
2049 | |
2050 | (void)memcpy(mtxData->name, &CROSS_MDL_REF_FIELD_NAME, mxMAXNAM); |
2051 | mtxData->nRows = 1; |
2052 | mtxData->nCols = 1; |
2053 | mtxData->nDims = 1; /* => matlab scalar */ |
2054 | |
2055 | mtxData->re = &data[i]; |
2056 | mtxData->im = NULL; |
2057 | mtxData->dTypeID = SS_DOUBLE; |
2058 | mtxData->mxID = rt_GetMxIdFromDTypeId(SS_DOUBLE); |
2059 | mtxData->elSize = sizeof(real_T); |
2060 | mtxData->logical = matLOGICAL_BIT; |
2061 | mtxData->complex = 0U; |
2062 | mtxData->frameData = 0; |
2063 | mtxData->frameSize = 1; |
2064 | } |
2065 | ++sig->numActiveFields; |
2066 | } |
2067 | |
2068 | return(NULL); /* NORMAL_EXIT */ |
2069 | |
2070 | ERROR_EXIT: |
2071 | |
2072 | (void)fprintf(stderr, "*** Error creating signals structure " |
2073 | "in the struct log variable %s\n", var->name); |
2074 | if (*errStatus == NULL) { |
2075 | *errStatus = rtMemAllocError; |
2076 | } |
2077 | rt_DestroyLogVar(sig->values); |
2078 | FREE(sig->labels); |
2079 | FREE(sig->plotStyles); |
2080 | FREE(sig->dimensions); |
2081 | FREE(sig->titles); |
2082 | FREE(sig->blockNames); |
2083 | FREE(sig->stateNames); |
2084 | FREE(sig->crossMdlRef); |
2085 | |
2086 | return(*errStatus); |
2087 | |
2088 | } /* end rt_InitSignalsStruct */ |
2089 | |
2090 | |
2091 | /* Function: local_CreateStructLogVar ========================================== |
2092 | * Abstract: |
2093 | * Create a logging variable in the structure format. |
2094 | * |
2095 | * Returns: |
2096 | * ~= NULL => success, returns the log variable created. |
2097 | * == NULL => failure, error message set in the simstruct. |
2098 | */ |
2099 | static StructLogVar *local_CreateStructLogVar( |
2100 | RTWLogInfo *li, |
2101 | const real_T startTime, |
2102 | const real_T finalTime, |
2103 | const real_T inStepSize, |
2104 | const char_T **errStatus, |
2105 | const char_T *varName, |
2106 | boolean_T logTime, |
2107 | int_T maxRows, |
2108 | int_T decimation, |
2109 | real_T sampleTime, |
2110 | const RTWLogSignalInfo *sigInfo, |
2111 | const char_T *blockName) |
2112 | { |
2113 | StructLogVar *var; |
2114 | LogInfo *logInfo = rtliGetLogInfo(li); |
2115 | |
2116 | /* reset error status */ |
2117 | *errStatus = NULL; |
2118 | |
2119 | if ( (var = calloc(1, sizeof(StructLogVar))) == NULL ) goto ERROR_EXIT; |
2120 | |
2121 | var->numActiveFields = 2; |
2122 | |
2123 | /* Setup the structure name using varName and nameModifier */ |
2124 | rt_LoadModifiedLogVarName(li,varName,var->name); |
2125 | |
2126 | /* time field */ |
2127 | if (logTime) { |
2128 | /* need to create a LogVar to log time */ |
2129 | int_T dims = 1; |
2130 | var->time = rt_CreateLogVarWithConvert(li, startTime, finalTime, |
2131 | inStepSize, errStatus, |
2132 | &TIME_FIELD_NAME, SS_DOUBLE, |
2133 | NULL, |
2134 | 0, 0, 0, 1, |
2135 | 1, &dims, NO_LOGVALDIMS, |
2136 | NULL, NULL, maxRows, |
2137 | decimation, sampleTime, 0); |
2138 | if (var->time == NULL) goto ERROR_EXIT; |
2139 | } else { |
2140 | /* create a dummy MatrixData to write out time as an empty matrix */ |
2141 | BuiltInDTypeId dt = rt_GetActualDTypeID(SS_DOUBLE); |
2142 | size_t nbytes = sizeof(MatrixData); |
2143 | MatrixData *time; |
2144 | |
2145 | if ( (var->time = calloc(nbytes, 1)) == NULL ) goto ERROR_EXIT; |
2146 | time = var->time; |
2147 | |
2148 | (void)memcpy(time->name, &TIME_FIELD_NAME, mxMAXNAM); |
2149 | time->nRows = 0; |
2150 | time->nCols = 0; |
2151 | time->nDims = 0; |
2152 | time->re = NULL; |
2153 | time->im = NULL; |
2154 | time->dTypeID = dt; |
2155 | time->mxID = rt_GetMxIdFromDTypeId(dt); |
2156 | time->elSize = rt_GetSizeofDataType(dt); |
2157 | time->logical = 0U; |
2158 | time->complex = 0U; |
2159 | } |
2160 | var->logTime = logTime; |
2161 | |
2162 | /* signals field */ |
2163 | if (sigInfo) { |
2164 | if (rt_InitSignalsStruct(li,startTime,finalTime,inStepSize,errStatus, |
2165 | var,maxRows,decimation,sampleTime,sigInfo)) { |
2166 | goto ERROR_EXIT; |
2167 | } |
2168 | } |
2169 | |
2170 | /* blockName Field */ |
2171 | if (blockName != NULL) { |
2172 | int_T dataLen = (int_T)strlen(blockName); |
2173 | size_t nbytes; |
2174 | size_t dataOffset = sizeof(MatrixData); |
2175 | /*LINTED E_ASSIGN_INT_TO_SMALL_INT*/ |
2176 | uint_T overhang = (uint_T)(dataOffset % sizeof(short)); |
2177 | |
2178 | if (overhang) { /* polyspace DEFECT:DEAD_CODE [Not a defect:Unset] |
2179 | "Needed for possible padding determination. */ |
2180 | dataOffset += (sizeof(short) - overhang); |
2181 | } |
2182 | /*LINTED E_ASSIGN_INT_TO_SMALL_INT*/ |
2183 | nbytes = dataOffset + dataLen*sizeof(short); |
2184 | |
2185 | if ( (var->blockName = calloc(nbytes, 1)) == NULL ) goto ERROR_EXIT; |
2186 | |
2187 | (void)memcpy(var->blockName->name, &BLOCKNAME_FIELD_NAME, mxMAXNAM); |
2188 | var->blockName->nRows = (dataLen) ? 1 : 0; |
2189 | var->blockName->nCols = dataLen; |
2190 | |
2191 | var->blockName->nDims = 1; |
2192 | var->blockName->dims = var->blockName->_dims; |
2193 | var->blockName->dims[0] = dataLen; |
2194 | { |
2195 | /*LINTED E_BAD_PTR_CAST_ALIGN*/ |
2196 | unsigned short *data = (unsigned short*)(((char_T*) (var->blockName))+dataOffset); |
2197 | int_T i; |
2198 | |
2199 | for (i=0; i<dataLen; i++) { |
2200 | data[i] = (uint8_T)blockName[i]; |
2201 | } |
2202 | var->blockName->re = data; |
2203 | } |
2204 | var->blockName->im = NULL; |
2205 | var->blockName->dTypeID = SS_INT16; |
2206 | var->blockName->mxID = mxCHAR_CLASS; |
2207 | var->blockName->elSize = sizeof(short); |
2208 | var->blockName->logical = 0U; |
2209 | var->blockName->complex = 0U; |
2210 | |
2211 | ++var->numActiveFields; |
2212 | } |
2213 | |
2214 | /* Add this struct log var to the linked list in log info */ |
2215 | { |
2216 | StructLogVar *list = logInfo->structLogVarsList; |
2217 | |
2218 | if (list != NULL) { |
2219 | while (list->next != NULL) { |
2220 | list = list->next; |
2221 | } |
2222 | list->next = var; |
2223 | } else { |
2224 | logInfo->structLogVarsList = var; |
2225 | } |
2226 | } |
2227 | |
2228 | return(var); /* NORMAL_EXIT */ |
2229 | |
2230 | ERROR_EXIT: |
2231 | (void)fprintf(stderr, "*** Error creating log variable %s\n", varName); |
2232 | if (*errStatus == NULL) { |
2233 | *errStatus = rtMemAllocError; |
2234 | } |
2235 | rt_DestroyStructLogVar(var); |
2236 | return(NULL); |
2237 | |
2238 | } /* end local_CreateStructLogVar */ |
2239 | |
2240 | |
2241 | /* Function: rt_StartDataLoggingForOutput ====================================== |
2242 | * Abstract: |
2243 | */ |
2244 | static const char_T *rt_StartDataLoggingForOutput(RTWLogInfo *li, |
2245 | const real_T startTime, |
2246 | const real_T finalTime, |
2247 | const real_T stepSize, |
2248 | const char_T **errStatus) |
2249 | { |
2250 | const char_T *varName; |
2251 | real_T sampleTime = stepSize; |
2252 | int_T maxRows = rtliGetLogMaxRows(li); |
2253 | int_T decimation = rtliGetLogDecimation(li); |
2254 | int_T logFormat = rtliGetLogFormat(li); |
2255 | boolean_T logTime = (logFormat==2) ? 1 : 0; |
2256 | |
2257 | LogInfo * logInfo; |
2258 | logInfo = rtliGetLogInfo(li); |
2259 | |
2260 | /* reset error status */ |
2261 | *errStatus = NULL; |
2262 | |
2263 | /* outputs */ |
2264 | varName = rtliGetLogY(li); |
2265 | if (varName[0] != '\0') { |
2266 | int_T i; |
2267 | int_T ny; |
2268 | int_T yIdx; |
2269 | char_T name[mxMAXNAM]; |
2270 | const char_T *cp = strchr(varName,','); |
2271 | LogSignalPtrsType ySigPtrs = rtliGetLogYSignalPtrs(li); |
2272 | const RTWLogSignalInfo *yInfo = rtliGetLogYSignalInfo(li); |
2273 | |
2274 | /* count the number of variables (matrices or structures) to create */ |
2275 | for (ny=1; cp != NULL; ny++) { |
2276 | cp = strchr(cp+1,','); |
2277 | } |
2278 | logInfo->ny = ny; |
2279 | |
2280 | if (logFormat==0) { |
2281 | if ( (logInfo->y = calloc(ny,sizeof(LogVar*))) == NULL ) { |
2282 | *errStatus = rtMemAllocError; |
2283 | goto ERROR_EXIT; |
2284 | } |
2285 | } else { |
2286 | if ( (logInfo->y = calloc(ny,sizeof(StructLogVar*))) == NULL ) { |
2287 | *errStatus = rtMemAllocError; |
2288 | goto ERROR_EXIT; |
2289 | } |
2290 | } |
2291 | |
2292 | for (i = yIdx = 0, cp = varName; i < ny; i++) { |
2293 | int_T len; |
2294 | const char_T *cp1 = strchr(cp+1,','); |
2295 | |
2296 | if (cp1 != NULL) { |
2297 | /*LINTED E_ASSIGN_INT_TO_SMALL_INT*/ |
2298 | len = (int_T)(cp1 - cp); |
2299 | if (len >= mxMAXNAM) len = mxMAXNAM - 1; |
2300 | } else { |
2301 | len = mxMAXNAM - 1; |
2302 | } |
2303 | (void)strncpy(name, cp, len); |
2304 | name[len] = '\0'; |
2305 | |
2306 | if (ny > 1 && ySigPtrs[i] == NULL) { |
2307 | goto NEXT_NAME; |
2308 | } |
2309 | |
2310 | if (logFormat == 0) { |
2311 | int numCols; |
2312 | int nDims; |
2313 | const int *dims; |
2314 | BuiltInDTypeId dataType; |
2315 | int isComplex; |
2316 | |
2317 | if (ny == 1) { |
2318 | int_T op; |
2319 | |
2320 | numCols = yInfo[0].numCols[0]; |
2321 | for (op = 1; op < yInfo[0].numSignals; op++) { |
2322 | numCols += yInfo[0].numCols[op]; |
2323 | } |
2324 | /* |
2325 | * If we have only one "matrix" outport, |
2326 | * we can still log it as a matrix |
2327 | */ |
2328 | if (yInfo[0].numSignals == 1) { |
2329 | nDims = yInfo[0].numDims ? yInfo[0].numDims[0] : 1; |
2330 | dims = yInfo[0].dims; |
2331 | } else { |
2332 | nDims = 1; |
2333 | dims = &numCols; |
2334 | } |
2335 | |
2336 | dataType = yInfo[0].dataTypes[0]; |
2337 | isComplex = yInfo[0].complexSignals[0]; |
2338 | } else { |
2339 | numCols = yInfo[yIdx].numCols[0]; |
2340 | nDims = yInfo[yIdx].numDims ? yInfo[yIdx].numDims[0] : 1; |
2341 | dims = yInfo[yIdx].dims; |
2342 | dataType = yInfo[yIdx].dataTypes[0]; |
2343 | isComplex = yInfo[yIdx].complexSignals[0]; |
2344 | } |
2345 | |
2346 | logInfo->y[yIdx] = rt_CreateLogVarWithConvert( |
2347 | li, startTime, finalTime, |
2348 | stepSize, errStatus, |
2349 | name, |
2350 | dataType, |
2351 | yInfo[yIdx].dataTypeConvert, |
2352 | 0,isComplex, |
2353 | 0,numCols,nDims,dims, |
2354 | NO_LOGVALDIMS, NULL, NULL, |
2355 | maxRows,decimation, |
2356 | sampleTime,1); |
2357 | if (logInfo->y[yIdx] == NULL) goto ERROR_EXIT; |
2358 | } else { |
2359 | logInfo->y[yIdx] = local_CreateStructLogVar(li, startTime, |
2360 | finalTime, stepSize, |
2361 | errStatus, name, |
2362 | logTime, maxRows, |
2363 | decimation, sampleTime, |
2364 | &yInfo[yIdx], NULL); |
2365 | if (logInfo->y[yIdx] == NULL) goto ERROR_EXIT; |
2366 | } |
2367 | ++yIdx; |
2368 | NEXT_NAME: |
2369 | cp = cp1; |
2370 | if (cp != NULL && *cp == ',') cp++; |
2371 | } |
2372 | } |
2373 | |
2374 | return(NULL); /* NORMAL_EXIT */ |
2375 | |
2376 | ERROR_EXIT: |
2377 | (void)fprintf(stderr, "*** Errors occurred when starting data logging.\n"); |
2378 | if (*errStatus == NULL) { |
2379 | *errStatus = rtMemAllocError; |
2380 | } |
2381 | if (logInfo) { /* polyspace DEFECT:USELESS_IF [No action planned:Unset] |
2382 | "Defense coding." */ |
2383 | rt_DestroyLogVar(logInfo->logVarsList); |
2384 | logInfo->logVarsList = NULL; |
2385 | rt_DestroyStructLogVar(logInfo->structLogVarsList); |
2386 | logInfo->structLogVarsList = NULL; |
2387 | FREE(logInfo->y); |
2388 | logInfo->y = NULL; |
2389 | } |
2390 | return(*errStatus); |
2391 | |
2392 | } /* end rt_StartDataLoggingForOutput */ |
2393 | |
2394 | |
2395 | /* Function: rt_ReallocLogVar ================================================== |
2396 | * Abstract: |
2397 | * Allocate more memory for the data buffers in the log variable. |
2398 | * Exit if unable to allocate more memory. |
2399 | */ |
2400 | static void rt_ReallocLogVar(LogVar *var, boolean_T isVarDims) |
2401 | { |
2402 | void *tmp; |
2403 | int_T nCols = var->data.nCols; |
2404 | int_T nRows; |
2405 | size_t elSize = var->data.elSize; |
2406 | |
2407 | if (isVarDims) |
2408 | { |
2409 | nRows = var->data.nRows + DEFAULT_BUFFER_SIZE; |
2410 | } |
2411 | else |
2412 | { |
2413 | nRows = var->data.nRows == 0 ? 1 : 2*var->data.nRows; |
2414 | } |
2415 | |
2416 | tmp = realloc(var->data.re, nRows*nCols*elSize); |
2417 | if (tmp == NULL) { |
2418 | (void)fprintf(stderr, |
2419 | "*** Memory allocation error.\n"); |
2420 | (void)fprintf(stderr, "" |
2421 | " varName = %s%s\n" |
2422 | " nRows = %d\n" |
2423 | " nCols = %d\n" |
2424 | " elementSize = %lu\n" |
2425 | " Current Size = %.16g\n" |
2426 | " Failed resize = %.16g\n\n", |
2427 | var->data.name, |
2428 | var->data.complex ? " (real part)" : "", |
2429 | var->data.nRows, |
2430 | var->data.nCols, |
2431 | (unsigned long) var->data.elSize, |
2432 | (double)nRows*nCols*elSize, |
2433 | (double)(nRows+DEFAULT_BUFFER_SIZE)*nCols*elSize); |
2434 | exit(1); |
2435 | } |
2436 | var->data.re = tmp; |
2437 | |
2438 | if (var->data.complex) { |
2439 | tmp = realloc(var->data.im, nRows*nCols*elSize); |
2440 | if (tmp == NULL) { |
2441 | (void)fprintf(stderr, |
2442 | "*** Memory allocation error.\n"); |
2443 | (void)fprintf(stderr, "" |
2444 | " varName = %s (complex part)\n" |
2445 | " nRows = %d\n" |
2446 | " nCols = %d\n" |
2447 | " elementSize = %lu\n" |
2448 | " Current Size = %.16g\n" |
2449 | " Failed resize = %.16g\n\n", |
2450 | var->data.name, |
2451 | var->data.nRows, |
2452 | var->data.nCols, |
2453 | (unsigned long) var->data.elSize, |
2454 | (double)nRows*nCols*elSize, |
2455 | (double)(nRows+DEFAULT_BUFFER_SIZE)*nCols*elSize); |
2456 | exit(1); |
2457 | } |
2458 | var->data.im = tmp; |
2459 | } |
2460 | var->data.nRows = nRows; |
2461 | |
2462 | /* Also reallocate memory for "valueDimensions" |
2463 | when logging the variable-size signal |
2464 | */ |
2465 | if(isVarDims){ |
2466 | int_T k; |
2467 | |
2468 | nCols = var->valDims->nCols; |
2469 | nRows = var->valDims->nRows + DEFAULT_BUFFER_SIZE; |
2470 | elSize = sizeof(real_T); |
2471 | tmp = realloc(var->valDims->dimsData, nRows*nCols*elSize); |
2472 | if (tmp == NULL) { |
2473 | (void)fprintf(stderr, |
2474 | "*** Memory allocation error.\n"); |
2475 | (void)fprintf(stderr, "" |
2476 | " varName = %s\n" |
2477 | " nRows = %d\n" |
2478 | " nCols = %d\n" |
2479 | " elementSize = %lu\n" |
2480 | " Current Size = %.16g\n" |
2481 | " Failed resize = %.16g\n\n", |
2482 | var->valDims->name, |
2483 | var->valDims->nRows, |
2484 | var->valDims->nCols, |
2485 | (unsigned long) elSize, |
2486 | (double)nRows*nCols*elSize, |
2487 | (double)(nRows+DEFAULT_BUFFER_SIZE)*nCols*elSize); |
2488 | exit(1); |
2489 | } |
2490 | |
2491 | /* |
2492 | * valueDimensions data is stored in array format and must be |
2493 | * adjusted after reallocation (see also rt_FixupLogVar()) |
2494 | * |
2495 | * Example: maxRows = 4; nRows = 4; nDims = 3; |
2496 | * Before realloc of the logVar, the locations of data are as below: |
2497 | * (x, y, z -- useful data / o -- junk, don't care) |
2498 | * a[0] = x a[4] = y a[8] = z |
2499 | * a[1] = x a[5] = y a[9] = z |
2500 | * a[2] = x a[6] = y a[10]= z |
2501 | * a[3] = x a[7] = y a[11]= z |
2502 | * |
2503 | * After realloc of the logVar (suppose 2 extra rows are added), |
2504 | * the locations of data are as below: |
2505 | * a[0] = x a[6] = y a[12]= o |
2506 | * a[1] = x a[7] = y a[13]= o |
2507 | * a[2] = x a[8] = z a[14]= o |
2508 | * a[3] = x a[9] = z a[15]= o |
2509 | * a[4] = y a[10]= z a[16]= o |
2510 | * a[5] = y a[11]= z a[17]= o |
2511 | * |
2512 | * The data must be adjusted as below: |
2513 | * a[0] = x a[6] = y a[12]= z |
2514 | * a[1] = x a[7] = y a[13]= z |
2515 | * a[2] = x a[8] = y a[14]= z |
2516 | * a[3] = x a[9] = y a[15]= z |
2517 | * a[4] = o a[10]= o a[16]= o |
2518 | * a[5] = o a[11]= o a[17]= o |
2519 | */ |
2520 | for(k = var->data.nDims-1; k > 0; k--){ |
2521 | (void) memcpy((real_T*)tmp + k*nRows, |
2522 | (real_T*)tmp + k*var->valDims->nRows, |
2523 | elSize * var->valDims->nRows); |
2524 | } |
2525 | |
2526 | var->valDims->dimsData = tmp; |
2527 | var->valDims->nRows = nRows; |
2528 | } |
2529 | |
2530 | } /* end rt_ReallocLogVar */ |
2531 | |
2532 | const char_T *rt_UpdateLogVarWithDiscontiguousData(LogVar *var, |
2533 | int8_T** data, |
2534 | const int_T *segmentLengths, |
2535 | int_T nSegments, |
2536 | RTWPreprocessingFcnPtr *preprocessingPtrs); |
2537 | |
2538 | /* Function: rt_UpdateLogVarWithDiscontinuousData ============================== |
2539 | * Abstract: |
2540 | * Log one row of the LogVar with data that is not contiguous. |
2541 | */ |
2542 | const char_T *rt_UpdateLogVarWithDiscontiguousData(LogVar *var, |
2543 | int8_T** data, |
2544 | const int_T *segmentLengths, |
2545 | int_T nSegments, |
2546 | RTWPreprocessingFcnPtr *preprocessingPtrs) |
2547 | { |
2548 | size_t elSize = 0; |
2549 | size_t offset = 0; |
2550 | int segIdx = 0; |
2551 | |
2552 | if (++var->numHits % var->decimation) return(NULL); |
2553 | var->numHits = 0; |
2554 | |
2555 | /* |
2556 | * Reallocate or wrap the LogVar |
2557 | */ |
2558 | if (var->rowIdx == var->data.nRows) { |
2559 | if (var->okayToRealloc == 1) { |
2560 | rt_ReallocLogVar(var, false); |
2561 | } else { |
2562 | /* Circular buffer */ |
2563 | var->rowIdx = 0; |
2564 | ++(var->wrapped); /* increment the wrap around counter */ |
2565 | } |
2566 | } |
2567 | |
2568 | /* This function is only used to log states, there's no var-dims issue. */ |
2569 | elSize = var->data.elSize; |
2570 | offset = (size_t)(elSize * var->rowIdx * var->data.nCols); |
2571 | |
2572 | if (var->data.complex) { |
2573 | char_T *dstRe = (char_T*)(var->data.re) + offset; |
2574 | char_T *dstIm = (char_T*)(var->data.im) + offset; |
2575 | |
2576 | for (segIdx = 0; segIdx < nSegments; segIdx++) { |
2577 | int_T nEl = segmentLengths[segIdx]; |
2578 | char_T *src = (char_T *)data[segIdx]; |
2579 | int_T el; |
2580 | |
2581 | /* preprocess data in-place before logging */ |
2582 | RTWPreprocessingFcnPtr preprocessingPtr = preprocessingPtrs[segIdx]; |
2583 | if (preprocessingPtr != NULL) { |
2584 | src = malloc(elSize * nEl * 2); |
2585 | preprocessingPtr(src, (void *)data[segIdx]); |
2586 | } |
2587 | |
2588 | if (src == NULL) { |
2589 | const char_T *errorMessage = "Could not allocate memory for logging."; |
2590 | fprintf(stderr,"%s.\n", errorMessage); |
2591 | return(errorMessage); |
2592 | } |
2593 | else { |
2594 | for (el = 0; el < nEl; el++) { |
2595 | (void)memcpy(dstRe, src, elSize); |
2596 | dstRe += elSize; src += elSize; |
2597 | (void)memcpy(dstIm, src, elSize); |
2598 | dstIm += elSize; src += elSize; |
2599 | } |
2600 | } |
2601 | |
2602 | /* free temporarily declared data */ |
2603 | if (preprocessingPtr != NULL) { |
2604 | free( src ); |
2605 | } |
2606 | } |
2607 | } else { |
2608 | char_T *dst = (char_T*)(var->data.re) + offset; |
2609 | |
2610 | for (segIdx = 0; segIdx < nSegments; segIdx++) { |
2611 | size_t segSize = elSize*segmentLengths[segIdx]; |
2612 | char_T *src = (void *) data[segIdx]; |
2613 | |
2614 | /* preprocess data in-place before logging */ |
2615 | RTWPreprocessingFcnPtr preprocessingPtr = preprocessingPtrs[segIdx]; |
2616 | if (preprocessingPtr != NULL) { |
2617 | src = malloc(segSize); |
2618 | preprocessingPtr(src, data[segIdx]); |
2619 | } |
2620 | if (src == NULL) { |
2621 | const char_T *errorMessage = "Could not allocate memory for logging."; |
2622 | fprintf(stderr,"%s.\n", errorMessage); |
2623 | return(errorMessage); } |
2624 | else { |
2625 | (void)memcpy(dst, src, segSize); |
2626 | dst += segSize; |
2627 | } |
2628 | |
2629 | /* free temporarily declared data */ |
2630 | if (preprocessingPtr != NULL) { |
2631 | free( src ); |
2632 | } |
2633 | } |
2634 | } |
2635 | |
2636 | ++var->rowIdx; |
2637 | return(NULL); |
2638 | |
2639 | } /* end rt_UpdateLogVarWithDiscontinuousData */ |
2640 | |
2641 | |
2642 | /*==================* |
2643 | * Visible routines * |
2644 | *==================*/ |
2645 | |
2646 | |
2647 | |
2648 | #ifdef __cplusplus |
2649 | extern "C" { |
2650 | #endif |
2651 | |
2652 | |
2653 | /* Function: rt_CreateLogVarWithConvert ======================================== |
2654 | * Abstract: |
2655 | * Create a logging variable. |
2656 | * |
2657 | * Returns: |
2658 | * ~= NULL => success, returns the log variable created. |
2659 | * == NULL => failure, error message set in the simstruct. |
2660 | */ |
2661 | LogVar *rt_CreateLogVarWithConvert( |
2662 | RTWLogInfo *li, |
2663 | const real_T startTime, |
2664 | const real_T finalTime, |
2665 | const real_T inStepSize, |
2666 | const char_T **errStatus, |
2667 | const char_T *varName, |
2668 | BuiltInDTypeId inpDataTypeID, |
2669 | const RTWLogDataTypeConvert *pDataTypeConvertInfo, |
2670 | int_T logical, |
2671 | int_T complex, |
2672 | int_T frameData, |
2673 | int_T nCols, |
2674 | int_T nDims, |
2675 | const int_T *dims, |
2676 | LogValDimsStat logValDimsStat, |
2677 | void **currSigDims, |
2678 | int_T *currSigDimsSize, |
2679 | int_T maxRows, |
2680 | int_T decimation, |
2681 | real_T sampleTime, |
2682 | int_T appendToLogVarsList) |
2683 | { |
2684 | int_T usingDefaultBufSize = 0; |
2685 | #ifdef NO_LOGGING_REALLOC |
2686 | int_T okayToRealloc = 0; |
2687 | #else |
2688 | int_T okayToRealloc = 1; |
2689 | #endif |
2690 | LogVar *var = NULL; |
2691 | /*inpDataTypeID is the rt_LoggedOutputDataTypeId*/ |
2692 | BuiltInDTypeId dTypeID = (BuiltInDTypeId)inpDataTypeID; |
2693 | size_t elementSize = rt_GetSizeofDataType(dTypeID); |
2694 | int_T frameSize; |
2695 | int_T nRows; |
2696 | int_T nColumns; |
2697 | |
2698 | /*===================================================================* |
2699 | * Determine the frame size if the data is frame based * |
2700 | *===================================================================*/ |
2701 | frameSize = frameData ? dims[0] : 1; |
2702 | |
2703 | /*===================================================================* |
2704 | * Calculate maximum number of rows needed in the buffer * |
2705 | *===================================================================*/ |
2706 | |
2707 | if (finalTime > startTime && finalTime != rtInf) { |
2708 | real_T nPoints; /* Tfinal is finite ===> nRows can be */ |
2709 | real_T stepSize; /* computed since the StepSize is fixed */ |
2710 | |
2711 | if (sampleTime == -2.0) { /* The signal being logged is constant, * |
2712 | * Hence, only one data point is logged. */ |
2713 | stepSize = finalTime; |
2714 | } else if (sampleTime == -1.0 || sampleTime == 0.0) { |
2715 | /* Signal being logged is either inside a * |
2716 | * triggered sub-system or it is continuous. */ |
2717 | stepSize = inStepSize; |
2718 | } else { /* Discrete signal */ |
2719 | stepSize = sampleTime; |
2720 | } |
2721 | |
2722 | if (stepSize == 0.0) { |
2723 | /* small initial value, so as to exercise the realloc code */ |
2724 | nRows = maxRows+1; |
2725 | okayToRealloc = 1; |
2726 | } else { |
2727 | nPoints = 1.0 + floor((finalTime-startTime)/stepSize); |
2728 | |
2729 | /* |
2730 | * Add one more data point if needed. |
2731 | */ |
2732 | if ( stepSize*(nPoints-1.0) < (finalTime-startTime) ) { |
2733 | nPoints += 1.0; |
2734 | } |
2735 | |
2736 | /* |
2737 | * Actual number of points to log = nPoints * size of |
2738 | * each frame if data is frame-based |
2739 | */ |
2740 | nPoints = frameData ? (nPoints * frameSize) : nPoints; |
2741 | |
2742 | nPoints /= decimation; |
2743 | if (nPoints != floor(nPoints)) { |
2744 | nPoints += 1.0; |
2745 | } |
2746 | nRows = (nPoints <= INT_MAX) ? ((int_T) nPoints) : INT_MAX; |
2747 | } |
2748 | /* |
2749 | * If maxRows is specified, and if this number is less |
2750 | * than the number we computed (nRows) then use maxRows. |
2751 | */ |
2752 | if ((maxRows > 0) && (maxRows < nRows)) { |
2753 | nRows = maxRows; |
2754 | okayToRealloc = 0; |
2755 | } |
2756 | } else if (finalTime == startTime) { |
2757 | /* |
2758 | * Number of rows to log is equal to 1 if not frame-based and |
2759 | * equal to frame size if frame-based |
2760 | */ |
2761 | nRows = frameData ? frameSize : 1; |
2762 | |
2763 | /* |
2764 | * If maxRows is specified, and if this number is less |
2765 | * than the number we computed (nRows) then use maxRows. |
2766 | */ |
2767 | if ((maxRows > 0) && (maxRows < nRows)) { |
2768 | nRows = maxRows; |
2769 | okayToRealloc = 0; |
2770 | } |
2771 | } else if (maxRows > 0) { /* maxRows is specified => nRows=maxRows */ |
2772 | nRows = maxRows; |
2773 | okayToRealloc = 0; |
2774 | } else { |
2775 | |
2776 | if (inStepSize == 0) { |
2777 | /* small initial value, so as to exercise the realloc code */ |
2778 | nRows = maxRows+1; |
2779 | okayToRealloc = 1; |
2780 | } else { /* Use a default value for nRows */ |
2781 | usingDefaultBufSize = 1; |
2782 | nRows = DEFAULT_BUFFER_SIZE; |
2783 | okayToRealloc = 0; /* No realloc with infinite stop time */ |
2784 | (void)fprintf(stdout, "*** Using a default buffer of size %d for " |
2785 | "logging variable %s\n", nRows, varName); |
2786 | } |
2787 | } |
2788 | |
2789 | /* |
2790 | * Figure out the number of columns that the log variable should have. |
2791 | * If the data is not frame based, then number of columns should equal |
2792 | * nCols that is provided as input to the function. If the data is |
2793 | * frame-based, then the number of columns should be equal to the |
2794 | * number of channels = nCols/frameSize = dims[1]; |
2795 | */ |
2796 | nColumns = frameData ? dims[1] : nCols; |
2797 | |
2798 | /* |
2799 | * Error out if the size of the circular buffer is absurdly large, this |
2800 | * error message is more informative than the one we get when we try to |
2801 | * malloc this many number of bytes in one fell swoop. |
2802 | */ |
2803 | { |
2804 | double tmpDbl = ((double)elementSize)*((double)nRows)* |
2805 | ((double)nColumns); |
2806 | |
2807 | if (tmpDbl >= UINT_MAX) { |
2808 | (void)fprintf(stderr, |
2809 | "\n*** Memory required to log variable '%s' is too" |
2810 | "\n big. Use the 'Limit rows to last:' and (or)" |
2811 | "\n 'Decimation:' options to reduce the required" |
2812 | "\n memory size.\n", varName); |
2813 | (void)fprintf(stderr, "*** Details:\n" |
2814 | " varName = %s\n" |
2815 | " nRows = %d\n" |
2816 | " nCols = %d\n" |
2817 | " elementSize = %lu\n" |
2818 | " Bytes Required = %.16g\n\n", |
2819 | varName, nRows, nColumns, (unsigned long) |
2820 | elementSize, tmpDbl); |
2821 | goto ERROR_EXIT; |
2822 | } |
2823 | } |
2824 | |
2825 | /* Allocate memory for the log variable */ |
2826 | if ( (var = calloc(1, sizeof(LogVar))) == NULL ) { |
2827 | (void)fprintf(stderr, "*** Error allocating memory for logging %s\n", |
2828 | varName); |
2829 | goto ERROR_EXIT; |
2830 | } |
2831 | |
2832 | /* Allocate memory for the circular buffer (real part) */ |
2833 | if ( (var->data.re = malloc(nRows*nColumns*elementSize)) == NULL ) { |
2834 | (void)fprintf(stderr, |
2835 | "*** Error allocating memory for the circular buffer\n"); |
2836 | (void)fprintf(stderr, "*** Details:\n" |
2837 | " varName = %s\n" |
2838 | " nRows = %d\n" |
2839 | " nCols = %d\n" |
2840 | " elementSize = %lu\n" |
2841 | " Bytes Requested = %.16g\n\n", |
2842 | varName, nRows, nColumns, (unsigned long) elementSize, |
2843 | ((double)elementSize)*((double)nRows)*((double)nColumns)); |
2844 | goto ERROR_EXIT; |
2845 | } |
2846 | |
2847 | /* Allocate memory for the circular buffer for the imaginary part */ |
2848 | if (complex) { |
2849 | if ( (var->data.im = malloc(nRows*nColumns*elementSize)) == NULL ) { |
2850 | (void)fprintf(stderr, |
2851 | "*** Error allocating memory for the circular buffer " |
2852 | "for logging the imaginary part of %s\n", varName); |
2853 | (void)fprintf(stderr, "*** Details:\n" |
2854 | " varName = %s\n" |
2855 | " nRows = %d\n" |
2856 | " nCols = %d\n" |
2857 | " elementSize = %lu\n" |
2858 | " Bytes Requested = %.16g\n\n", |
2859 | varName, nRows, nColumns, (unsigned long) elementSize, |
2860 | ((double)elementSize)*((double)nRows)* |
2861 | ((double)nColumns)); |
2862 | goto ERROR_EXIT; |
2863 | } |
2864 | } |
2865 | /* |
2866 | * Initialize the fields in LogVar structure. |
2867 | */ |
2868 | if (appendToLogVarsList) { |
2869 | rt_LoadModifiedLogVarName(li,varName,var->data.name); |
2870 | } else { |
2871 | var->data.name[mxMAXNAM-1] = '\0'; |
2872 | (void)strncpy(var->data.name,varName,mxMAXNAM-1); |
2873 | } |
2874 | var->data.nCols = nColumns; |
2875 | var->data.nRows = nRows; |
2876 | |
2877 | var->data.nDims = frameData ? 1 : nDims; |
2878 | if (var->data.nDims > 2) { |
2879 | var->data.dims = (int_T*)malloc(sizeof(int_T)*var->data.nDims); |
2880 | } else { |
2881 | var->data.dims = var->data._dims; |
2882 | } |
2883 | if (frameData) { |
2884 | var->data.dims[0] = nColumns; |
2885 | } else { |
2886 | /*LINTED E_CAST_INT_TO_SMALL_INT*/ |
2887 | (void)memcpy(var->data.dims, dims, (size_t)(nDims*sizeof(int_T))); |
2888 | } |
2889 | |
2890 | var->data.dTypeID = dTypeID; |
2891 | var->data.elSize = elementSize; |
2892 | |
2893 | var->data.dataTypeConvertInfo = rt_GetDataTypeConvertInfo( |
2894 | pDataTypeConvertInfo, dTypeID); |
2895 | |
2896 | var->data.mxID = rt_GetMxIdFromDTypeId(dTypeID); |
2897 | /* over-ride logical bit if data type is boolean */ |
2898 | logical = dTypeID == SS_BOOLEAN ? 1 : 0; |
2899 | var->data.logical = (logical) ? matLOGICAL_BIT : 0x0; |
2900 | var->data.complex = (complex) ? matCOMPLEX_BIT : 0x0; |
2901 | var->data.frameData = frameData; |
2902 | var->data.frameSize = (frameData) ? frameSize : 1; |
2903 | |
2904 | /* fill up valDims field */ |
2905 | if(logValDimsStat == NO_LOGVALDIMS){ |
2906 | /* All signals are fixed-size, no need to log valueDimensions field */ |
2907 | var->valDims = NULL; |
2908 | /* Set these pointers to NULLs in this case */ |
2909 | var->coords = NULL; |
2910 | var->strides = NULL; |
2911 | var->currStrides = NULL; |
2912 | } |
2913 | else{ |
2914 | if ( (var->valDims = calloc(1, sizeof(ValDimsData))) == NULL ) { |
2915 | goto ERROR_EXIT; |
2916 | } |
2917 | |
2918 | (void)memcpy(var->valDims->name, &VALUEDIMENSIONS_FIELD_NAME, mxMAXNAM); |
2919 | |
2920 | if (logValDimsStat == LOGVALDIMS_EMPTYMX) { |
2921 | /* At least one signal is variable-size, |
2922 | but the current signal is fixed-size. |
2923 | Therefore, create a dummy MatrixData to write out valueDimensions |
2924 | as an empty matrix. |
2925 | */ |
2926 | var->valDims->nRows = 0; |
2927 | var->valDims->nCols = 0; |
2928 | var->valDims->currSigDims = NULL; |
2929 | var->valDims->currSigDimsSize = NULL; |
2930 | var->valDims->dimsData = NULL; |
2931 | /* Set these pointers to NULLs in this case */ |
2932 | var->coords = NULL; |
2933 | var->strides = NULL; |
2934 | var->currStrides = NULL; |
2935 | } else { /* The current signal is a variable-size signal. */ |
2936 | /* The "valueDimensions" must be double, so re-assign element size */ |
2937 | elementSize = sizeof(real_T); |
2938 | |
2939 | /* When signals are frame-based, 'valueDimensions' has 1 column */ |
2940 | if(frameData){ |
2941 | /* When signal is frame-based, the first dimension is always fixed, |
2942 | so we only need to record the second dimension. |
2943 | e.g. Two frame-based signals [10x4] and [10x3], |
2944 | 'valueDimensions' and 'currSigDims' |
2945 | only record 4 or 3. |
2946 | */ |
2947 | nColumns = 1; |
2948 | var->valDims->currSigDims = (void**) (currSigDims + 1); |
2949 | var->valDims->currSigDimsSize = (int_T*) (currSigDimsSize + 1); |
2950 | } else { /* non-frame based */ |
2951 | nColumns = nDims; |
2952 | var->valDims->currSigDims = (void**) currSigDims; |
2953 | var->valDims->currSigDimsSize = (int_T*) currSigDimsSize; |
2954 | } |
2955 | |
2956 | /* Allocate memory for the circular buffer */ |
2957 | if ( (var->valDims->dimsData = malloc(nRows*nColumns*elementSize)) == NULL ) { |
2958 | (void)fprintf(stderr, |
2959 | "*** Error allocating memory for the circular buffer\n"); |
2960 | (void)fprintf(stderr, "*** Details:\n" |
2961 | " varName = %s\n" |
2962 | " nRows = %d\n" |
2963 | " nCols = %d\n" |
2964 | " elementSize = %lu\n" |
2965 | " Bytes Requested = %.16g\n\n", |
2966 | var->valDims->name, nRows, nColumns, (unsigned long) elementSize, |
2967 | ((double)elementSize)*((double)nRows)*((double)nColumns)); |
2968 | goto ERROR_EXIT; |
2969 | } |
2970 | var->valDims->nRows = nRows; |
2971 | var->valDims->nCols = nColumns; |
2972 | |
2973 | /* Allocate memory for these dynamic arrays */ |
2974 | { |
2975 | size_t nbytes = var->data.nDims*sizeof(int_T); |
2976 | if( ((var->coords = calloc(nbytes, 1)) == NULL) |
2977 | ||((var->strides = calloc(nbytes, 1)) == NULL) |
2978 | ||((var->currStrides = calloc(nbytes, 1)) == NULL) ) |
2979 | goto ERROR_EXIT; |
2980 | } |
2981 | } |
2982 | } |
2983 | |
2984 | var->rowIdx = 0; |
2985 | var->wrapped = 0; |
2986 | var->nDataPoints = 0; |
2987 | var->usingDefaultBufSize = usingDefaultBufSize; |
2988 | var->okayToRealloc = okayToRealloc; |
2989 | var->decimation = decimation; |
2990 | var->numHits = -1; /* so first point gets logged */ |
2991 | |
2992 | /* Add this log var to list in log info, if necessary */ |
2993 | if (appendToLogVarsList) { |
2994 | LogInfo *logInfo = (LogInfo*) rtliGetLogInfo(li); |
2995 | LogVar *varList = logInfo->logVarsList; |
2996 | |
2997 | if (varList != NULL) { |
2998 | while (varList->next != NULL) { |
2999 | varList = varList->next; |
3000 | } |
3001 | varList->next = var; |
3002 | } else { |
3003 | logInfo->logVarsList = var; |
3004 | } |
3005 | } |
3006 | |
3007 | return(var); /* NORMAL_EXIT */ |
3008 | |
3009 | ERROR_EXIT: |
3010 | |
3011 | *errStatus = rtMemAllocError; |
3012 | rt_DestroyLogVar(var); |
3013 | return(NULL); |
3014 | |
3015 | } /* end rt_CreateLogVarWithConvert */ |
3016 | |
3017 | |
3018 | #ifdef __cplusplus |
3019 | } |
3020 | #endif |
3021 | |
3022 | |
3023 | |
3024 | |
3025 | #ifdef __cplusplus |
3026 | extern "C" { |
3027 | #endif |
3028 | |
3029 | |
3030 | /* Function: rt_CreateLogVar =================================================== |
3031 | * Abstract: |
3032 | * Create a logging variable. |
3033 | * |
3034 | * Returns: |
3035 | * ~= NULL => success, returns the log variable created. |
3036 | * == NULL => failure, error message set in the simstruct. |
3037 | */ |
3038 | LogVar *rt_CreateLogVar(RTWLogInfo *li, |
3039 | const real_T startTime, |
3040 | const real_T finalTime, |
3041 | const real_T inStepSize, |
3042 | const char_T **errStatus, |
3043 | const char_T *varName, |
3044 | BuiltInDTypeId inpDataTypeID, |
3045 | int_T logical, |
3046 | int_T complex, |
3047 | int_T frameData, |
3048 | int_T nCols, |
3049 | int_T nDims, |
3050 | const int_T *dims, |
3051 | LogValDimsStat logValDimsStat, |
3052 | void **currSigDims, |
3053 | int_T *currSigDimsSize, |
3054 | int_T maxRows, |
3055 | int_T decimation, |
3056 | real_T sampleTime, |
3057 | int_T appendToLogVarsList) |
3058 | { |
3059 | const RTWLogDataTypeConvert *pDataTypeConvertInfo = NULL; |
3060 | |
3061 | return rt_CreateLogVarWithConvert(li, |
3062 | startTime, |
3063 | finalTime, |
3064 | inStepSize, |
3065 | errStatus, |
3066 | varName, |
3067 | inpDataTypeID, |
3068 | pDataTypeConvertInfo, |
3069 | logical, |
3070 | complex, |
3071 | frameData, |
3072 | nCols, |
3073 | nDims, |
3074 | dims, |
3075 | logValDimsStat, |
3076 | currSigDims, |
3077 | currSigDimsSize, |
3078 | maxRows, |
3079 | decimation, |
3080 | sampleTime, |
3081 | appendToLogVarsList); |
3082 | |
3083 | } /* end rt_CreateLogVar */ |
3084 | |
3085 | |
3086 | #ifdef __cplusplus |
3087 | } |
3088 | #endif |
3089 | |
3090 | |
3091 | |
3092 | |
3093 | #ifdef __cplusplus |
3094 | extern "C" { |
3095 | #endif |
3096 | |
3097 | |
3098 | /* Function: rt_CreateStructLogVar ============================================= |
3099 | * Abstract: |
3100 | * Create a logging variable in the structure format. |
3101 | * |
3102 | * Returns: |
3103 | * ~= NULL => success, returns the log variable created. |
3104 | * == NULL => failure, error message set in the simstruct. |
3105 | */ |
3106 | StructLogVar *rt_CreateStructLogVar(RTWLogInfo *li, |
3107 | const real_T startTime, |
3108 | const real_T finalTime, |
3109 | const real_T inStepSize, |
3110 | const char_T **errStatus, |
3111 | const char_T *varName, |
3112 | boolean_T logTime, |
3113 | int_T maxRows, |
3114 | int_T decimation, |
3115 | real_T sampleTime, |
3116 | const RTWLogSignalInfo *sigInfo, |
3117 | const char_T *blockName) |
3118 | { |
3119 | |
3120 | return( local_CreateStructLogVar(li, |
3121 | startTime, |
3122 | finalTime, |
3123 | inStepSize, |
3124 | errStatus, |
3125 | varName, |
3126 | logTime, |
3127 | maxRows, |
3128 | decimation, |
3129 | sampleTime, |
3130 | sigInfo, |
3131 | blockName)); |
3132 | |
3133 | } /* end rt_CreateStructLogVar */ |
3134 | |
3135 | |
3136 | #ifdef __cplusplus |
3137 | } |
3138 | #endif |
3139 | |
3140 | |
3141 | |
3142 | |
3143 | #ifdef __cplusplus |
3144 | extern "C" { |
3145 | #endif |
3146 | |
3147 | |
3148 | /* Function: rt_StartDataLoggingWithStartTime ================================== |
3149 | * Abstract: |
3150 | * Initialize data logging info based upon the following settings cached |
3151 | * in the RTWLogging data structure of the SimStruct. |
3152 | * |
3153 | * Return value is: |
3154 | * == NULL => success |
3155 | * != NULL => failure (the return value is a pointer that points to the |
3156 | * error message, which is also set in the simstruct) |
3157 | */ |
3158 | const char_T *rt_StartDataLoggingWithStartTime(RTWLogInfo *li, |
3159 | const real_T startTime, |
3160 | const real_T finalTime, |
3161 | const real_T stepSize, |
3162 | const char_T **errStatus) |
3163 | { |
3164 | const char_T *varName; |
3165 | LogInfo *logInfo; |
3166 | real_T sampleTime = stepSize; |
3167 | int_T maxRows = rtliGetLogMaxRows(li); |
3168 | int_T decimation = rtliGetLogDecimation(li); |
3169 | int_T logFormat = rtliGetLogFormat(li); |
3170 | boolean_T logTime = (logFormat==2) ? 1 : 0; |
3171 | |
3172 | /* reset error status */ |
3173 | *errStatus = NULL; |
3174 | |
3175 | if ((logInfo=calloc(1,sizeof(LogInfo))) == NULL) { |
3176 | *errStatus = rtMemAllocError; |
3177 | goto ERROR_EXIT; |
3178 | } |
3179 | rtliSetLogInfo(li, (void*)logInfo); |
3180 | |
3181 | /* time */ |
3182 | varName = rtliGetLogT(li); |
3183 | if (varName[0] != '\0') { |
3184 | int_T dims = 1; |
3185 | logInfo->t = rt_CreateLogVarWithConvert(li, startTime, finalTime, |
3186 | stepSize, errStatus, |
3187 | varName,SS_DOUBLE, |
3188 | NULL, |
3189 | 0,0,0,1,1, |
3190 | &dims, NO_LOGVALDIMS, NULL, NULL, |
3191 | maxRows,decimation, |
3192 | sampleTime,1); |
3193 | if (logInfo->t == NULL) goto ERROR_EXIT; |
3194 | } |
3195 | |
3196 | /* states */ |
3197 | if ( rtliGetLogX(li)[0] != '\0' || rtliGetLogXFinal(li)[0] != '\0' ) { |
3198 | const RTWLogSignalInfo *xInfo = rtliGetLogXSignalInfo(li); |
3199 | |
3200 | if (logFormat == 0) { /* Matrix Format */ |
3201 | int numCols; |
3202 | int nDims; |
3203 | const int *dims; |
3204 | BuiltInDTypeId dataType; |
3205 | int isComplex; |
3206 | int_T sIdx; |
3207 | |
3208 | const RTWLogDataTypeConvert *pDTConvInfo; |
3209 | |
3210 | numCols = xInfo[0].numCols ? xInfo[0].numCols[0] : 0; |
3211 | for (sIdx = 1; sIdx < xInfo[0].numSignals; sIdx++) { |
3212 | numCols += xInfo[0].numCols[sIdx]; |
3213 | } |
3214 | /* If we have only one "matrix" state, we can log as a matrix */ |
3215 | if (xInfo[0].numSignals == 1) { |
3216 | nDims = xInfo[0].numDims ? xInfo[0].numDims[0] : 1; |
3217 | dims = xInfo[0].dims; |
3218 | } else { |
3219 | nDims = 1; |
3220 | dims = &numCols; |
3221 | } |
3222 | dataType = xInfo[0].dataTypes ? xInfo[0].dataTypes[0] : 0; |
3223 | isComplex = xInfo[0].complexSignals ? xInfo[0].complexSignals[0] : 0; |
3224 | |
3225 | pDTConvInfo = xInfo[0].dataTypeConvert; |
3226 | |
3227 | if (rtliGetLogX(li)[0] != '\0') { |
3228 | logInfo->x = rt_CreateLogVarWithConvert(li, startTime, finalTime, |
3229 | stepSize, errStatus, |
3230 | rtliGetLogX(li),dataType, |
3231 | pDTConvInfo, |
3232 | 0, |
3233 | isComplex,0,numCols,nDims,dims, |
3234 | NO_LOGVALDIMS, NULL, NULL, |
3235 | maxRows,decimation,sampleTime,1); |
3236 | if (logInfo->x == NULL) goto ERROR_EXIT; |
3237 | } |
3238 | if (rtliGetLogXFinal(li)[0] != '\0') { |
3239 | logInfo->xFinal = rt_CreateLogVarWithConvert(li, startTime, finalTime, |
3240 | stepSize, errStatus, |
3241 | rtliGetLogXFinal(li),dataType, |
3242 | pDTConvInfo, |
3243 | 0,isComplex,0,numCols,nDims, |
3244 | dims, NO_LOGVALDIMS, NULL, |
3245 | NULL, 1,decimation, |
3246 | sampleTime,1); |
3247 | if (logInfo->xFinal == NULL) goto ERROR_EXIT; |
3248 | } |
3249 | } else { /* Structure Format */ |
3250 | if (rtliGetLogX(li)[0] != '\0') { |
3251 | logInfo->x = local_CreateStructLogVar(li, startTime, finalTime, |
3252 | stepSize, errStatus, |
3253 | rtliGetLogX(li), logTime, |
3254 | maxRows, decimation, |
3255 | sampleTime, xInfo, NULL); |
3256 | if (logInfo->x == NULL) goto ERROR_EXIT; |
3257 | } |
3258 | if (rtliGetLogXFinal(li)[0] != '\0') { |
3259 | logInfo->xFinal = local_CreateStructLogVar(li, startTime, finalTime, |
3260 | stepSize, errStatus, |
3261 | rtliGetLogXFinal(li), |
3262 | logTime,1,decimation, |
3263 | sampleTime,xInfo,NULL); |
3264 | if (logInfo->xFinal == NULL) goto ERROR_EXIT; |
3265 | } |
3266 | } |
3267 | } |
3268 | |
3269 | /* outputs */ |
3270 | *errStatus = rt_StartDataLoggingForOutput(li,startTime,finalTime, |
3271 | stepSize,errStatus); |
3272 | if (*errStatus != NULL) goto ERROR_EXIT; |
3273 | |
3274 | return(NULL); /* NORMAL_EXIT */ |
3275 | |
3276 | ERROR_EXIT: |
3277 | (void)fprintf(stderr, "*** Errors occurred when starting data logging.\n"); |
3278 | if (*errStatus == NULL) { |
3279 | *errStatus = rtMemAllocError; |
3280 | } |
3281 | if (logInfo) { |
3282 | rt_DestroyLogVar(logInfo->logVarsList); |
3283 | logInfo->logVarsList = NULL; |
3284 | rt_DestroyStructLogVar(logInfo->structLogVarsList); |
3285 | logInfo->structLogVarsList = NULL; |
3286 | FREE(logInfo); |
3287 | rtliSetLogInfo(li,NULL); |
3288 | } |
3289 | return(*errStatus); |
3290 | |
3291 | } /* end rt_StartDataLoggingWithStartTime */ |
3292 | |
3293 | |
3294 | #ifdef __cplusplus |
3295 | } |
3296 | #endif |
3297 | |
3298 | |
3299 | |
3300 | |
3301 | #ifdef __cplusplus |
3302 | extern "C" { |
3303 | #endif |
3304 | |
3305 | |
3306 | /* Function: rt_StartDataLogging =============================================== |
3307 | * Abstract: |
3308 | */ |
3309 | const char_T *rt_StartDataLogging(RTWLogInfo *li, |
3310 | const real_T finalTime, |
3311 | const real_T stepSize, |
3312 | const char_T **errStatus) |
3313 | { |
3314 | return rt_StartDataLoggingWithStartTime(li, |
3315 | 0.0, |
3316 | finalTime, |
3317 | stepSize, |
3318 | errStatus); |
3319 | } |
3320 | |
3321 | |
3322 | #ifdef __cplusplus |
3323 | } |
3324 | #endif |
3325 | |
3326 | |
3327 | |
3328 | |
3329 | #ifdef __cplusplus |
3330 | extern "C" { |
3331 | #endif |
3332 | |
3333 | |
3334 | /* Function: rt_UpdateLogVar =================================================== |
3335 | * Abstract: |
3336 | * Called to log data for a log variable. |
3337 | */ |
3338 | void rt_UpdateLogVar(LogVar *var, const void *data, boolean_T isVarDims) |
3339 | { |
3340 | size_t elSize = var->data.elSize; |
3341 | const char_T *cData = data; |
3342 | const int_T frameData = var->data.frameData; |
3343 | const int_T frameSize = frameData ? (var->data.frameSize) : 1; |
3344 | const int_T logWidth = var->data.nCols; |
3345 | BuiltInDTypeId dTypeID = var->data.dTypeID; |
3346 | |
3347 | size_t offset = 0; |
3348 | char_T *currRealRow = NULL; |
3349 | char_T *currImagRow = NULL; |
3350 | int_T pointSize = (int_T)((var->data.complex) ? rt_GetSizeofComplexType(dTypeID) : elSize); |
3351 | |
3352 | int i, j, k; |
3353 | |
3354 | /* The following variables will be used for |
3355 | logging variable-size signals */ |
3356 | const int_T nDims = var->data.nDims; |
3357 | const int_T *dims = var->data.dims; |
3358 | const void * const *currDimsPtr = NULL; |
3359 | const int_T *currDimsSizePtr = NULL; |
3360 | |
3361 | /* The following variables will be used for |
3362 | logging "valueDimensions" field */ |
3363 | size_t offset_valDims = 0; |
3364 | char_T *currValDimsRow = NULL; |
3365 | size_t elSize_valDims = sizeof(real_T); |
3366 | real_T currentSigDims = 0; |
3367 | int_T nRows_valDims = 0; |
3368 | int_T logWidth_valDims = 0; |
3369 | |
3370 | for (i = 0; i < frameSize; i++) { |
3371 | if (++var->numHits % var->decimation) continue; |
3372 | var->numHits = 0; |
3373 | |
3374 | if (var->rowIdx == var->data.nRows) { |
3375 | if (var->okayToRealloc == 1) { |
3376 | rt_ReallocLogVar(var, isVarDims); |
3377 | } else { |
3378 | /* Circular buffer */ |
3379 | var->rowIdx = 0; |
3380 | ++(var->wrapped); /* increment the wrap around counter */ |
3381 | } |
3382 | } |
3383 | |
3384 | if(isVarDims){ |
3385 | currDimsPtr = (const void * const *) var->valDims->currSigDims; |
3386 | currDimsSizePtr = (const int_T*) var->valDims->currSigDimsSize; |
3387 | logWidth_valDims = frameData ? 1 : var->valDims->nCols; |
3388 | nRows_valDims = var->valDims->nRows; |
3389 | |
3390 | var->strides[0] = 1; |
3391 | var->currStrides[0] = 1; |
3392 | |
3393 | for (k = 1; k < nDims; k++){ |
3394 | int32_T currDimsVal=0; |
3395 | switch (currDimsSizePtr[k-1]) { |
3396 | case 1: |
3397 | currDimsVal = (**(((const uint8_T * const *) currDimsPtr)+(k-1))); |
3398 | break; |
3399 | case 2: |
3400 | currDimsVal = (**(((const uint16_T * const *) currDimsPtr)+(k-1))); |
3401 | break; |
3402 | case 4: |
3403 | currDimsVal = (**(((const uint32_T * const *) currDimsPtr)+(k-1))); |
3404 | break; |
3405 | } |
3406 | var->strides[k] = var->strides[k-1] * dims[k-1]; |
3407 | var->currStrides[k] = var->currStrides[k-1] * currDimsVal; |
3408 | } |
3409 | } |
3410 | |
3411 | offset = (size_t)(elSize * var->rowIdx * logWidth); |
3412 | currRealRow = ((char_T*) (var->data.re)) + offset; |
3413 | currImagRow = (var->data.complex) ? |
3414 | ((char_T*) (var->data.im)) + offset : NULL; |
3415 | |
3416 | /* update logging data */ |
3417 | for (j = 0; j < logWidth; j++) { |
3418 | |
3419 | boolean_T inRange = true; |
3420 | int idx = j; |
3421 | |
3422 | /* Check whether the currently logged value is in range or not. |
3423 | For fixed-size signal logging, always inRange = true; idx = j; |
3424 | For variable-size signal logging, use strides, coordinates |
3425 | and current strides to decide whether the currently logged |
3426 | data is in range or not and its location in the logging |
3427 | matrix. |
3428 | */ |
3429 | if(isVarDims){ |
3430 | int rem = j; |
3431 | idx = 0; |
3432 | for(k = nDims-1; k>=0; k--){ |
3433 | int32_T currDimsVal=0; |
3434 | switch (currDimsSizePtr[k]) { |
3435 | case 1: |
3436 | currDimsVal = (**(((const uint8_T * const *) currDimsPtr)+k)); |
3437 | break; |
3438 | case 2: |
3439 | currDimsVal = (**(((const uint16_T * const *) currDimsPtr)+k)); |
3440 | break; |
3441 | case 4: |
3442 | currDimsVal = (**(((const uint32_T * const *) currDimsPtr)+k)); |
3443 | break; |
3444 | } |
3445 | var->coords[k] = rem / var->strides[k]; |
3446 | if( var->coords[k] >= currDimsVal ){ |
3447 | inRange = false; |
3448 | break; |
3449 | } |
3450 | rem = rem - var->coords[k] * var->strides[k]; |
3451 | } |
3452 | if(inRange){ |
3453 | idx = var->coords[0]; |
3454 | for (k = 1; k < nDims; k++){ |
3455 | idx += var->coords[k] * var->currStrides[k]; |
3456 | } |
3457 | } |
3458 | } |
3459 | |
3460 | if (!var->data.dataTypeConvertInfo.conversionNeeded) { |
3461 | /* NO conversion needed |
3462 | */ |
3463 | if (inRange) { |
3464 | /* If in range, fill in data */ |
3465 | const char *cDataPoint = cData + (i+frameSize*idx) * pointSize; |
3466 | |
3467 | (void) memcpy(currRealRow, cDataPoint, elSize); |
3468 | currRealRow += elSize; |
3469 | if (var->data.complex) { |
3470 | (void) memcpy(currImagRow, cDataPoint + pointSize/2, elSize); |
3471 | currImagRow += elSize; |
3472 | } |
3473 | } else { |
3474 | /* If out of range, fill in NaN or 0: |
3475 | 1) For bool, int32, uint32, int16, uint16, etc, |
3476 | memset to zeros; |
3477 | 2) For fixed-point data type, NaN conversion is not |
3478 | allowed, memset to zeros. |
3479 | */ |
3480 | if (dTypeID == SS_DOUBLE) { |
3481 | (void) memcpy(currRealRow, &rtNaN, elSize); |
3482 | } else if (dTypeID == SS_SINGLE){ |
3483 | (void) memcpy(currRealRow, &rtNaNF, elSize); |
3484 | } else { |
3485 | (void) memset(currRealRow, 0, elSize); |
3486 | } |
3487 | |
3488 | currRealRow += elSize; |
3489 | if (var->data.complex) { |
3490 | /* For imaginary part, fill in 0 */ |
3491 | (void) memset(currImagRow, 0, elSize); |
3492 | currImagRow += elSize; |
3493 | } |
3494 | } |
3495 | } |
3496 | else |
3497 | { |
3498 | /* YES conversion needed |
3499 | */ |
3500 | DTypeId dataTypeIdOriginal = |
3501 | var->data.dataTypeConvertInfo.dataTypeIdOriginal; |
3502 | int_T DpSize = (int_T)((var->data.complex) ? |
3503 | rt_GetSizeofComplexType(dataTypeIdOriginal) : |
3504 | rt_GetSizeofDataType(dataTypeIdOriginal)); |
3505 | |
3506 | DTypeId dataTypeIdLoggingTo = |
3507 | var->data.dataTypeConvertInfo.dataTypeIdLoggingTo; |
3508 | |
3509 | int bitsPerChunk = var->data.dataTypeConvertInfo.bitsPerChunk; |
3510 | int numOfChunk = var->data.dataTypeConvertInfo.numOfChunk; |
3511 | unsigned int isSigned = var->data.dataTypeConvertInfo.isSigned; |
3512 | |
3513 | double fracSlope = var->data.dataTypeConvertInfo.fracSlope; |
3514 | int fixedExp = var->data.dataTypeConvertInfo.fixedExp; |
3515 | double bias = var->data.dataTypeConvertInfo.bias; |
3516 | |
3517 | double curRealValue = -0.12345678987654; |
3518 | double curImagValue = -0.12345678987654; |
3519 | |
3520 | int_T adjIndexIfComplex = (var->data.complex) ? 2 : 1; |
3521 | |
3522 | if(inRange){ |
3523 | if(numOfChunk > 1) |
3524 | { |
3525 | /* For multiword */ |
3526 | const char *pInData = (const char *)(cData); |
3527 | int dtSize = bitsPerChunk*numOfChunk/8; |
3528 | pInData += ((i+frameSize*idx) * adjIndexIfComplex) * dtSize; |
3529 | |
3530 | curRealValue = rt_GetDblValueFromOverSizedData(pInData, bitsPerChunk, numOfChunk, |
3531 | isSigned, fracSlope, fixedExp, bias); |
3532 | if (var->data.complex) { |
3533 | curImagValue = rt_GetDblValueFromOverSizedData((pInData+dtSize), bitsPerChunk, numOfChunk, |
3534 | isSigned, fracSlope, fixedExp, bias); |
3535 | } |
3536 | } |
3537 | else |
3538 | { |
3539 | /* if in range, fill in data that is converted first */ |
3540 | switch ( dataTypeIdOriginal ) |
3541 | { |
3542 | case SS_DOUBLE: |
3543 | { |
3544 | const real_T *pInData = (const real_T *)(cData + (i+frameSize*idx)* DpSize); |
3545 | |
3546 | curRealValue = ldexp( fracSlope * (double)(*pInData), fixedExp ) + bias; |
3547 | if (var->data.complex) { |
3548 | pInData = (const real_T *)(cData + (i+frameSize*idx)* DpSize + DpSize/2); |
3549 | curImagValue = ldexp( fracSlope * (double)(*pInData), fixedExp ) + bias; |
3550 | } |
3551 | } |
3552 | break; |
3553 | case SS_SINGLE: |
3554 | { |
3555 | const real32_T *pInData = (const real32_T *)(cData + (i+frameSize*idx)* DpSize); |
3556 | |
3557 | curRealValue = ldexp( fracSlope * (double)(*pInData), fixedExp ) + bias; |
3558 | if (var->data.complex) { |
3559 | pInData = (const real32_T *)(cData + (i+frameSize*idx)* DpSize + DpSize/2); |
3560 | curImagValue = ldexp( fracSlope * (double)(*pInData), fixedExp ) + bias; |
3561 | } |
3562 | } |
3563 | break; |
3564 | case SS_INT8: |
3565 | { |
3566 | const int8_T *pInData = (const int8_T *)(cData + (i+frameSize*idx)* DpSize); |
3567 | |
3568 | curRealValue = ldexp( fracSlope * (double)(*pInData), fixedExp ) + bias; |
3569 | if (var->data.complex) { |
3570 | pInData = (const int8_T *)(cData + (i+frameSize*idx)* DpSize + DpSize/2); |
3571 | curImagValue = ldexp( fracSlope * (double)(*pInData), fixedExp ) + bias; |
3572 | } |
3573 | } |
3574 | break; |
3575 | case SS_UINT8: |
3576 | { |
3577 | const uint8_T *pInData = (const uint8_T *)(cData + (i+frameSize*idx)* DpSize); |
3578 | |
3579 | curRealValue = ldexp( fracSlope * (double)(*pInData), fixedExp ) + bias; |
3580 | if (var->data.complex) { |
3581 | pInData = (const uint8_T *)(cData + (i+frameSize*idx)* DpSize + DpSize/2); |
3582 | curImagValue = ldexp( fracSlope * (double)(*pInData), fixedExp ) + bias; |
3583 | } |
3584 | } |
3585 | break; |
3586 | case SS_INT16: |
3587 | { |
3588 | const int16_T *pInData = (const int16_T *)(cData + (i+frameSize*idx)* DpSize); |
3589 | |
3590 | curRealValue = ldexp( fracSlope * (double)(*pInData), fixedExp ) + bias; |
3591 | if (var->data.complex) { |
3592 | pInData = (const int16_T *)(cData + (i+frameSize*idx)* DpSize + DpSize/2); |
3593 | curImagValue = ldexp( fracSlope * (double)(*pInData), fixedExp ) + bias; |
3594 | } |
3595 | } |
3596 | break; |
3597 | case SS_UINT16: |
3598 | { |
3599 | const uint16_T *pInData = (const uint16_T *)(cData + (i+frameSize*idx)* DpSize); |
3600 | |
3601 | curRealValue = ldexp( fracSlope * (double)(*pInData), fixedExp ) + bias; |
3602 | if (var->data.complex) { |
3603 | pInData = (const uint16_T *)(cData + (i+frameSize*idx)* DpSize + DpSize/2); |
3604 | curImagValue = ldexp( fracSlope * (double)(*pInData), fixedExp ) + bias; |
3605 | } |
3606 | } |
3607 | break; |
3608 | case SS_INT32: |
3609 | { |
3610 | const int32_T *pInData = (const int32_T *)(cData + (i+frameSize*idx)* DpSize); |
3611 | |
3612 | curRealValue = ldexp( fracSlope * (double)(*pInData), fixedExp ) + bias; |
3613 | if (var->data.complex) { |
3614 | pInData = (const int32_T *)(cData + (i+frameSize*idx)* DpSize + DpSize/2); |
3615 | curImagValue = ldexp( fracSlope * (double)(*pInData), fixedExp ) + bias; |
3616 | } |
3617 | } |
3618 | break; |
3619 | case SS_UINT32: |
3620 | { |
3621 | const uint32_T *pInData = (const uint32_T *)(cData + (i+frameSize*idx)* DpSize); |
3622 | |
3623 | curRealValue = ldexp( fracSlope * (double)(*pInData), fixedExp ) + bias; |
3624 | if (var->data.complex) { |
3625 | pInData = (const uint32_T *)(cData + (i+frameSize*idx)* DpSize + DpSize/2); |
3626 | curImagValue = ldexp( fracSlope * (double)(*pInData), fixedExp ) + bias; |
3627 | } |
3628 | } |
3629 | break; |
3630 | case SS_BOOLEAN: |
3631 | { |
3632 | const boolean_T *pInData = ((const boolean_T *)(cData)); |
3633 | |
3634 | pInData += (i+frameSize*idx) * adjIndexIfComplex; |
3635 | |
3636 | curRealValue = ldexp( fracSlope * (double)(*pInData), fixedExp ) + bias; |
3637 | if (var->data.complex) { |
3638 | curImagValue = ldexp( fracSlope * (double)(*pInData), fixedExp ) + bias; |
3639 | } |
3640 | } |
3641 | break; |
3642 | default: |
3643 | { |
3644 | /* For biglong */ |
3645 | const char *pInData = (const char *)(cData); |
3646 | int dtSize = bitsPerChunk*numOfChunk/8; |
3647 | pInData += ((i+frameSize*idx) * adjIndexIfComplex) * dtSize; |
3648 | |
3649 | curRealValue = rt_GetDblValueFromOverSizedData(pInData, bitsPerChunk, numOfChunk, |
3650 | isSigned, fracSlope, fixedExp, bias); |
3651 | if (var->data.complex) { |
3652 | curImagValue = rt_GetDblValueFromOverSizedData((pInData+dtSize), bitsPerChunk, numOfChunk, |
3653 | isSigned, fracSlope, fixedExp, bias); |
3654 | } |
3655 | } |
3656 | break; |
3657 | } /* -- end of switch -- */ |
3658 | } |
3659 | } else { |
3660 | /* if out of range, just fill NaN or 0 */ |
3661 | if(dTypeID == SS_DOUBLE || dTypeID == SS_SINGLE){ |
3662 | /* vijay 4/11/2013: DO NOT CALL ldexp() with NaN below as it causes |
3663 | * lcc-win64 to generate inf instead of NaN as output. |
3664 | * Just use rtNaN directly */ |
3665 | curRealValue = rtNaN; |
3666 | } |
3667 | else{ |
3668 | curRealValue = ldexp( 0, fixedExp ) + bias; |
3669 | } |
3670 | if (var->data.complex) { |
3671 | /* fill 0 in imaginary part*/ |
3672 | curImagValue = ldexp( 0, fixedExp ) + bias; |
3673 | } |
3674 | } |
3675 | |
3676 | switch ( dataTypeIdLoggingTo ) |
3677 | { |
3678 | case SS_DOUBLE: |
3679 | { |
3680 | *((real_T *)currRealRow) = (real_T)curRealValue; |
3681 | |
3682 | if (var->data.complex) { |
3683 | |
3684 | *((real_T *)currImagRow) = (real_T)curImagValue; |
3685 | } |
3686 | } |
3687 | break; |
3688 | case SS_SINGLE: |
3689 | { |
3690 | *((real32_T *)currRealRow) = (real32_T)curRealValue; |
3691 | |
3692 | if (var->data.complex) { |
3693 | |
3694 | *((real32_T *)currImagRow) = (real32_T)curImagValue; |
3695 | } |
3696 | } |
3697 | break; |
3698 | case SS_INT8: |
3699 | { |
3700 | *((int8_T *)currRealRow) = (int8_T)curRealValue; |
3701 | |
3702 | if (var->data.complex) { |
3703 | |
3704 | *((int8_T *)currImagRow) = (int8_T)curImagValue; |
3705 | } |
3706 | } |
3707 | break; |
3708 | case SS_UINT8: |
3709 | { |
3710 | *((uint8_T *)currRealRow) = (uint8_T)curRealValue; |
3711 | |
3712 | if (var->data.complex) { |
3713 | |
3714 | *((uint8_T *)currImagRow) = (uint8_T)curImagValue; |
3715 | } |
3716 | } |
3717 | break; |
3718 | case SS_INT16: |
3719 | { |
3720 | *((int16_T *)currRealRow) = (int16_T)curRealValue; |
3721 | |
3722 | if (var->data.complex) { |
3723 | |
3724 | *((int16_T *)currImagRow) = (int16_T)curImagValue; |
3725 | } |
3726 | } |
3727 | break; |
3728 | case SS_UINT16: |
3729 | { |
3730 | *((uint16_T *)currRealRow) = (uint16_T)curRealValue; |
3731 | |
3732 | if (var->data.complex) { |
3733 | |
3734 | *((uint16_T *)currImagRow) = (uint16_T)curImagValue; |
3735 | } |
3736 | } |
3737 | break; |
3738 | case SS_INT32: |
3739 | { |
3740 | *((int32_T *)currRealRow) = (int32_T)curRealValue; |
3741 | |
3742 | if (var->data.complex) { |
3743 | |
3744 | *((int32_T *)currImagRow) = (int32_T)curImagValue; |
3745 | } |
3746 | } |
3747 | break; |
3748 | case SS_UINT32: |
3749 | { |
3750 | *((uint32_T *)currRealRow) = (uint32_T)curRealValue; |
3751 | |
3752 | if (var->data.complex) { |
3753 | |
3754 | *((uint32_T *)currImagRow) = (uint32_T)curImagValue; |
3755 | } |
3756 | } |
3757 | break; |
3758 | case SS_BOOLEAN: |
3759 | { |
3760 | *((boolean_T *)currRealRow) = (boolean_T)(curRealValue != 0.0); |
3761 | |
3762 | if (var->data.complex) { |
3763 | |
3764 | *((boolean_T *)currImagRow) = (boolean_T)(curImagValue != 0.0); |
3765 | } |
3766 | } |
3767 | break; |
3768 | } /* -- end of switch -- */ |
3769 | |
3770 | currRealRow += elSize; |
3771 | if (var->data.complex) { |
3772 | currImagRow += elSize; |
3773 | } |
3774 | } |
3775 | } |
3776 | |
3777 | if(isVarDims){ /* update "valueDimensions" field */ |
3778 | for(j = 0; j < logWidth_valDims; j ++){ |
3779 | int32_T currDimsVal=0; |
3780 | switch (currDimsSizePtr[j]) { |
3781 | case 1: |
3782 | currDimsVal = (**(((const uint8_T * const *) currDimsPtr)+j)); |
3783 | break; |
3784 | case 2: |
3785 | currDimsVal = (**(((const uint16_T * const *) currDimsPtr)+j)); |
3786 | break; |
3787 | case 4: |
3788 | currDimsVal = (**(((const uint32_T * const *) currDimsPtr)+j)); |
3789 | break; |
3790 | } |
3791 | offset_valDims = (size_t)(elSize_valDims *( var->rowIdx + nRows_valDims * j)); |
3792 | currValDimsRow = ((char_T*) (var->valDims->dimsData)) + offset_valDims; |
3793 | |
3794 | /* convert int_T to real_T */ |
3795 | currentSigDims = (real_T) currDimsVal; |
3796 | (void) memcpy(currValDimsRow, ¤tSigDims, elSize_valDims); |
3797 | currValDimsRow += elSize_valDims; |
3798 | } |
3799 | } |
3800 | |
3801 | ++var->rowIdx; |
3802 | } |
3803 | |
3804 | return; |
3805 | |
3806 | } /* end rt_UpdateLogVar */ |
3807 | |
3808 | |
3809 | #ifdef __cplusplus |
3810 | } |
3811 | #endif |
3812 | |
3813 | |
3814 | |
3815 | |
3816 | #ifdef __cplusplus |
3817 | extern "C" { |
3818 | #endif |
3819 | |
3820 | |
3821 | /* Function: rt_UpdateStructLogVar ============================================= |
3822 | * Abstract: |
3823 | * Called to log data for a structure log variable. |
3824 | */ |
3825 | void rt_UpdateStructLogVar(StructLogVar *var, const real_T *t, const void *data) |
3826 | { |
3827 | LogVar *values = var->signals.values; |
3828 | const char_T *signal = data; |
3829 | boolean_T *isVarDims = var->signals.isVarDims; |
3830 | int i = 0; |
3831 | |
3832 | /* time */ |
3833 | if (var->logTime) { |
3834 | rt_UpdateLogVar(var->time, t, false); |
3835 | } |
3836 | |
3837 | /* signals */ |
3838 | while (values) { |
3839 | size_t elSz = values->data.elSize; |
3840 | |
3841 | rt_UpdateLogVar(values, signal, isVarDims[i]); |
3842 | |
3843 | if (values->data.complex) elSz *= 2; |
3844 | signal += elSz * values->data.nCols; |
3845 | |
3846 | values = values->next; |
3847 | i++; |
3848 | } |
3849 | |
3850 | } /* end rt_UpdateStructLogVar */ |
3851 | |
3852 | |
3853 | #ifdef __cplusplus |
3854 | } |
3855 | #endif |
3856 | |
3857 | |
3858 | |
3859 | |
3860 | #ifdef __cplusplus |
3861 | extern "C" { |
3862 | #endif |
3863 | |
3864 | /* |
3865 | * g1614989:Refactoring this function to accept number of elements |
3866 | * instead of accepting signalInfo and index. |
3867 | */ |
3868 | void* rt_getTempMemory(LogVar* var, int_T numEls); |
3869 | |
3870 | void* rt_getTempMemory(LogVar* var, int_T numEls) |
3871 | { |
3872 | size_t elSize = var->data.elSize; |
3873 | size_t cmplxMult = var->data.complex ? 2 : 1; |
3874 | /* |
3875 | * g1689750: With multiword support for mat file logging in row major array layout, we need to allocate more space to |
3876 | * store the data when the transpose operation is being performed. The additional space is required to store multiple |
3877 | * chunks that each multi word contains. |
3878 | */ |
3879 | size_t numOfChunks = var->data.dataTypeConvertInfo.conversionNeeded ? var->data.dataTypeConvertInfo.numOfChunk : 1; |
3880 | void* tempMemory = malloc(elSize * numEls * cmplxMult * numOfChunks); |
3881 | return tempMemory; |
3882 | } |
3883 | |
3884 | /* |
3885 | * g1614989:This function processes the signal data if a function pointer is available and then logs the data. |
3886 | * If a function pointer is not present, signal data is logged without any processing. |
3887 | * The idx parameter specifies which information from the SignalInfo to be used for processing and logging. |
3888 | * When idx is -1, the provided signal info is to be used for processing and logging the data. |
3889 | */ |
3890 | void rt_preProcessAndLogDataWithIndex(const RTWLogSignalInfo *signalInfo, int_T idx, LogVar* val, const void * data, boolean_T isVarDims); |
3891 | |
3892 | void rt_preProcessAndLogDataWithIndex(const RTWLogSignalInfo *signalInfo, int_T idx, LogVar* val, const void * data, boolean_T isVarDims) |
3893 | { |
3894 | RTWPreprocessingFcnPtr preprocessingPtr = NULL; |
3895 | int_T numEls = -1; |
3896 | if (idx == -1) { |
3897 | preprocessingPtr = *(signalInfo->preprocessingPtrs); |
3898 | numEls = *(signalInfo->numCols); |
3899 | } |
3900 | else { |
3901 | preprocessingPtr = signalInfo->preprocessingPtrs[idx]; |
3902 | numEls = signalInfo->numCols[idx]; |
3903 | } |
3904 | |
3905 | if (preprocessingPtr != NULL) { |
3906 | void* curData = rt_getTempMemory(val, numEls); |
3907 | preprocessingPtr(curData, data); |
3908 | rt_UpdateLogVar(val, curData, isVarDims); |
3909 | free(curData); |
3910 | } |
3911 | else { |
3912 | rt_UpdateLogVar(val, data, isVarDims); |
3913 | } |
3914 | } |
3915 | |
3916 | /* |
3917 | * g1614989:This function is called when each signal has a specific RTWLogSignalInfo structure defined. |
3918 | */ |
3919 | |
3920 | void rt_preProcessAndLogData(RTWLogSignalInfo signalInfo, LogVar* val, const void * data, boolean_T isVarDims); |
3921 | |
3922 | void rt_preProcessAndLogData(RTWLogSignalInfo signalInfo, LogVar* val, const void * data, boolean_T isVarDims) |
3923 | { |
3924 | rt_preProcessAndLogDataWithIndex(&signalInfo, -1, val, data, isVarDims); |
3925 | } |
3926 | |
3927 | /* Function: rt_UpdateTXYLogVars =============================================== |
3928 | * Abstract: |
3929 | * Update the xFinal,T,X,Y variables that are being logged. |
3930 | */ |
3931 | const char_T *rt_UpdateTXYLogVars(RTWLogInfo *li, time_T *tPtr) |
3932 | { |
3933 | return rt_UpdateTXXFYLogVars(li, tPtr, true); |
3934 | } |
3935 | |
3936 | /* Function: rt_UpdateTXXFYLogVars ============================================= |
3937 | * Abstract: |
3938 | * Update xFinal and/or the T,X,Y variables that are being logged |
3939 | */ |
3940 | const char_T *rt_UpdateTXXFYLogVars(RTWLogInfo *li, time_T *tPtr, boolean_T updateTXY) |
3941 | { |
3942 | LogInfo *logInfo = rtliGetLogInfo(li); |
3943 | int_T matrixFormat = (rtliGetLogFormat(li) == 0); |
3944 | const RTWLogSignalInfo* yInfo = rtliGetLogYSignalInfo(li); |
3945 | const RTWLogSignalInfo* xInfo = rtliGetLogXSignalInfo(li); |
3946 | |
3947 | /* time */ |
3948 | if (logInfo->t != NULL && updateTXY) { |
3949 | rt_UpdateLogVar(logInfo->t, tPtr, false); |
3950 | } |
3951 | |
3952 | if (matrixFormat) { /* MATRIX_FORMAT */ |
3953 | /* states */ |
3954 | if (logInfo->x != NULL || logInfo->xFinal != NULL) { |
3955 | int8_T** segAddr = _rtliGetLogXSignalPtrs(li); |
3956 | const int_T *segLengths = xInfo->numCols; |
3957 | int_T nSegments = xInfo->numSignals; |
3958 | RTWPreprocessingFcnPtr* preprocessingPtrs = xInfo->preprocessingPtrs; |
3959 | |
3960 | if (logInfo->x != NULL && updateTXY) { |
3961 | const char_T *errorMessage = rt_UpdateLogVarWithDiscontiguousData(logInfo->x, segAddr, |
3962 | segLengths, nSegments, |
3963 | preprocessingPtrs); |
3964 | if (errorMessage != NULL) return(errorMessage); |
3965 | } |
3966 | if (logInfo->xFinal != NULL) { |
3967 | const char_T *errorMessage = rt_UpdateLogVarWithDiscontiguousData(logInfo->xFinal, segAddr, |
3968 | segLengths, nSegments, |
3969 | preprocessingPtrs); |
3970 | if (errorMessage != NULL) return(errorMessage); |
3971 | } |
3972 | } |
3973 | /* outputs */ |
3974 | if (logInfo->y != NULL && updateTXY) { |
3975 | LogVar **var = (LogVar**) (logInfo->y); |
3976 | int_T ny = logInfo->ny; |
3977 | int_T i; |
3978 | int yIdx; |
3979 | LogSignalPtrsType data = rtliGetLogYSignalPtrs(li); |
3980 | |
3981 | for (i = 0, yIdx = 0; i < ny; i++) { |
3982 | if (data[i] != NULL) { |
3983 | /* |
3984 | When outputs are logged in Matrix format, |
3985 | no variable-size signal logging is allowed. |
3986 | */ |
3987 | /* g1614989:Code refactoring and fix for logging issue. |
3988 | * Function pointer is now identified by using |
3989 | * Y Signal Info instead of iterating over pre-processing |
3990 | * function pointers. |
3991 | */ |
3992 | rt_preProcessAndLogData(yInfo[yIdx], var[yIdx], data[i], false); |
3993 | yIdx++; |
3994 | } |
3995 | } |
3996 | } |
3997 | } else { /* STRUCTURE_FORMAT */ |
3998 | /* states */ |
3999 | if (logInfo->x != NULL && updateTXY) { |
4000 | int_T i; |
4001 | StructLogVar *var = logInfo->x; |
4002 | LogVar *val = var->signals.values; |
4003 | int_T nsig = var->signals.numSignals; |
4004 | LogSignalPtrsType data = rtliGetLogXSignalPtrs(li); |
4005 | |
4006 | /* time */ |
4007 | if (var->logTime) { |
4008 | rt_UpdateLogVar(var->time, tPtr, false); |
4009 | } |
4010 | |
4011 | /* signals */ |
4012 | for (i = 0; i < nsig; i++) { |
4013 | /* g1614989:Code refactoring and fix for logging issue. |
4014 | * Function pointer is now identified by using |
4015 | * X Signal Info instead of iterating over pre-processing |
4016 | * function pointers. |
4017 | */ |
4018 | rt_preProcessAndLogDataWithIndex(xInfo, i, val, data[i], false); |
4019 | val = val->next; |
4020 | } |
4021 | } |
4022 | |
4023 | /* outputs */ |
4024 | if (logInfo->y != NULL && updateTXY) { |
4025 | int_T ny = logInfo->ny; |
4026 | LogSignalPtrsType data = rtliGetLogYSignalPtrs(li); |
4027 | StructLogVar **var = (StructLogVar**) (logInfo->y); |
4028 | |
4029 | if (ny == 1) { |
4030 | int_T i; |
4031 | int_T dataIdx; |
4032 | LogVar *val = var[0]->signals.values; |
4033 | int_T nsig = var[0]->signals.numSignals; |
4034 | boolean_T *isVarDims = var[0]->signals.isVarDims; |
4035 | |
4036 | /* time */ |
4037 | if (var[0]->logTime) { |
4038 | rt_UpdateLogVar(var[0]->time, tPtr, false); |
4039 | } |
4040 | |
4041 | /* signals */ |
4042 | for (i = 0, dataIdx = 0; i < nsig; i++) { |
4043 | while (data[dataIdx] == NULL) { |
4044 | ++dataIdx; |
4045 | } |
4046 | /* g1614989:Code refactoring and fix for logging issue. |
4047 | * Function pointer is now identified by using |
4048 | * Y Signal Info instead of iterating over pre-processing |
4049 | * function pointers. |
4050 | */ |
4051 | rt_preProcessAndLogDataWithIndex(yInfo, i, val, data[dataIdx], isVarDims[i]); |
4052 | dataIdx++; |
4053 | val = val->next; |
4054 | } |
4055 | } else { |
4056 | int_T i; |
4057 | int_T dataIdx; |
4058 | |
4059 | for (i = 0, dataIdx = 0; i < ny && var[i] != NULL; i++) { |
4060 | LogVar *val = var[i]->signals.values; |
4061 | boolean_T *isVarDims = var[i]->signals.isVarDims; |
4062 | |
4063 | /* time */ |
4064 | if (var[i]->logTime) { |
4065 | rt_UpdateLogVar(var[i]->time, tPtr, false); |
4066 | } |
4067 | |
4068 | /* signals */ |
4069 | while (data[dataIdx] == NULL) { |
4070 | ++dataIdx; |
4071 | } |
4072 | /* g1614989:Code refactoring and fix for logging issue. |
4073 | * Function pointer is now identified by using |
4074 | * Y Signal Info instead of iterating over pre-processing |
4075 | * function pointers. |
4076 | */ |
4077 | rt_preProcessAndLogData(yInfo[i], val, data[dataIdx], isVarDims[0]); |
4078 | dataIdx++; |
4079 | val = val->next; |
4080 | } |
4081 | } |
4082 | } |
4083 | /* final state */ |
4084 | if (logInfo->xFinal != NULL) { |
4085 | StructLogVar *xf = logInfo->xFinal; |
4086 | LogVar *val = xf->signals.values; |
4087 | int_T nsig = xf->signals.numSignals; |
4088 | int_T i; |
4089 | |
4090 | /* time */ |
4091 | if (xf->logTime) { |
4092 | rt_UpdateLogVar(xf->time, tPtr, false); |
4093 | } |
4094 | |
4095 | /* signals */ |
4096 | for (i = 0; i < nsig; i++) { |
4097 | LogSignalPtrsType data = rtliGetLogXSignalPtrs(li); |
4098 | /* g1614989:Code refactoring and fix for logging issue. |
4099 | * Function pointer is now identified by using |
4100 | * X Signal Info instead of iterating over pre-processing |
4101 | * function pointers. |
4102 | */ |
4103 | rt_preProcessAndLogDataWithIndex(xInfo, i, val, data[i], false); |
4104 | val = val->next; |
4105 | } |
4106 | } |
4107 | } |
4108 | return(NULL); |
4109 | } /* end rt_UpdateTXXFYLogVars */ |
4110 | |
4111 | |
4112 | #ifdef __cplusplus |
4113 | } |
4114 | #endif |
4115 | |
4116 | |
4117 | |
4118 | |
4119 | #ifdef __cplusplus |
4120 | extern "C" { |
4121 | #endif |
4122 | |
4123 | |
4124 | /* Function: rt_StopDataLoggingImpl ======================================= |
4125 | * Abstract: |
4126 | * Write logged data to model.mat and free memory. |
4127 | */ |
4128 | void rt_StopDataLoggingImpl(const char_T *file, RTWLogInfo *li, boolean_T isRaccel) |
4129 | { |
4130 | FILE *fptr; |
4131 | LogInfo *logInfo = (LogInfo*) rtliGetLogInfo(li); |
4132 | LogVar *var = logInfo->logVarsList; |
4133 | StructLogVar *svar = logInfo->structLogVarsList; |
4134 | /* At this time, verbose is only needed if running rapid accelerator |
4135 | * simulations. */ |
4136 | int verbose = isRaccel ? 0: 1; |
4137 | |
4138 | boolean_T emptyFile = 1; /* assume */ |
4139 | boolean_T errFlag = 0; |
4140 | const char_T *msg; |
4141 | |
4142 | /******************************* |
4143 | * Create MAT file with header * |
4144 | *******************************/ |
4145 | if ((fptr=fopen(file,"w+b")) == NULL) { |
4146 | (void)fprintf(stderr,"*** Error opening %s",file); |
4147 | goto EXIT_POINT; |
4148 | } |
4149 | if (rt_WriteMat5FileHeader(fptr)) { |
4150 | (void)fprintf(stderr,"*** Error writing to %s",file); |
4151 | goto EXIT_POINT; |
4152 | } |
4153 | |
4154 | /************************************************** |
4155 | * First log all the variables in the LogVar list * |
4156 | **************************************************/ |
4157 | while (var != NULL) { |
4158 | if ( (msg = rt_FixupLogVar(var,verbose)) != NULL ) { |
4159 | (void)fprintf(stderr,"*** Error writing %s due to: %s\n",file,msg); |
4160 | errFlag = 1; |
4161 | break; |
4162 | } |
4163 | if (var->nDataPoints > 0 || isRaccel) { |
4164 | MatItem item; |
4165 | |
4166 | item.type = matMATRIX; |
4167 | item.nbytes = 0; /* not yet known */ |
4168 | item.data = &(var->data); |
4169 | if (rt_WriteItemToMatFile(fptr, &item, MATRIX_ITEM)) { |
4170 | (void)fprintf(stderr,"*** Error writing log variable %s to " |
4171 | "file %s",var->data.name, file); |
4172 | errFlag = 1; |
4173 | break; |
4174 | } |
4175 | emptyFile = 0; |
4176 | } |
4177 | var = var->next; |
4178 | } |
4179 | /* free up some memory by destroying the log var list here */ |
4180 | rt_DestroyLogVar(logInfo->logVarsList); |
4181 | logInfo->logVarsList = NULL; |
4182 | |
4183 | /******************************************************* |
4184 | * Next log all the variables in the StructLogVar list * |
4185 | *******************************************************/ |
4186 | while (svar != NULL) { |
4187 | MatItem item; |
4188 | |
4189 | if (svar->logTime) { |
4190 | var = svar->time; |
4191 | if ( (msg = rt_FixupLogVar(var,verbose)) != NULL ) { |
4192 | (void)fprintf(stderr, "*** Error writing %s due to: %s\n", |
4193 | file, msg); |
4194 | errFlag = 1; |
4195 | break; |
4196 | } |
4197 | } |
4198 | |
4199 | var = svar->signals.values; |
4200 | while (var) { |
4201 | if ( (msg = rt_FixupLogVar(var,verbose)) != NULL ) { |
4202 | (void)fprintf(stderr, "*** Error writing %s due to: %s\n", |
4203 | file, msg); |
4204 | errFlag = 1; |
4205 | break; |
4206 | } |
4207 | var = var->next; |
4208 | } |
4209 | |
4210 | item.type = matMATRIX; |
4211 | item.nbytes = 0; /* not yet known */ |
4212 | item.data = svar; |
4213 | |
4214 | if (rt_WriteItemToMatFile(fptr, &item, STRUCT_LOG_VAR_ITEM)) { |
4215 | (void)fprintf(stderr,"*** Error writing structure log variable " |
4216 | "%s to file %s",svar->name, file); |
4217 | errFlag = 1; |
4218 | break; |
4219 | } |
4220 | emptyFile = 0; |
4221 | |
4222 | svar = svar->next; |
4223 | } |
4224 | |
4225 | /****************** |
4226 | * Close the file * |
4227 | ******************/ |
4228 | (void)fclose(fptr); |
4229 | if (emptyFile || errFlag) { |
4230 | (void)remove(file); |
4231 | } else { |
4232 | if( verbose ) { |
4233 | (void)printf("** created %s **\n\n", file); |
4234 | } |
4235 | } |
4236 | |
4237 | EXIT_POINT: |
4238 | |
4239 | /**************** |
4240 | * free logInfo * |
4241 | ****************/ |
4242 | rt_DestroyLogVar(logInfo->logVarsList); |
4243 | logInfo->logVarsList = NULL; |
4244 | rt_DestroyStructLogVar(logInfo->structLogVarsList); |
4245 | logInfo->structLogVarsList = NULL; |
4246 | FREE(logInfo->y); |
4247 | logInfo->y = NULL; |
4248 | FREE(logInfo); |
4249 | rtliSetLogInfo(li,NULL); |
4250 | |
4251 | } /* end rt_StopDataLoggingImpl */ |
4252 | |
4253 | |
4254 | #ifdef __cplusplus |
4255 | } |
4256 | #endif |
4257 | |
4258 | |
4259 | #ifdef __cplusplus |
4260 | extern "C" { |
4261 | #endif |
4262 | |
4263 | |
4264 | /* Function: rt_StopDataLogging ================================================ |
4265 | * Abstract: |
4266 | * Write logged data to model.mat and free memory. |
4267 | */ |
4268 | void rt_StopDataLogging(const char_T *file, RTWLogInfo *li) |
4269 | { |
4270 | rt_StopDataLoggingImpl(file,li,false); |
4271 | |
4272 | } /* end rt_StopDataLogging */ |
4273 | |
4274 | |
4275 | #ifdef __cplusplus |
4276 | } |
4277 | #endif |
4278 | |
4279 | #else /*!defined(MAT_FILE) || (defined(MAT_FILE) && MAT_FILE == 1)*/ |
4280 | |
4281 | #define rt_StartDataLogging(li, finalTime, stepSize, errStatus) NULL /* do nothing */ |
4282 | #define rt_UpdateTXYLogVars(li, tPtr) NULL /* do nothing */ |
4283 | #define rt_StopDataLogging(file, li); /* do nothing */ |
4284 | |
4285 | #endif /*!defined(MAT_FILE) || (defined(MAT_FILE) && MAT_FILE == 1)*/ |
4286 | |
4287 | |
4288 | |
4289 | /* [eof] rt_logging.c */ |
4290 | |
4291 | /* LocalWords: Tfinal MAXNAM nonfinite DType PWS RSim Fixup logvar DDEFAULT th |
4292 | * LocalWords: curr Realloc realloc inp biglong vijay ldexp TXY eof XFinal th |
4293 | * LocalWords: TXXFY NULL typedefs ret polyspace NUL |
4294 | */ |
4295 | |