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