1/* Copyright 2003-2019 The MathWorks, Inc. */
2
3/**
4 * Utility functions to traverse and access information from ModelMappingInfo
5 *
6 */
7
8#ifdef SL_INTERNAL
9
10# include "version.h"
11# include "util.h"
12# include "simstruct/simstruc_types.h"
13# include "simulinkcoder_capi/rtw_modelmap.h"
14
15#else
16
17# include <stdlib.h>
18# include <assert.h>
19
20# define utFree(arg) if (arg) free(arg)
21# define utMalloc(arg) malloc(arg)
22# define utAssert(exp) assert(exp)
23
24/*
25 * UNUSED_PARAMETER(x)
26 * Used to specify that a function parameter (argument) is required but not
27 * accessed by the function body.
28 */
29#ifndef UNUSED_PARAMETER
30# if defined(__LCC__)
31# define UNUSED_PARAMETER(x) /* do nothing */
32# else
33/*
34 * This is the semi-ANSI standard way of indicating that a
35 * unused function parameter is required.
36 */
37# define UNUSED_PARAMETER(x) (void) (x)
38# endif
39#endif
40
41# include "builtin_typeid_types.h"
42# include "rtwtypes.h"
43# include "rtw_modelmap.h"
44
45#endif
46
47#include <string.h>
48
49/* Logical definitions */
50#if (!defined(__cplusplus))
51# ifndef false
52# define false (0U)
53# endif
54# ifndef true
55# define true (1U)
56# endif
57#endif
58
59static const char_T* rtwCAPI_mallocError = "Memory Allocation Error";
60
61/** Function: rtwCAPI_EncodePath ===============================================
62 * Abstract:
63 * Escape all '|' characters in bpath. For examples 'aaa|b' will become
64 * 'aaa~|b'. The caller is responsible for freeing the returned string
65 *
66 *
67 * NOTE: returned string can be NULL in two cases:
68 * (1) string passed in was NULL
69 * (2) a memory allocation error occurred
70 * In the second case, the caller need to report the error
71 */
72char* rtwCAPI_EncodePath(const char* path)
73{
74 char* encodedPath = NULL;
75 size_t pathLen = (path==NULL) ? 0:strlen(path) + 1;
76 size_t encodedPathLen = pathLen;
77 unsigned i;
78 unsigned j = 0;
79
80 if (path == NULL) return NULL;
81
82 for (i = 0; i < pathLen; ++i) {
83 if (path[i] == '|' || path[i] == '~') ++encodedPathLen;
84 }
85
86 encodedPath = (char_T*)utMalloc(encodedPathLen*sizeof(char_T));
87 if (encodedPath == NULL) return encodedPath;
88
89 for (i = 0; i < pathLen; ++i) {
90 char ch = path[i];
91 if (ch == '~' || ch == '|') encodedPath[j++] = '~';
92 encodedPath[j++] = ch;
93 }
94 utAssert(j == encodedPathLen);
95 utAssert(encodedPath[j-1] == '\0');
96
97 return encodedPath;
98
99} /* rtwCAPI_EncodePath */
100
101/** Function: rtwCAPI_GetSigAddrFromMap ========================================
102 *
103 */
104void rtwCAPI_GetSigAddrFromMap(uint8_T isPointer,
105 int_T* sigComplexity,
106 int_T* sigDataType,
107 void** sigDataAddr,
108 int_T* sigIdx,
109 uint_T mapIdx,
110 void** dataAddrMap)
111{
112 if (isPointer) {
113 /* Dereference pointer and cache the address */
114
115 /* Imported Pointers cannot be complex - Assert */
116 utAssert(sigComplexity[*sigIdx] != 1);
117 UNUSED_PARAMETER(sigComplexity);
118
119 /* Check for data type and dereference accordingly */
120 switch (sigDataType[*sigIdx]) {
121 case SS_DOUBLE:
122 sigDataAddr[*sigIdx] = \
123 (void*) *((real_T **) dataAddrMap[mapIdx]);
124 break;
125 case SS_SINGLE:
126 sigDataAddr[*sigIdx] = \
127 (void*) *((real32_T **) dataAddrMap[mapIdx]);
128 break;
129 case SS_UINT32:
130 sigDataAddr[*sigIdx] = \
131 (void*) *((uint32_T **) dataAddrMap[mapIdx]);
132 break;
133 case SS_INT32:
134 sigDataAddr[*sigIdx] = \
135 (void*) *((int32_T **) dataAddrMap[mapIdx]);
136 break;
137 case SS_UINT16:
138 sigDataAddr[*sigIdx] = \
139 (void*) *((uint16_T **) dataAddrMap[mapIdx]);
140 break;
141 case SS_INT16:
142 sigDataAddr[*sigIdx] = \
143 (void*) *((int16_T **) dataAddrMap[mapIdx]);
144 break;
145 case SS_UINT8:
146 sigDataAddr[*sigIdx] = \
147 (void*) *((uint8_T **) dataAddrMap[mapIdx]);
148 break;
149 case SS_INT8:
150 sigDataAddr[*sigIdx] = \
151 (void*) *((int8_T **) dataAddrMap[mapIdx]);
152 break;
153 case SS_BOOLEAN:
154 sigDataAddr[*sigIdx] = \
155 (void*) *((boolean_T **) dataAddrMap[mapIdx]);
156 break;
157 default:
158 sigDataAddr[*sigIdx] = \
159 (void*) *((real_T **) dataAddrMap[mapIdx]);
160 break;
161 } /* end switch */
162 } else {
163 /* if Data is not a pointer store the address directly */
164 sigDataAddr[*sigIdx] = dataAddrMap[mapIdx];
165 }
166
167} /* rtwCAPI_GetSigAddrFromMap */
168
169
170/** Function: rtwCAPI_HasStates ================================================
171 *
172 */
173boolean_T rtwCAPI_HasStates(const rtwCAPI_ModelMappingInfo* mmi)
174{
175 int_T i;
176 int_T nCMMI;
177
178 if (mmi == NULL) return(0U);
179
180 if (rtwCAPI_GetNumStates(mmi) > 0) return(1U);
181
182 nCMMI = rtwCAPI_GetChildMMIArrayLen(mmi);
183 for (i = 0; i < nCMMI; ++i) {
184 if (rtwCAPI_HasStates(rtwCAPI_GetChildMMI(mmi,i))) return(1U);
185 }
186 return(0U);
187
188} /* rtwCAPI_HasStates */
189
190
191
192/** Function: rtwCAPI_GetNumStateRecords =======================================
193 *
194 */
195int_T rtwCAPI_GetNumStateRecords(const rtwCAPI_ModelMappingInfo* mmi)
196{
197 int_T i;
198 int_T nRecs;
199 int_T nCMMI;
200
201 if (mmi == NULL) return(0);
202
203 nRecs = rtwCAPI_GetNumStates(mmi);
204
205 nCMMI = rtwCAPI_GetChildMMIArrayLen(mmi);
206 for (i = 0; i < nCMMI; ++i) {
207 const rtwCAPI_ModelMappingInfo* cMMI = rtwCAPI_GetChildMMI(mmi,i);
208 nRecs += rtwCAPI_GetNumStateRecords(cMMI);
209 }
210 return(nRecs);
211
212} /* rtwCAPI_GetNumStateRecords */
213
214
215/** Function: rtwCAPI_GetNumStateRecordsForRTWLogging ==========================
216 *
217 */
218int_T rtwCAPI_GetNumStateRecordsForRTWLogging(const rtwCAPI_ModelMappingInfo* mmi)
219{
220 int_T i;
221 int_T nRecs = 0;
222 int_T nStates;
223 int_T nCMMI;
224 const rtwCAPI_States *states;
225 const rtwCAPI_DataTypeMap* dataTypeMap;
226
227 if (mmi == NULL) return(0);
228
229 nStates = rtwCAPI_GetNumStates(mmi);
230 states = rtwCAPI_GetStates(mmi);
231 dataTypeMap = rtwCAPI_GetDataTypeMap(mmi);
232
233 for (i = 0; i < nStates; ++i) {
234 if (rtwCAPI_CanLogStateToMATFile(dataTypeMap, states, i)) {
235 ++nRecs;
236 }
237 }
238
239 nCMMI = rtwCAPI_GetChildMMIArrayLen(mmi);
240 for (i = 0; i < nCMMI; ++i) {
241 const rtwCAPI_ModelMappingInfo* cMMI = rtwCAPI_GetChildMMI(mmi,i);
242 nRecs += rtwCAPI_GetNumStateRecordsForRTWLogging(cMMI);
243 }
244
245 return(nRecs);
246
247} /* rtwCAPI_GetNumStateRecordsForRTWLogging */
248
249
250/** Function: rtwCAPI_GetNumContStateRecords ===================================
251 *
252 */
253int_T rtwCAPI_GetNumContStateRecords(const rtwCAPI_ModelMappingInfo* mmi)
254{
255 int_T i;
256 int_T nRecs;
257 int_T nCMMI;
258 int_T nCStateRecs;
259 const rtwCAPI_States* states;
260 const rtwCAPI_DataTypeMap* dataTypeMap;
261
262 if (mmi == NULL) return 0;
263
264 nCStateRecs = 0;
265 states = rtwCAPI_GetStates(mmi);
266 dataTypeMap = rtwCAPI_GetDataTypeMap(mmi);
267
268 nRecs = rtwCAPI_GetNumStates(mmi);
269 for (i = 0; i < nRecs; i++) {
270 if (rtwCAPI_IsAContinuousState(states,i)) {
271 ++nCStateRecs;
272
273 /* All continuous states should be able to be logged to MAT-File
274 * so we do not need to skip any states here. */
275 utAssert(rtwCAPI_CanLogStateToMATFile(dataTypeMap, states, i));
276 }
277 }
278
279 nCMMI = rtwCAPI_GetChildMMIArrayLen(mmi);
280 for (i = 0; i < nCMMI; ++i) {
281 const rtwCAPI_ModelMappingInfo* cMMI = rtwCAPI_GetChildMMI(mmi,i);
282 nCStateRecs += rtwCAPI_GetNumContStateRecords(cMMI);
283 }
284 return nCStateRecs;
285
286} /* rtwCAPI_GetNumContStateRecords */
287
288
289/** Function: rtwCAPI_FreeFullPaths ============================================
290 *
291 */
292void rtwCAPI_FreeFullPaths(rtwCAPI_ModelMappingInfo* mmi)
293{
294 int_T i;
295 int_T nCMMI;
296 char_T* fullPath;
297
298 if (mmi == NULL) return;
299
300 fullPath = rtwCAPI_GetFullPath(mmi);
301 utAssert(fullPath != NULL);
302 utFree(fullPath);
303 rtwCAPI_SetFullPath(*mmi, NULL);
304
305 nCMMI = rtwCAPI_GetChildMMIArrayLen(mmi);
306 for (i = 0; i < nCMMI; ++i) {
307 rtwCAPI_ModelMappingInfo* cMMI = rtwCAPI_GetChildMMI(mmi,i);
308 rtwCAPI_FreeFullPaths(cMMI);
309 }
310
311} /* rtwCAPI_FreeFullPaths */
312
313
314/** Function: rtwCAPI_UpdateFullPaths =========================================*
315 *
316 */
317const char_T* rtwCAPI_UpdateFullPaths(rtwCAPI_ModelMappingInfo* mmi,
318 const char_T* path,
319 boolean_T isCalledFromTopModel)
320{
321 int_T i;
322 int_T nCMMI;
323 size_t pathLen;
324 char_T* mmiPath;
325 size_t mmiPathLen;
326 char_T* relMMIPath;
327 size_t relMMIPathLen;
328
329 if (mmi == NULL) return NULL;
330
331 utAssert(path != NULL);
332 utAssert( rtwCAPI_GetFullPath(mmi) == NULL );
333
334 pathLen = strlen(path)+1;
335
336 if (isCalledFromTopModel) {
337 /* If called from top model - FullPath is same as path */
338 mmiPath = (char_T*)utMalloc(pathLen*sizeof(char_T));
339 (void)memcpy(mmiPath, path, pathLen*sizeof(char_T));
340 }
341 else {
342 relMMIPath = rtwCAPI_EncodePath(rtwCAPI_GetPath(mmi));
343 if ( (relMMIPath== NULL) && (rtwCAPI_GetPath(mmi) != NULL)) {
344 return rtwCAPI_mallocError;
345 }
346 relMMIPathLen = relMMIPath ? (strlen(relMMIPath) + 1) : 0;
347
348 mmiPathLen = pathLen + relMMIPathLen;
349
350 mmiPath = (char_T*)utMalloc(mmiPathLen*sizeof(char_T));
351 if (mmiPath == NULL) return rtwCAPI_mallocError;
352 (void)memcpy(mmiPath, path, pathLen*sizeof(char_T));
353 utAssert(mmiPath[pathLen-1] == '\0');
354
355 if (relMMIPath) {
356 /* mmiPath = path + | + relMMIPath + '\0' */
357 mmiPath[pathLen-1] = '|';
358 (void)memcpy(&(mmiPath[pathLen]),
359 relMMIPath, relMMIPathLen*sizeof(char_T));
360 utAssert(mmiPath[mmiPathLen-1] == '\0');
361 utFree(relMMIPath);
362 }
363 }
364 rtwCAPI_SetFullPath(*mmi, mmiPath);
365
366 nCMMI = rtwCAPI_GetChildMMIArrayLen(mmi);
367 for (i = 0; i < nCMMI; ++i) {
368 rtwCAPI_ModelMappingInfo* cMMI = rtwCAPI_GetChildMMI(mmi,i);
369 const char_T* errstr = rtwCAPI_UpdateFullPaths(cMMI, mmiPath, 0);
370 if (errstr != NULL) return errstr;
371 }
372 return NULL;
373
374} /* rtwCAPI_UpdateFullPaths */
375
376
377/** Function: rtwCAPI_GetFullStateBlockPath ===================================
378 *
379 */
380char* rtwCAPI_GetFullStateBlockPath(const char* stateBlockPath,
381 const char* mmiPath,
382 size_t mmiPathLen,
383 boolean_T crossingModel)
384{
385 char_T* blockPath = NULL;
386 char_T* fullStateBlockPath = NULL;
387 size_t fullStateBlockPathLen;
388
389 if (stateBlockPath == NULL) goto EXIT_POINT;
390
391 /* fullStateBlockPath = mmiPath + | + blockPath + '\0' */
392 /* If crossing a model boundary encode, otherwise do not */
393
394 if (crossingModel) {
395 blockPath = rtwCAPI_EncodePath(stateBlockPath);
396 if (blockPath == NULL) goto EXIT_POINT;
397 } else {
398 size_t len = strlen(stateBlockPath)+1;
399 blockPath = (char*)utMalloc(len*sizeof(char));
400 if (blockPath == NULL) goto EXIT_POINT;
401 (void)strcpy(blockPath,stateBlockPath);
402 }
403 utAssert(blockPath != NULL);
404 fullStateBlockPathLen = ( (mmiPath==NULL) ?
405 strlen(blockPath) + 1 :
406 mmiPathLen + strlen(blockPath) + 2 );
407 fullStateBlockPath = (char*)utMalloc(fullStateBlockPathLen*sizeof(char));
408 if (fullStateBlockPath == NULL) goto EXIT_POINT;
409
410 if (mmiPath != NULL) {
411 (void)strcpy(fullStateBlockPath, mmiPath);
412 fullStateBlockPath[mmiPathLen] = '|';
413 fullStateBlockPath[mmiPathLen+1] = '\0';
414 (void)strcat(fullStateBlockPath, blockPath);
415 } else {
416 (void)strcpy(fullStateBlockPath, blockPath);
417 fullStateBlockPath[fullStateBlockPathLen-1] = '\0';
418 }
419 utAssert(fullStateBlockPath[fullStateBlockPathLen-1] == '\0');
420
421 EXIT_POINT:
422 utFree(blockPath);
423 return fullStateBlockPath; /* caller is responsible for free */
424}
425
426uint_T rtwCAPI_GetStateWidth(const rtwCAPI_DimensionMap* dimMap,
427 const uint_T* dimArray,
428 const rtwCAPI_States* states,
429 uint_T iState)
430{
431 uint_T mapIdx = rtwCAPI_GetStateDimensionIdx(states, iState);
432 uint_T numDims = rtwCAPI_GetNumDims(dimMap,mapIdx);
433 uint_T width = 1;
434 uint_T i = 0;
435 utAssert( numDims > 0 );
436 mapIdx = rtwCAPI_GetDimArrayIndex(dimMap, mapIdx);
437 for (i = 0; i < numDims; i++) {
438 width *= dimArray[mapIdx+i];
439 }
440 return width;
441}
442
443
444
445/** Function: rtwCAPI_GetStateRecordInfo =======================================
446 *
447 */
448const char_T* rtwCAPI_GetStateRecordInfo(const rtwCAPI_ModelMappingInfo* mmi,
449 const char_T** sigBlockName,
450 const char_T** sigLabel,
451 const char_T** sigName,
452 int_T* sigWidth,
453 int_T* sigDataType,
454 int_T* logDataType,
455 int_T* sigComplexity,
456 void** sigDataAddr,
457 RTWLoggingFcnPtr* RTWLoggingPtrs,
458 boolean_T* sigCrossMdlRef,
459 boolean_T* sigInProtectedMdl,
460 const char_T** sigPathAlias,
461 real_T* sigSampleTime,
462 int_T* sigHierInfoIdx,
463 uint_T* sigFlatElemIdx,
464 const rtwCAPI_ModelMappingInfo** sigMMI,
465 int_T* sigIdx,
466 boolean_T crossingModel,
467 boolean_T isInProtectedMdl,
468 real_T* contStateDeriv,
469 boolean_T rtwLogging)
470{
471 int_T i;
472 int_T nCMMI;
473 int_T nStates;
474 const char_T* mmiPath;
475 size_t mmiPathLen;
476 const rtwCAPI_States* states;
477 const rtwCAPI_DimensionMap* dimMap;
478 const uint_T* dimArray;
479 const rtwCAPI_DataTypeMap* dataTypeMap;
480 void** dataAddrMap;
481 RTWLoggingFcnPtr* RTWLoggingPtrsMap;
482 const char_T* errstr = NULL;
483 uint8_T isPointer = 0;
484
485 if (mmi == NULL) goto EXIT_POINT;
486 isInProtectedMdl = isInProtectedMdl || rtwCAPI_IsProtectedModel(mmi);
487 nCMMI = rtwCAPI_GetChildMMIArrayLen(mmi);
488 for (i = 0; i < nCMMI; ++i) {
489 rtwCAPI_ModelMappingInfo* cMMI = rtwCAPI_GetChildMMI(mmi,i);
490 real_T* childContStateDeriv = NULL;
491
492 if (cMMI == NULL) continue;
493
494 if (contStateDeriv) {
495 int idx;
496
497 idx = rtwCAPI_MMIGetContStateStartIndex(cMMI);
498 if(idx == -1) continue;
499
500 childContStateDeriv = &contStateDeriv[idx];
501 }
502 errstr = rtwCAPI_GetStateRecordInfo(cMMI,
503 sigBlockName,
504 sigLabel,
505 sigName,
506 sigWidth,
507 sigDataType,
508 logDataType,
509 sigComplexity,
510 sigDataAddr,
511 RTWLoggingPtrs,
512 sigCrossMdlRef,
513 sigInProtectedMdl,
514 sigPathAlias,
515 sigSampleTime,
516 sigHierInfoIdx,
517 sigFlatElemIdx,
518 sigMMI,
519 sigIdx,
520 0x1, /* true, */
521 isInProtectedMdl,
522 childContStateDeriv,
523 rtwLogging);
524 if (errstr != NULL) goto EXIT_POINT;
525 }
526
527 nStates = rtwCAPI_GetNumStates(mmi);
528 if (nStates < 1) goto EXIT_POINT;
529
530 mmiPath = rtwCAPI_GetFullPath(mmi);
531 mmiPathLen = (mmiPath==NULL)? 0 : strlen(mmiPath);
532 states = rtwCAPI_GetStates(mmi);
533 dimMap = rtwCAPI_GetDimensionMap(mmi);
534 dimArray = rtwCAPI_GetDimensionArray(mmi);
535 dataTypeMap = rtwCAPI_GetDataTypeMap(mmi);
536 dataAddrMap = rtwCAPI_GetDataAddressMap(mmi);
537 RTWLoggingPtrsMap = rtwCAPI_GetRTWLoggingPtrsMap(mmi);
538
539 for (i = 0; i < nStates; ++i) {
540 uint_T mapIdx;
541
542 /* If collecting continuous states, skip non-continuous states */
543 if (contStateDeriv && !rtwCAPI_IsAContinuousState(states,i)) continue;
544
545 /* For RTW logging, skip states that cannot be logged to MAT-File. */
546 if ((rtwLogging) &&
547 (rtwCAPI_CanLogStateToMATFile(dataTypeMap, states, i) == false)) continue;
548
549 /* BlockPath (caller is responsible for free) */
550 sigBlockName[*sigIdx] =
551 rtwCAPI_GetFullStateBlockPath(rtwCAPI_GetStateBlockPath(states,i),
552 mmiPath, mmiPathLen, crossingModel);
553 if (sigBlockName[*sigIdx] == NULL) {
554 errstr = rtwCAPI_mallocError;
555 goto EXIT_POINT;
556 }
557
558 /* Label */
559 if (rtwCAPI_IsAContinuousState(states,i)){
560 sigLabel[*sigIdx] = "CSTATE";
561 } else {
562 sigLabel[*sigIdx] = "DSTATE";
563 }
564 sigName[*sigIdx] = rtwCAPI_GetStateName(states, i);
565
566 /* Width */
567 sigWidth[*sigIdx] = rtwCAPI_GetStateWidth(dimMap, dimArray, states, i);
568
569 /* DataType and logDataType */
570 mapIdx = rtwCAPI_GetStateDataTypeIdx(states, i);
571 sigDataType[*sigIdx] = rtwCAPI_GetDataTypeSLId(dataTypeMap, mapIdx);
572 /* this mimics code in simulink.dll:DtGetDataTypeLoggingId() */
573 if (logDataType) {
574 switch (sigDataType[*sigIdx]) {
575 case SS_DOUBLE:
576 case SS_SINGLE:
577 case SS_INT8:
578 case SS_UINT8:
579 case SS_INT16:
580 case SS_UINT16:
581 case SS_INT32:
582 case SS_UINT32:
583 case SS_BOOLEAN:
584 logDataType[*sigIdx] = sigDataType[*sigIdx];
585 break;
586 case SS_ENUM_TYPE:
587 logDataType[*sigIdx] = SS_INT32;
588 break;
589 default:
590 logDataType[*sigIdx] = SS_DOUBLE;
591 break;
592 }
593 }
594
595 /* Complexity */
596 sigComplexity[*sigIdx] = rtwCAPI_GetDataIsComplex(dataTypeMap, mapIdx);
597
598 /* Data Access - Pointer or Direct*/
599 isPointer = ((uint8_T)rtwCAPI_GetDataIsPointer(dataTypeMap, mapIdx));
600
601 /* Address */
602 if (contStateDeriv) {
603 int_T csvIdx = rtwCAPI_GetContStateStartIndex(states,i);
604 utAssert(csvIdx >= 0);
605 sigDataAddr[*sigIdx] = &contStateDeriv[csvIdx];
606 } else {
607 mapIdx = rtwCAPI_GetStateAddrIdx(states,i);
608 rtwCAPI_GetSigAddrFromMap(isPointer, sigComplexity, sigDataType,
609 sigDataAddr, sigIdx, mapIdx, dataAddrMap);
610 }
611
612 /* Logging function pointer */
613 if (RTWLoggingPtrs) {
614 if (contStateDeriv || !RTWLoggingPtrsMap) {
615 RTWLoggingPtrs[*sigIdx] = NULL;
616 }
617 else {
618 mapIdx = rtwCAPI_GetStateAddrIdx(states, i);
619 RTWLoggingPtrs[*sigIdx] = RTWLoggingPtrsMap[mapIdx];
620 }
621 }
622
623 /* CrossingModelBoundary */
624 sigCrossMdlRef[*sigIdx] = crossingModel;
625
626 if (sigInProtectedMdl)
627 {
628 sigInProtectedMdl[*sigIdx] = isInProtectedMdl;
629 }
630
631 if (sigPathAlias &&
632 rtwCAPI_GetStatePathAlias(states,i) != NULL &&
633 rtwCAPI_GetStatePathAlias(states,i)[0] != '\0') {
634 sigPathAlias[*sigIdx] =
635 rtwCAPI_GetFullStateBlockPath(rtwCAPI_GetStatePathAlias(states,i),
636 mmiPath, mmiPathLen, crossingModel);
637 }
638
639 /* Sample Time */
640 if (sigSampleTime) {
641 const rtwCAPI_SampleTimeMap* tsMap = rtwCAPI_GetSampleTimeMap(mmi);
642 int_T TID;
643 mapIdx = rtwCAPI_GetStateSampleTimeIdx(states, i);
644 TID = rtwCAPI_GetSampleTimeTID(tsMap, mapIdx);
645 if (TID >= 0) {
646 sigSampleTime[2*(*sigIdx)] =
647 *((const real_T*)rtwCAPI_GetSamplePeriodPtr(tsMap,mapIdx));
648 sigSampleTime[2*(*sigIdx)+1] =
649 *((const real_T*)rtwCAPI_GetSampleOffsetPtr(tsMap,mapIdx));
650 } else { /* triggered */
651 utAssert(TID==-1);
652 sigSampleTime[2*(*sigIdx)] = -1.0;
653 sigSampleTime[2*(*sigIdx)+1] = -1.0;
654 }
655 }
656
657 /* HierInfoIdx and FlatElemIdx */
658 if (sigHierInfoIdx && sigFlatElemIdx)
659 {
660 sigHierInfoIdx[*sigIdx] = rtwCAPI_GetStateHierInfoIdx(states, i);
661 sigFlatElemIdx[*sigIdx] = rtwCAPI_GetStateFlatElemIdx(states, i);
662 }
663
664 /* MMI for each state */
665 if (sigMMI)
666 {
667 sigMMI[*sigIdx] = mmi;
668 }
669
670 ++(*sigIdx);
671 }
672
673 EXIT_POINT:
674 return(errstr);
675
676} /* rtwCAPI_GetStateRecordInfo */
677
678/* Signal Logging functions */
679
680/** Function: rtwCAPI_GetNumSigLogRecords ======================================
681 *
682 */
683int_T rtwCAPI_GetNumSigLogRecords(const rtwCAPI_ModelMappingInfo* mmi)
684{
685 int_T i;
686 int_T nRecs;
687 int_T nCMMI;
688
689 if (mmi == NULL) return(0);
690
691 nRecs = rtwCAPI_GetNumSignals(mmi);
692
693 nCMMI = rtwCAPI_GetChildMMIArrayLen(mmi);
694 for (i = 0; i < nCMMI; ++i) {
695 const rtwCAPI_ModelMappingInfo* cMMI = rtwCAPI_GetChildMMI(mmi,i);
696 nRecs += rtwCAPI_GetNumSigLogRecords(cMMI);
697 }
698 return(nRecs);
699
700} /* rtwCAPI_GetNumSigLogRecords */
701
702
703/** Function: rtwCAPI_GetNumSigLogRecordsForRTWLogging =========================
704 *
705 */
706int_T rtwCAPI_GetNumSigLogRecordsForRTWLogging(const rtwCAPI_ModelMappingInfo* mmi)
707{
708 int_T i;
709 int_T nRecs = 0;
710 int_T nSignals = 0;
711 int_T nCMMI;
712 const rtwCAPI_Signals *signals = NULL;
713 const rtwCAPI_DataTypeMap* dataTypeMap;
714
715 if (mmi == NULL) return(0);
716
717 nSignals = rtwCAPI_GetNumSignals(mmi);
718 signals = rtwCAPI_GetSignals(mmi);
719 dataTypeMap = rtwCAPI_GetDataTypeMap(mmi);
720
721 for (i = 0; i < nSignals; ++i) {
722 if (rtwCAPI_CanLogSignalToMATFile(dataTypeMap, signals, i)) {
723 ++nRecs;
724 }
725 }
726
727 nCMMI = rtwCAPI_GetChildMMIArrayLen(mmi);
728 for (i = 0; i < nCMMI; ++i) {
729 const rtwCAPI_ModelMappingInfo* cMMI = rtwCAPI_GetChildMMI(mmi,i);
730 nRecs += rtwCAPI_GetNumSigLogRecordsForRTWLogging(cMMI);
731 }
732
733 return(nRecs);
734
735} /* rtwCAPI_GetNumSigLogRecords */
736
737
738/** Function: rtwCAPI_GetSigLogRecordInfo ======================================
739 *
740 */
741const char_T* rtwCAPI_GetSigLogRecordInfo(const rtwCAPI_ModelMappingInfo* mmi,
742 const char_T** sigBlockName,
743 const char_T** sigLabel,
744 int_T* sigWidth,
745 int_T* sigDataType,
746 int_T* logDataType,
747 int_T* sigComplexity,
748 void** sigDataAddr,
749 boolean_T* sigCrossMdlRef,
750 int_T* sigIdx,
751 boolean_T crossingModel,
752 boolean_T rtwLogging)
753{
754 int_T i;
755 int_T nCMMI;
756 int_T nSignals;
757 const char_T* mmiPath;
758 size_t mmiPathLen;
759 const rtwCAPI_Signals* signals;
760 const rtwCAPI_DimensionMap* dimMap;
761 const uint_T* dimArray;
762 const rtwCAPI_DataTypeMap* dataTypeMap;
763 void** dataAddrMap;
764 const char_T* errstr = NULL;
765 uint8_T isPointer = 0;
766 char* blockPath = NULL;
767
768 if (mmi == NULL) goto EXIT_POINT;
769
770 nCMMI = rtwCAPI_GetChildMMIArrayLen(mmi);
771 for (i = 0; i < nCMMI; ++i) {
772 rtwCAPI_ModelMappingInfo* cMMI = rtwCAPI_GetChildMMI(mmi,i);
773
774 errstr = rtwCAPI_GetSigLogRecordInfo(cMMI,
775 sigBlockName,
776 sigLabel,
777 sigWidth,
778 sigDataType,
779 logDataType,
780 sigComplexity,
781 sigDataAddr,
782 sigCrossMdlRef,
783 sigIdx,
784 true,
785 rtwLogging);
786 if (errstr != NULL) goto EXIT_POINT;
787 }
788
789 nSignals = rtwCAPI_GetNumSignals(mmi);
790 if (nSignals < 1) goto EXIT_POINT;
791
792 mmiPath = rtwCAPI_GetFullPath(mmi);
793 mmiPathLen = (mmiPath==NULL)? 0 : strlen(mmiPath);
794 signals = rtwCAPI_GetSignals(mmi);
795 dimMap = rtwCAPI_GetDimensionMap(mmi);
796 dimArray = rtwCAPI_GetDimensionArray(mmi);
797 dataTypeMap = rtwCAPI_GetDataTypeMap(mmi);
798 dataAddrMap = rtwCAPI_GetDataAddressMap(mmi);
799
800 for (i = 0; i < nSignals; ++i) {
801 uint_T mapIdx;
802 size_t sigPathLen;
803 char* sigPath;
804
805 /* For RTW logging, skip states that cannot be logged to MAT-File. */
806 if ((rtwLogging) &&
807 (rtwCAPI_CanLogSignalToMATFile(dataTypeMap, signals, i) == false)) continue;
808
809 /* sigBlockPath = mmiPath + | + BlockPath + '\0' */
810 /* If crossing a model boundary encode, otherwise do not */
811
812 if (crossingModel) {
813 blockPath = rtwCAPI_EncodePath(rtwCAPI_GetSignalBlockPath(signals, i));
814 if ( (blockPath == NULL) &&
815 (rtwCAPI_GetSignalBlockPath(signals, i) != NULL)) {
816 errstr = rtwCAPI_mallocError;
817 goto EXIT_POINT;
818 }
819 } else {
820 const char* constBlockPath = rtwCAPI_GetSignalBlockPath(signals, i);
821 blockPath = (char*)utMalloc((strlen(constBlockPath)+1)*sizeof(char));
822 (void)strcpy(blockPath, constBlockPath);
823 }
824 utAssert(blockPath != NULL);
825 sigPathLen = ( (mmiPath==NULL) ?
826 strlen(blockPath) + 1 :
827 mmiPathLen + strlen(blockPath) + 2 );
828 sigPath = (char*)utMalloc(sigPathLen*sizeof(char));
829 if (sigPath == NULL) {
830 errstr = rtwCAPI_mallocError;
831 goto EXIT_POINT;
832 }
833 if (mmiPath != NULL) {
834 (void)strcpy(sigPath, mmiPath);
835 sigPath[mmiPathLen] = '|';
836 sigPath[mmiPathLen+1] = '\0';
837 (void)strcat(sigPath, blockPath);
838 } else {
839 (void)strcpy(sigPath, blockPath);
840 sigPath[sigPathLen-1] = '\0';
841 }
842 /* need to free for every iteration of the loop, but also have
843 * the free below EXIT_POINT in case of error */
844 utFree(blockPath);
845 blockPath = NULL;
846 utAssert(sigPath[sigPathLen-1] == '\0');
847 sigBlockName[*sigIdx] = sigPath; /* caller is responsible for free */
848
849 /* Label */
850 sigLabel[*sigIdx] = rtwCAPI_GetSignalName(signals, i);
851
852 /* Width */
853 mapIdx = rtwCAPI_GetSignalDimensionIdx(signals, i);
854 utAssert( rtwCAPI_GetNumDims(dimMap,mapIdx) == 2 );
855 mapIdx = rtwCAPI_GetDimArrayIndex(dimMap, mapIdx);
856 sigWidth[*sigIdx] = dimArray[mapIdx] * dimArray[mapIdx+1];
857
858 /* DataType and logDataType */
859 mapIdx = rtwCAPI_GetSignalDataTypeIdx(signals, i);
860 sigDataType[*sigIdx] = rtwCAPI_GetDataTypeSLId(dataTypeMap, mapIdx);
861 /* this mimics code in simulink.dll:mapSigDataTypeToLogDataType */
862 switch (sigDataType[*sigIdx]) {
863 case SS_DOUBLE:
864 case SS_SINGLE:
865 case SS_INT8:
866 case SS_UINT8:
867 case SS_INT16:
868 case SS_UINT16:
869 case SS_INT32:
870 case SS_UINT32:
871 case SS_BOOLEAN:
872 logDataType[*sigIdx] = sigDataType[*sigIdx];
873 break;
874 case SS_ENUM_TYPE:
875 logDataType[*sigIdx] = SS_INT32;
876 break;
877 default:
878 logDataType[*sigIdx] = SS_DOUBLE;
879 break;
880 }
881
882 /* Complexity */
883 sigComplexity[*sigIdx] = rtwCAPI_GetDataIsComplex(dataTypeMap, mapIdx);
884
885 /* Data Access - Pointer or Direct*/
886 isPointer = ((uint8_T)rtwCAPI_GetDataIsPointer(dataTypeMap, mapIdx));
887
888 /* Address */
889 mapIdx = rtwCAPI_GetSignalAddrIdx(signals, i);
890
891 rtwCAPI_GetSigAddrFromMap(isPointer, sigComplexity, sigDataType,
892 sigDataAddr, sigIdx, mapIdx, dataAddrMap);
893
894 /* CrossingModelBoundary */
895 sigCrossMdlRef[*sigIdx] = crossingModel;
896
897 ++(*sigIdx);
898 }
899
900 EXIT_POINT:
901 utFree(blockPath);
902 return(errstr);
903
904} /* rtwCAPI_GetSigLogRecordInfo */
905
906
907/** Function: rtwCAPI_CountSysRan ==============================================
908 * Recursive function that counts the number of non-NULL pointers in the array
909 * of system ran dwork pointers, for the given MMI and below
910 */
911void rtwCAPI_CountSysRan(const rtwCAPI_ModelMappingInfo *mmi,
912 int *count)
913{
914 sysRanDType **sysRan;
915 int numSys;
916 int nCMMI;
917 int numSysRan = 0;
918 int i;
919
920 if (mmi == NULL) return;
921
922 sysRan = rtwCAPI_GetSystemRan(mmi);
923 numSys = rtwCAPI_GetNumSystems(mmi);
924 nCMMI = rtwCAPI_GetChildMMIArrayLen(mmi);
925
926 /* Recurse over children */
927 for (i = 0; i < nCMMI; i++) {
928 rtwCAPI_CountSysRan(rtwCAPI_GetChildMMI(mmi,i), &numSysRan);
929 }
930
931 /* Count number of dworks in this MMI - skip root */
932 for (i = 1; i< numSys; i++) {
933 if (sysRan[i] != NULL) numSysRan++;
934 }
935
936 *count += numSysRan;
937
938} /* end rtwCAPI_CountSysRan */
939
940
941/** Function: rtwCAPI_FillSysRan ===============================================
942 * Recursive function that fills in the system ran dwork pointers and their
943 * corresponding tids in the given array, for the given MMI and below. The
944 * array to be filled in must be allocated outside
945 */
946void rtwCAPI_FillSysRan(const rtwCAPI_ModelMappingInfo *mmi,
947 sysRanDType **sysRan,
948 int *sysTid,
949 int *fillIdx)
950{
951 int numSys;
952 sysRanDType **mmiSysRan;
953 int nCMMI;
954 int *mmiSysTid;
955 int idx = *fillIdx;
956 const int *mmiConSys;
957 int i;
958
959 if (mmi == NULL) return;
960
961 numSys = rtwCAPI_GetNumSystems(mmi);
962 mmiSysRan = rtwCAPI_GetSystemRan(mmi);
963 nCMMI = rtwCAPI_GetChildMMIArrayLen(mmi);
964 mmiSysTid = rtwCAPI_GetSystemTid(mmi);
965 mmiConSys = rtwCAPI_GetContextSystems(mmi);
966
967 /* Recurse over children */
968 for (i = 0; i < nCMMI; i++) {
969 rtwCAPI_FillSysRan(rtwCAPI_GetChildMMI(mmi,i), sysRan, sysTid, &idx);
970 }
971
972 /* Populate arrays with dwork pointers and tid - skip root */
973 for (i = 1; i< numSys; i++) {
974 if (mmiSysRan[i] != NULL) {
975 idx++;
976 sysRan[idx] = mmiSysRan[i];
977 sysTid[idx] = mmiSysTid[mmiConSys[i]];
978 }
979 }
980
981 *fillIdx = idx;
982
983} /* end rtwCAPI_FillSysRan */
984
985/* LocalWords: CAPI bpath aaa Addr mmi CSTATE DSTATE Hier tids
986 */
987