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 | |
59 | static 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 | */ |
72 | char* 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 | */ |
104 | void 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 | */ |
173 | boolean_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 | */ |
195 | int_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 | */ |
218 | int_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 | */ |
253 | int_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 | */ |
292 | void 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 | */ |
317 | const 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 | */ |
380 | char* 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 | |
426 | uint_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 | */ |
448 | const 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 | */ |
683 | int_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 | */ |
706 | int_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 | */ |
741 | const 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 | */ |
911 | void 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 | */ |
946 | void 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 | |