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
84typedef 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
97typedef struct MatItem_tag {
98 int32_T type;
99 uint32_T nbytes;
100 const void *data;
101} MatItem;
102
103typedef enum {
104 DATA_ITEM,
105 MATRIX_ITEM,
106 STRUCT_LOG_VAR_ITEM,
107 SIGNALS_STRUCT_ITEM
108} ItemDataKind;
109
110/*===========*
111 * Constants *
112 *===========*/
113
114static 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 */
136static 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
141static 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
149static 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 */
174static 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;
180static 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
188extern real_T rtInf; /* declared by rt_nonfinite.c */
189extern real_T rtNaN;
190extern 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 */
200static 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 */
242static 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 */
302static 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 */
331static 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 */
393static 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
469extern "C" {
470#endif
471
472
473/* Function: rt_GetMxIdFromDTypeIdForRSim ======================================
474 * Abstract:
475 * Get the mx???_CLASS given the simulink builtin data type id.
476 */
477mxClassID 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
512extern "C" {
513#endif
514
515
516/* Function: rt_GetMxIdFromDTypeId =============================================
517 * Abstract:
518 * Get the mx???_CLASS given the simulink builtin data type id.
519 */
520mxClassID 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 */
556static 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 */
609static 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 */
625static 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 */
1112static 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 */
1163static 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 */
1200static 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 */
1423static 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
1460static 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 */
1482static 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 */
1512static 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 */
1548static 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 */
2101static 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 */
2246static 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 */
2402static 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
2534const 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 */
2544const 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
2651extern "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 */
2663LogVar *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
3028extern "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 */
3040LogVar *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
3096extern "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 */
3108StructLogVar *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
3146extern "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 */
3160const 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
3304extern "C" {
3305#endif
3306
3307
3308/* Function: rt_StartDataLogging ===============================================
3309 * Abstract:
3310 */
3311const 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
3332extern "C" {
3333#endif
3334
3335
3336/* Function: rt_UpdateLogVar ===================================================
3337 * Abstract:
3338 * Called to log data for a log variable.
3339 */
3340void 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, &currentSigDims, 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
3819extern "C" {
3820#endif
3821
3822
3823/* Function: rt_UpdateStructLogVar =============================================
3824 * Abstract:
3825 * Called to log data for a structure log variable.
3826 */
3827void 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
3863extern "C" {
3864#endif
3865
3866/*
3867 * g1614989:Refactoring this function to accept number of elements
3868 * instead of accepting signalInfo and index.
3869 */
3870void* rt_getTempMemory(LogVar* var, int_T numEls);
3871
3872void* 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*/
3892void rt_preProcessAndLogDataWithIndex(const RTWLogSignalInfo *signalInfo, int_T idx, LogVar* val, const void * data, boolean_T isVarDims);
3893
3894void 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
3922void rt_preProcessAndLogData(RTWLogSignalInfo signalInfo, LogVar* val, const void * data, boolean_T isVarDims);
3923
3924void 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 */
3933const 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 */
3942const 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
4122extern "C" {
4123#endif
4124
4125
4126/* Function: rt_StopDataLoggingImpl =======================================
4127 * Abstract:
4128 * Write logged data to model.mat and free memory.
4129 */
4130void 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
4262extern "C" {
4263#endif
4264
4265
4266/* Function: rt_StopDataLogging ================================================
4267 * Abstract:
4268 * Write logged data to model.mat and free memory.
4269 */
4270void 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