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