1 /*
2  * Trace Recorder for Tracealyzer v4.5.1
3  * Copyright 2021 Percepio AB
4  * www.percepio.com
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  *
8  * uC/OS3 specific parts of the trace recorder
9  */
10 
11 #include <os.h>
12 #include <lib_str.h>
13 #include "trcInternalBuffer.h"
14 
15 #if (defined(TRC_USE_TRACEALYZER_RECORDER) && TRC_USE_TRACEALYZER_RECORDER == 1)
16 
17 #if (OS_VERSION < 30700u)
18 /* This is used to keep track of the tick task so we are able to filter it */
19 void* prvTrcTickTask = 0;
20 #endif /* (OS_VERSION < 30700u) */
21 
22 #include <stdint.h>
23 
24 #if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING) || (defined(TRC_CFG_ENABLE_STACK_MONITOR) && (TRC_CFG_ENABLE_STACK_MONITOR == 1) && (TRC_CFG_SCHEDULING_ONLY == 0))
25 
26 /* TzCtrl task Stack and TCB */
27 static  CPU_STK  TzCtrlStk[TRC_CFG_CTRL_TASK_STACK_SIZE];
28 static  OS_TCB   TzCtrlTCB;
29 static  OS_TCB*  ptrTzCtrlTCB = NULL;
30 
31 /* The TzCtrl task - receives commands from Tracealyzer (start/stop) */
32 static  void     TzCtrl (void  *p_arg);
33 
34 #if defined(TRC_CFG_ENABLE_STACK_MONITOR) && (TRC_CFG_ENABLE_STACK_MONITOR == 1) && (TRC_CFG_SCHEDULING_ONLY == 0)
35 void prvReportStackUsage(void);
36 #else /* defined(TRC_CFG_ENABLE_STACK_MONITOR) && (TRC_CFG_ENABLE_STACK_MONITOR == 1) && (TRC_CFG_SCHEDULING_ONLY == 0) */
37 #define prvReportStackUsage()
38 #endif /* defined(TRC_CFG_ENABLE_STACK_MONITOR) && (TRC_CFG_ENABLE_STACK_MONITOR == 1) && (TRC_CFG_SCHEDULING_ONLY == 0) */
39 
40 #endif /* (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING) || (defined(TRC_CFG_ENABLE_STACK_MONITOR) && (TRC_CFG_ENABLE_STACK_MONITOR == 1) && (TRC_CFG_SCHEDULING_ONLY == 0)) */
41 
42 #define TRC_MAX_STRING_APPEND_SIZE 64
43 
44 /* Variables to hold the latest suspended and resumed task */
45 static void* lastResumedTask = 0;
46 static void* lastSuspendedTask = 0;
47 
prvTraceGetCurrentTaskHandle(void)48 void* prvTraceGetCurrentTaskHandle(void)
49 {
50 	return (void*)OSTCBCurPtr;                                         /* OSTCBCurPtr is a pointer to currently running TCB    */
51 }
52 
prvTraceAppend(const char * name,const char * suffix)53 char* prvTraceAppend(const char *name, const char *suffix)
54 {
55 	static char buf[TRC_MAX_STRING_APPEND_SIZE];
56 	uint32_t i = 0, j = 0;
57 
58 	/* (i < ((TRC_MAX_STRING_APPEND_SIZE) - 2)) leaves room for ' ' and null termination */
59 	while ((i < ((TRC_MAX_STRING_APPEND_SIZE) - 2)) && (name[i] != 0))
60 	{
61 		buf[i] = name[i];
62 		i++;
63 	}
64 
65 	buf[i] = ' ';
66 	i++;
67 
68 	/* (i < ((TRC_MAX_STRING_APPEND_SIZE) - 1)) leaves room for null termination */
69 	while ((i < ((TRC_MAX_STRING_APPEND_SIZE) - 1)) && (suffix[j] != 0))
70 	{
71 		buf[i] = suffix[j];
72 		i++;
73 		j++;
74 	}
75 
76 	/* Always null termination */
77 	buf[i] = 0;
78 
79 	return (&buf[0]);
80 }
81 
82 /* Tasks */
prvTraceGetTaskNumberLow16(void * handle)83 uint16_t prvTraceGetTaskNumberLow16(void* handle)
84 {
85 	if (handle == 0)
86 		return 0;
87 
88 	return TRACE_GET_LOW16(((OS_TCB*)handle)->TaskID);
89 }
90 
prvTraceGetTaskNumberHigh16(void * handle)91 uint16_t prvTraceGetTaskNumberHigh16(void* handle)
92 {
93 	return TRACE_GET_HIGH16(((OS_TCB*)handle)->TaskID);
94 }
95 
prvTraceSetTaskNumberLow16(void * handle,uint16_t value)96 void prvTraceSetTaskNumberLow16(void* handle, uint16_t value)
97 {
98 	((OS_TCB*)handle)->TaskID = TRACE_SET_LOW16(((OS_TCB*)handle)->TaskID, value);
99 }
100 
prvTraceSetTaskNumberHigh16(void * handle,uint16_t value)101 void prvTraceSetTaskNumberHigh16(void* handle, uint16_t value)
102 {
103 	((OS_TCB*)handle)->TaskID = TRACE_SET_HIGH16(((OS_TCB*)handle)->TaskID, value);
104 }
105 
106 /* Task Queues */
107 #if (OS_CFG_TASK_Q_EN == DEF_ENABLED)
prvTraceGetTaskQueueNumberLow16(void * handle)108 uint16_t prvTraceGetTaskQueueNumberLow16(void* handle)
109 {
110 	return TRACE_GET_LOW16(((OS_MSG_Q *)handle)->MsgQID);
111 }
112 
prvTraceGetTaskQueueNumberHigh16(void * handle)113 uint16_t prvTraceGetTaskQueueNumberHigh16(void* handle)
114 {
115 	return TRACE_GET_HIGH16(((OS_MSG_Q *)handle)->MsgQID);
116 }
117 
prvTraceSetTaskQueueNumberLow16(void * handle,uint16_t value)118 void prvTraceSetTaskQueueNumberLow16(void* handle, uint16_t value)
119 {
120 	((OS_MSG_Q *)handle)->MsgQID = TRACE_SET_LOW16(((OS_MSG_Q *)handle)->MsgQID, value);
121 }
122 
prvTraceSetTaskQueueNumberHigh16(void * handle,uint16_t value)123 void prvTraceSetTaskQueueNumberHigh16(void* handle, uint16_t value)
124 {
125 	((OS_MSG_Q *)handle)->MsgQID = TRACE_SET_HIGH16(((OS_MSG_Q *)handle)->MsgQID, value);
126 }
127 #endif /* (OS_CFG_TASK_Q_EN == DEF_ENABLED) */
128 
129 /* Task Semaphores */
prvTraceGetTaskSemNumberLow16(void * handle)130 uint16_t prvTraceGetTaskSemNumberLow16(void* handle)
131 {
132 	return TRACE_GET_LOW16(((OS_TCB *)handle)->SemID);
133 }
134 
prvTraceGetTaskSemNumberHigh16(void * handle)135 uint16_t prvTraceGetTaskSemNumberHigh16(void* handle)
136 {
137 	return TRACE_GET_HIGH16(((OS_TCB *)handle)->SemID);
138 }
139 
prvTraceSetTaskSemNumberLow16(void * handle,uint16_t value)140 void prvTraceSetTaskSemNumberLow16(void* handle, uint16_t value)
141 {
142 	((OS_TCB *)handle)->SemID = TRACE_SET_LOW16(((OS_TCB *)handle)->SemID, value);
143 }
144 
prvTraceSetTaskSemNumberHigh16(void * handle,uint16_t value)145 void prvTraceSetTaskSemNumberHigh16(void* handle, uint16_t value)
146 {
147 	((OS_TCB *)handle)->SemID = TRACE_SET_HIGH16(((OS_TCB *)handle)->SemID, value);
148 }
149 
150 /* Queues */
prvTraceGetQueueNumberLow16(void * handle)151 uint16_t prvTraceGetQueueNumberLow16(void* handle)
152 {
153 	return TRACE_GET_LOW16(((OS_Q*)handle)->MsgQ.MsgQID);
154 }
155 
prvTraceGetQueueNumberHigh16(void * handle)156 uint16_t prvTraceGetQueueNumberHigh16(void* handle)
157 {
158 	return TRACE_GET_HIGH16(((OS_Q*)handle)->MsgQ.MsgQID);
159 }
160 
prvTraceSetQueueNumberLow16(void * handle,uint16_t value)161 void prvTraceSetQueueNumberLow16(void* handle, uint16_t value)
162 {
163 	((OS_Q*)handle)->MsgQ.MsgQID = TRACE_SET_LOW16(((OS_Q*)handle)->MsgQ.MsgQID, value);
164 }
165 
prvTraceSetQueueNumberHigh16(void * handle,uint16_t value)166 void prvTraceSetQueueNumberHigh16(void* handle, uint16_t value)
167 {
168 	((OS_Q*)handle)->MsgQ.MsgQID = TRACE_SET_HIGH16(((OS_Q*)handle)->MsgQ.MsgQID, value);
169 }
170 
171 /* Semaphores */
prvTraceGetSemaphoreNumberLow16(void * handle)172 uint16_t prvTraceGetSemaphoreNumberLow16(void* handle)
173 {
174 	return TRACE_GET_LOW16(((OS_SEM*)handle)->SemID);
175 }
176 
prvTraceGetSemaphoreNumberHigh16(void * handle)177 uint16_t prvTraceGetSemaphoreNumberHigh16(void* handle)
178 {
179 	return TRACE_GET_HIGH16(((OS_SEM*)handle)->SemID);
180 }
181 
prvTraceSetSemaphoreNumberLow16(void * handle,uint16_t value)182 void prvTraceSetSemaphoreNumberLow16(void* handle, uint16_t value)
183 {
184 	((OS_SEM*)handle)->SemID = TRACE_SET_LOW16(((OS_SEM*)handle)->SemID, value);
185 }
186 
prvTraceSetSemaphoreNumberHigh16(void * handle,uint16_t value)187 void prvTraceSetSemaphoreNumberHigh16(void* handle, uint16_t value)
188 {
189 	((OS_SEM*)handle)->SemID = TRACE_SET_HIGH16(((OS_SEM*)handle)->SemID, value);
190 }
191 
192 /* Mutexes */
prvTraceGetMutexNumberLow16(void * handle)193 uint16_t prvTraceGetMutexNumberLow16(void* handle)
194 {
195 	return TRACE_GET_LOW16(((OS_MUTEX*)handle)->MutexID);
196 }
197 
prvTraceGetMutexNumberHigh16(void * handle)198 uint16_t prvTraceGetMutexNumberHigh16(void* handle)
199 {
200 	return TRACE_GET_HIGH16(((OS_MUTEX*)handle)->MutexID);
201 }
202 
prvTraceSetMutexNumberLow16(void * handle,uint16_t value)203 void prvTraceSetMutexNumberLow16(void* handle, uint16_t value)
204 {
205 	((OS_MUTEX*)handle)->MutexID = TRACE_SET_LOW16(((OS_MUTEX*)handle)->MutexID, value);
206 }
207 
prvTraceSetMutexNumberHigh16(void * handle,uint16_t value)208 void prvTraceSetMutexNumberHigh16(void* handle, uint16_t value)
209 {
210 	((OS_MUTEX*)handle)->MutexID = TRACE_SET_HIGH16(((OS_MUTEX*)handle)->MutexID, value);
211 }
212 
213 /* Flags */
prvTraceGetFlagNumberLow16(void * handle)214 uint16_t prvTraceGetFlagNumberLow16(void* handle)
215 {
216 	return TRACE_GET_LOW16(((OS_FLAG_GRP*)handle)->FlagID);
217 }
218 
prvTraceGetFlagNumberHigh16(void * handle)219 uint16_t prvTraceGetFlagNumberHigh16(void* handle)
220 {
221 	return TRACE_GET_HIGH16(((OS_FLAG_GRP*)handle)->FlagID);
222 }
223 
prvTraceSetFlagNumberLow16(void * handle,uint16_t value)224 void prvTraceSetFlagNumberLow16(void* handle, uint16_t value)
225 {
226 	((OS_FLAG_GRP*)handle)->FlagID = TRACE_SET_LOW16(((OS_FLAG_GRP*)handle)->FlagID, value);
227 }
228 
prvTraceSetFlagNumberHigh16(void * handle,uint16_t value)229 void prvTraceSetFlagNumberHigh16(void* handle, uint16_t value)
230 {
231 	((OS_FLAG_GRP*)handle)->FlagID = TRACE_SET_HIGH16(((OS_FLAG_GRP*)handle)->FlagID, value);
232 }
233 
234 /* Mems */
prvTraceGetMemNumberLow16(void * handle)235 uint16_t prvTraceGetMemNumberLow16(void* handle)
236 {
237 	return TRACE_GET_LOW16(((OS_MEM*)handle)->MemID);
238 }
239 
prvTraceGetMemNumberHigh16(void * handle)240 uint16_t prvTraceGetMemNumberHigh16(void* handle)
241 {
242 	return TRACE_GET_HIGH16(((OS_MEM*)handle)->MemID);
243 }
244 
prvTraceSetMemNumberLow16(void * handle,uint16_t value)245 void prvTraceSetMemNumberLow16(void* handle, uint16_t value)
246 {
247 	((OS_MEM*)handle)->MemID = TRACE_SET_LOW16(((OS_MEM*)handle)->MemID, value);
248 }
249 
prvTraceSetMemNumberHigh16(void * handle,uint16_t value)250 void prvTraceSetMemNumberHigh16(void* handle, uint16_t value)
251 {
252 	((OS_MEM*)handle)->MemID = TRACE_SET_HIGH16(((OS_MEM*)handle)->MemID, value);
253 }
254 
255 /* Suspend and resume */
prvTraceTaskSuspendEnter(void * p_tcb)256 void prvTraceTaskSuspendEnter(void* p_tcb)
257 {
258 	TRACE_ALLOC_CRITICAL_SECTION();
259 	TRACE_ENTER_CRITICAL_SECTION();
260 	lastSuspendedTask = p_tcb;
261 }
262 
prvTraceTaskSuspendExit(uint32_t p_err)263 void prvTraceTaskSuspendExit(uint32_t p_err)
264 {
265 	if(p_err == OS_ERR_NONE){
266 #if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_SNAPSHOT)
267 		if (lastSuspendedTask == 0)
268 		{
269 			trcKERNEL_HOOKS_TASK_SUSPEND(TASK_SUSPEND, OSTCBCurPtr);
270 		}
271 		else
272 		{
273 			trcKERNEL_HOOKS_TASK_SUSPEND(TASK_SUSPEND, lastSuspendedTask);
274 		}
275 #else
276 		if (lastSuspendedTask == 0)
277 		{
278 			prvTraceStoreEvent1(PSF_EVENT_TASK_SUSPEND, (uint32_t)OSTCBCurPtr);
279 		}
280 		else
281 		{
282 			prvTraceStoreEvent1(PSF_EVENT_TASK_SUSPEND, lastSuspendedTask);
283 		}
284 #endif
285 	}
286 	else{
287 #if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_SNAPSHOT)
288 		if (lastSuspendedTask == 0)
289 		{
290 			trcKERNEL_HOOKS_TASK_SUSPEND(TASK_SUSPEND_FAIL, OSTCBCurPtr);
291 		}
292 		else
293 		{
294 			trcKERNEL_HOOKS_TASK_SUSPEND(TASK_SUSPEND_FAIL, lastSuspendedTask);
295 		}
296 #else
297 		if (lastSuspendedTask == 0)
298 		{
299 			prvTraceStoreEvent1(PSF_EVENT_TASK_SUSPEND_FAILED, (uint32_t)OSTCBCurPtr);
300 		}
301 		else
302 		{
303 			prvTraceStoreEvent1(PSF_EVENT_TASK_SUSPEND_FAILED, lastSuspendedTask);
304 		}
305 #endif
306 	}
307 	TRACE_ALLOC_CRITICAL_SECTION();
308 	TRACE_EXIT_CRITICAL_SECTION();
309 }
prvTraceTaskResumeEnter(void * p_tcb)310 void prvTraceTaskResumeEnter(void* p_tcb)
311 {
312 	TRACE_ALLOC_CRITICAL_SECTION();
313 	TRACE_ENTER_CRITICAL_SECTION();
314 	lastResumedTask = p_tcb;
315 }
316 
prvTraceTaskResumeExit(uint32_t p_err)317 void prvTraceTaskResumeExit(uint32_t p_err)
318 {
319 	if(p_err == OS_ERR_NONE){
320 #if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_SNAPSHOT)
321 		trcKERNEL_HOOKS_TASK_RESUME(TASK_RESUME, lastResumedTask);
322 #else
323 		prvTraceStoreEvent1(PSF_EVENT_TASK_RESUME, lastResumedTask);
324 #endif
325 	}
326 	else{
327 #if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_SNAPSHOT)
328 		trcKERNEL_HOOKS_TASK_RESUME(TASK_RESUME_FAIL, lastResumedTask);
329 #else
330 		prvTraceStoreEvent1(PSF_EVENT_TASK_RESUME_FAILED, lastResumedTask);
331 #endif
332 	}
333 	TRACE_ALLOC_CRITICAL_SECTION();
334 	TRACE_EXIT_CRITICAL_SECTION();
335 }
336 
337 
338 #if defined(TRC_CFG_ENABLE_STACK_MONITOR) && (TRC_CFG_ENABLE_STACK_MONITOR == 1) && (TRC_CFG_SCHEDULING_ONLY == 0)
prvTraceGetStackHighWaterMark(void * task)339 uint32_t prvTraceGetStackHighWaterMark(void* task)
340 {
341 	CPU_STK_SIZE free = 0, used = 0;
342 	OS_ERR err;
343 
344 	OSTaskStkChk(task, &free, &used, &err);
345 
346 	return free;
347 }
348 #endif /* defined(TRC_CFG_ENABLE_STACK_MONITOR) && (TRC_CFG_ENABLE_STACK_MONITOR == 1) && (TRC_CFG_SCHEDULING_ONLY == 0) */
349 
350 #if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING)
351 
352 static void* pCurrentTCB = NULL;
353 
354 /* Monitored by TzCtrl task, that give warnings as User Events */
355 extern volatile uint32_t NoRoomForSymbol;
356 extern volatile uint32_t NoRoomForObjectData;
357 extern volatile uint32_t LongestSymbolName;
358 extern volatile uint32_t MaxBytesTruncated;
359 #if defined(TRC_CFG_ENABLE_STACK_MONITOR) && (TRC_CFG_ENABLE_STACK_MONITOR == 1) && (TRC_CFG_SCHEDULING_ONLY == 0)
360 extern volatile uint32_t TaskStacksNotIncluded;
361 #endif /* defined(TRC_CFG_ENABLE_STACK_MONITOR) && (TRC_CFG_ENABLE_STACK_MONITOR == 1) && (TRC_CFG_SCHEDULING_ONLY == 0) */
362 
363 /* User Event Channel for giving warnings regarding NoRoomForSymbol etc. */
364 traceString trcWarningChannel = 0;
365 
366 TRC_STREAM_PORT_ALLOCATE_FIELDS()
367 
368 /* Called by TzCtrl task periodically (Normally every 100 ms) */
369 static void prvCheckRecorderStatus(void);
370 
371 extern void prvTraceWarning(int errCode);
372 
373 /*******************************************************************************
374  * vTraceEnable
375  *
376  * Function that enables the tracing and creates the control task. It will halt
377  * execution until a Start command has been received if haltUntilStart is true.
378  *
379  ******************************************************************************/
vTraceEnable(int startOption)380 void vTraceEnable(int startOption)
381 {
382     OS_ERR err;
383 	int32_t bytes = 0;
384 	int32_t status;
385 	TracealyzerCommandType msg;
386     extern uint32_t RecorderEnabled;
387 
388 	/* Make sure recorder data is initialized */
389 	vTraceInitialize();
390 
391 	if (ptrTzCtrlTCB == 0)
392 	{
393 		TRC_STREAM_PORT_INIT();
394 
395 		/* The #WFR channel means "Warnings from Recorder" and
396 		* is used to store warnings and errors from the recorder.
397 		* The abbreviation #WFR is used instead of the longer full name,
398 		* to avoid truncation by small slots in the symbol table.
399 		* This is translated in Tracealyzer and shown as the full name,
400 		* "Warnings from Recorder".
401 		*
402 		* Note: Requires that TRC_CFG_INCLUDE_USER_EVENTS is 1. */
403 		trcWarningChannel = xTraceRegisterString("#WFR");
404 
405         /* Creates the TzCtrl task - receives trace commands (start, stop, ...) */
406 		OSTaskCreate((OS_TCB     *)&TzCtrlTCB,             /* Create the control task                              */
407 					(CPU_CHAR   *)"Tracealyzer Control Task",
408 					(OS_TASK_PTR ) TzCtrl,
409 					(void       *) 0,
410 					(OS_PRIO     ) (TRC_CFG_CTRL_TASK_PRIORITY),
411 					(CPU_STK    *)&TzCtrlStk[0],
412 					(CPU_STK_SIZE) (TRC_CFG_CTRL_TASK_STACK_SIZE) / 10u,
413 					(CPU_STK_SIZE) (TRC_CFG_CTRL_TASK_STACK_SIZE),
414 					(OS_MSG_QTY  ) 0u,
415 					(OS_TICK     ) 0u,
416 					(void       *) 0,
417 					(OS_OPT      )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
418 					(OS_ERR     *)&err);
419 
420 		ptrTzCtrlTCB = &TzCtrlTCB;
421 	}
422 
423 	if (startOption == TRC_START_AWAIT_HOST)
424 	{
425 		/* We keep trying to read commands until the recorder has been started */
426 		do
427 		{
428 			bytes = 0;
429 
430 			status = TRC_STREAM_PORT_READ_DATA(&msg, sizeof(TracealyzerCommandType), (int32_t*)&bytes);
431 
432 			if (status != 0)
433 			{
434 				prvTraceWarning(PSF_WARNING_STREAM_PORT_READ);
435 			}
436 
437 			if ((status == 0) && (bytes == sizeof(TracealyzerCommandType)))
438 			{
439 				if (prvIsValidCommand(&msg))
440 				{
441 					if (msg.cmdCode == CMD_SET_ACTIVE && msg.param1 == 1)
442 					{
443 						/* On start, init and reset the timestamping */
444 						TRC_PORT_SPECIFIC_INIT();
445 					}
446 
447 					prvProcessCommand(&msg);
448 				}
449 			}
450 		}
451 		while (RecorderEnabled == 0);
452 	}
453 	else if (startOption == TRC_START)
454 	{
455 		/* We start streaming directly - this assumes that the interface is ready! */
456 		TRC_PORT_SPECIFIC_INIT();
457 
458 		msg.cmdCode = CMD_SET_ACTIVE;
459 		msg.param1 = 1;
460 		prvProcessCommand(&msg);
461 	}
462 	else if (startOption == TRC_INIT)
463 	{
464 		/* On TRC_INIT */
465 		TRC_PORT_SPECIFIC_INIT();
466 	}
467 }
468 
469 /*******************************************************************************
470  * prvTraceOnBegin
471  *
472  * Called on trace begin.
473  ******************************************************************************/
prvTraceOnBegin()474 void prvTraceOnBegin()
475 {
476 	TRC_STREAM_PORT_ON_TRACE_BEGIN();
477 }
478 
479 /*******************************************************************************
480  * prvTraceOnEnd
481  *
482  * Called on trace end.
483  ******************************************************************************/
prvTraceOnEnd()484 void prvTraceOnEnd()
485 {
486 	TRC_STREAM_PORT_ON_TRACE_END();
487 }
488 
489 /*******************************************************************************
490  * prvIsNewTCB
491  *
492  * Tells if this task is already executing, or if there has been a task-switch.
493  * Assumed to be called within a trace hook in kernel context.
494  ******************************************************************************/
prvIsNewTCB(void * pNewTCB)495 uint32_t prvIsNewTCB(void* pNewTCB)
496 {
497 	if (pCurrentTCB != pNewTCB)
498 	{
499 		pCurrentTCB = pNewTCB;
500 		return 1;
501 	}
502 	return 0;
503 }
504 
505 /*******************************************************************************
506  * prvTraceIsSchedulerSuspended
507  *
508  * Returns true if the RTOS scheduler currently is disabled, thus preventing any
509  * task-switches from occurring. Only called from vTraceStoreISREnd.
510  ******************************************************************************/
prvTraceIsSchedulerSuspended(void)511 unsigned char prvTraceIsSchedulerSuspended(void)
512 {
513     return OSRunning != OS_STATE_OS_STOPPED;
514 }
515 
516 
517 /*******************************************************************************
518  * prvCheckRecorderStatus
519  *
520  * Called by TzCtrl task periodically (every 100 ms - seems reasonable).
521  * Checks a number of diagnostic variables and give warnings as user events,
522  * in most cases including a suggested solution.
523  ******************************************************************************/
prvCheckRecorderStatus(void)524 static void prvCheckRecorderStatus(void)
525 {
526 #if defined(TRC_CFG_ENABLE_STACK_MONITOR) && (TRC_CFG_ENABLE_STACK_MONITOR == 1) && (TRC_CFG_SCHEDULING_ONLY == 0)
527 	if (TaskStacksNotIncluded > 0)
528 	{
529 		prvTraceWarning(PSF_WARNING_STACKMON_NO_SLOTS);
530 		TaskStacksNotIncluded = 0;
531 	}
532 #endif /* defined(TRC_CFG_ENABLE_STACK_MONITOR) && (TRC_CFG_ENABLE_STACK_MONITOR == 1) && (TRC_CFG_SCHEDULING_ONLY == 0) */
533 
534 	if (NoRoomForSymbol > 0)
535 	{
536 		prvTraceWarning(PSF_WARNING_SYMBOL_TABLE_SLOTS);
537 		NoRoomForSymbol = 0;
538 	}
539 
540 	if (NoRoomForObjectData > 0)
541 	{
542 		prvTraceWarning(PSF_WARNING_OBJECT_DATA_SLOTS);
543 		NoRoomForObjectData = 0;
544 	}
545 
546 	if (LongestSymbolName > (TRC_CFG_SYMBOL_MAX_LENGTH))
547 	{
548 		prvTraceWarning(PSF_WARNING_SYMBOL_MAX_LENGTH);
549 		LongestSymbolName = 0;
550 	}
551 
552 	if (MaxBytesTruncated > 0)
553 	{
554 		prvTraceWarning(PSF_WARNING_STRING_TOO_LONG);
555 		MaxBytesTruncated = 0;
556 	}
557 }
558 
559 /*******************************************************************************
560  * TzCtrl
561  *
562  * Task for sending the trace data from the internal buffer to the stream
563  * interface (assuming TRC_STREAM_PORT_USE_INTERNAL_BUFFER == 1) and for
564  * receiving commands from Tracealyzer. Also does some diagnostics.
565  ******************************************************************************/
TzCtrl(void * p_arg)566 static void TzCtrl(void  *p_arg)
567 {
568     OS_ERR  err;
569 
570 	TracealyzerCommandType msg;
571 	int32_t bytes = 0;
572 	int32_t status = 0;
573 	(void)p_arg;
574 
575 	while (1)
576 	{
577 		do
578 		{
579 			/* Listen for new commands */
580 			bytes = 0;
581 			status = TRC_STREAM_PORT_READ_DATA(&msg, sizeof(TracealyzerCommandType), (int32_t*)&bytes);
582 
583 			if (status != 0)
584 			{
585 				/* The connection has failed, stop tracing */
586 				vTraceStop();
587 			}
588 
589 			if ((status == 0) && (bytes == sizeof(TracealyzerCommandType)))
590 			{
591 				if (prvIsValidCommand(&msg))
592 				{
593 					prvProcessCommand(&msg); /* Start or Stop currently... */
594 				}
595 			}
596 
597 /* If the internal buffer is disabled, the COMMIT macro instead sends the data directly
598    from the "event functions" (using TRC_STREAM_PORT_WRITE_DATA). */
599 #if (TRC_STREAM_PORT_USE_INTERNAL_BUFFER == 1)
600 			/* If there is a buffer page, this sends it to the streaming interface using TRC_STREAM_PORT_WRITE_DATA. */
601 			bytes = prvPagedEventBufferTransfer();
602 #endif
603 
604 		/* If there was data sent or received (bytes != 0), loop around and repeat, if there is more data to send or receive.
605 		Otherwise, step out of this loop and sleep for a while. */
606 
607 		} while (bytes != 0);
608 
609 		if (xTraceIsRecordingEnabled())
610 		{
611 			prvCheckRecorderStatus();
612 			prvReportStackUsage();
613 		}
614 
615 		OSTimeDly(TRC_CFG_CTRL_TASK_DELAY, OS_OPT_TIME_DLY, &err);	/* 10ms */
616 	}
617 }
618 
619 #endif /*(TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING)*/
620 
621 
622 #if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_SNAPSHOT)
623 
624 /* Initialization of the object property table */
vTraceInitObjectPropertyTable()625 void vTraceInitObjectPropertyTable()
626 {
627 	RecorderDataPtr->ObjectPropertyTable.NumberOfObjectClasses = TRACE_NCLASSES;
628 	RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[0] = TRC_CFG_NQUEUE;
629 	RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[1] = TRC_CFG_NSEMAPHORE;
630 	RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[2] = TRC_CFG_NMUTEX;
631 	RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[3] = TRC_CFG_NFLAG;
632 	RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[4] = TRC_CFG_NMEM;
633 	RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[5] = TRC_CFG_NTASK_SEM;
634 	RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[6] = TRC_CFG_NTASK_Q;
635 	RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[7] = TRC_CFG_NTASK;
636 	RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[8] = TRC_CFG_NISR;
637 	RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[0] = TRC_CFG_NAME_LEN_QUEUE;
638 	RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[1] = TRC_CFG_NAME_LEN_SEMAPHORE;
639 	RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[2] = TRC_CFG_NAME_LEN_MUTEX;
640 	RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[3] = TRC_CFG_NAME_LEN_FLAG;
641 	RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[4] = TRC_CFG_NAME_LEN_MEM;
642 	RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[5] = TRC_CFG_NAME_LEN_TASK_SEM;
643 	RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[6] = TRC_CFG_NAME_LEN_TASK_Q;
644 	RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[7] = TRC_CFG_NAME_LEN_TASK;
645 	RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[8] = TRC_CFG_NAME_LEN_ISR;
646 	RecorderDataPtr->ObjectPropertyTable.TotalPropertyBytesPerClass[0] = PropertyTableSizeQueue;
647 	RecorderDataPtr->ObjectPropertyTable.TotalPropertyBytesPerClass[1] = PropertyTableSizeSemaphore;
648 	RecorderDataPtr->ObjectPropertyTable.TotalPropertyBytesPerClass[2] = PropertyTableSizeMutex;
649 	RecorderDataPtr->ObjectPropertyTable.TotalPropertyBytesPerClass[3] = PropertyTableSizeFlag;
650 	RecorderDataPtr->ObjectPropertyTable.TotalPropertyBytesPerClass[4] = PropertyTableSizeMem;
651 	RecorderDataPtr->ObjectPropertyTable.TotalPropertyBytesPerClass[5] = PropertyTableSizeTaskSem;
652 	RecorderDataPtr->ObjectPropertyTable.TotalPropertyBytesPerClass[6] = PropertyTableSizeTaskQ;
653 	RecorderDataPtr->ObjectPropertyTable.TotalPropertyBytesPerClass[7] = PropertyTableSizeTask;
654 	RecorderDataPtr->ObjectPropertyTable.TotalPropertyBytesPerClass[8] = PropertyTableSizeISR;
655 	RecorderDataPtr->ObjectPropertyTable.StartIndexOfClass[0] = StartIndexQueue;
656 	RecorderDataPtr->ObjectPropertyTable.StartIndexOfClass[1] = StartIndexSemaphore;
657 	RecorderDataPtr->ObjectPropertyTable.StartIndexOfClass[2] = StartIndexMutex;
658 	RecorderDataPtr->ObjectPropertyTable.StartIndexOfClass[3] = StartIndexFlag;
659 	RecorderDataPtr->ObjectPropertyTable.StartIndexOfClass[4] = StartIndexMem;
660 	RecorderDataPtr->ObjectPropertyTable.StartIndexOfClass[5] = StartIndexTaskSem;
661 	RecorderDataPtr->ObjectPropertyTable.StartIndexOfClass[6] = StartIndexTaskQ;
662 	RecorderDataPtr->ObjectPropertyTable.StartIndexOfClass[7] = StartIndexTask;
663 	RecorderDataPtr->ObjectPropertyTable.StartIndexOfClass[8] = StartIndexISR;
664 	RecorderDataPtr->ObjectPropertyTable.ObjectPropertyTableSizeInBytes = TRACE_OBJECT_TABLE_SIZE;
665 }
666 
667 /* Initialization of the handle mechanism, see e.g, prvTraceGetObjectHandle */
vTraceInitObjectHandleStack()668 void vTraceInitObjectHandleStack()
669 {
670     uint32_t i = 0;
671 
672 	objectHandleStacks.indexOfNextAvailableHandle[0] = objectHandleStacks.lowestIndexOfClass[0] = 0;
673 	objectHandleStacks.indexOfNextAvailableHandle[1] = objectHandleStacks.lowestIndexOfClass[1] = (TRC_CFG_NQUEUE);
674 	objectHandleStacks.indexOfNextAvailableHandle[2] = objectHandleStacks.lowestIndexOfClass[2] = (TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE);
675 	objectHandleStacks.indexOfNextAvailableHandle[3] = objectHandleStacks.lowestIndexOfClass[3] = (TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE) + (TRC_CFG_NMUTEX);
676 	objectHandleStacks.indexOfNextAvailableHandle[4] = objectHandleStacks.lowestIndexOfClass[4] = (TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE) + (TRC_CFG_NMUTEX) + (TRC_CFG_NFLAG);
677 	objectHandleStacks.indexOfNextAvailableHandle[5] = objectHandleStacks.lowestIndexOfClass[5] = (TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE) + (TRC_CFG_NMUTEX) + (TRC_CFG_NFLAG) + (TRC_CFG_NMEM);
678 	objectHandleStacks.indexOfNextAvailableHandle[6] = objectHandleStacks.lowestIndexOfClass[6] = (TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE) + (TRC_CFG_NMUTEX) + (TRC_CFG_NFLAG) + (TRC_CFG_NMEM) + (TRC_CFG_NTASK_SEM);
679 	objectHandleStacks.indexOfNextAvailableHandle[7] = objectHandleStacks.lowestIndexOfClass[7] = (TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE) + (TRC_CFG_NMUTEX) + (TRC_CFG_NFLAG) + (TRC_CFG_NMEM) + (TRC_CFG_NTASK_SEM) + (TRC_CFG_NTASK_Q);
680 	objectHandleStacks.indexOfNextAvailableHandle[8] = objectHandleStacks.lowestIndexOfClass[8] = (TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE) + (TRC_CFG_NMUTEX) + (TRC_CFG_NFLAG) + (TRC_CFG_NMEM) + (TRC_CFG_NTASK_SEM) + (TRC_CFG_NTASK_Q) + (TRC_CFG_NTASK);
681 
682 	objectHandleStacks.highestIndexOfClass[0] = (TRC_CFG_NQUEUE) - 1;
683 	objectHandleStacks.highestIndexOfClass[1] = (TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE) - 1;
684 	objectHandleStacks.highestIndexOfClass[2] = (TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE) + (TRC_CFG_NMUTEX) - 1;
685 	objectHandleStacks.highestIndexOfClass[3] = (TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE) + (TRC_CFG_NMUTEX) + (TRC_CFG_NFLAG) - 1;
686 	objectHandleStacks.highestIndexOfClass[4] = (TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE) + (TRC_CFG_NMUTEX) + (TRC_CFG_NFLAG) + (TRC_CFG_NMEM) - 1;
687 	objectHandleStacks.highestIndexOfClass[5] = (TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE) + (TRC_CFG_NMUTEX) + (TRC_CFG_NFLAG) + (TRC_CFG_NMEM) + (TRC_CFG_NTASK_SEM) - 1;
688 	objectHandleStacks.highestIndexOfClass[6] = (TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE) + (TRC_CFG_NMUTEX) + (TRC_CFG_NFLAG) + (TRC_CFG_NMEM) + (TRC_CFG_NTASK_SEM) + (TRC_CFG_NTASK_Q) - 1;
689 	objectHandleStacks.highestIndexOfClass[7] = (TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE) + (TRC_CFG_NMUTEX) + (TRC_CFG_NFLAG) + (TRC_CFG_NMEM) + (TRC_CFG_NTASK_SEM) + (TRC_CFG_NTASK_Q) + (TRC_CFG_NTASK) - 1;
690 	objectHandleStacks.highestIndexOfClass[8] = (TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE) + (TRC_CFG_NMUTEX) + (TRC_CFG_NFLAG) + (TRC_CFG_NMEM) + (TRC_CFG_NTASK_SEM) + (TRC_CFG_NTASK_Q) + (TRC_CFG_NTASK) + (TRC_CFG_NISR) - 1;
691 
692 	for (i = 0; i < TRACE_NCLASSES; i++)
693 	{
694 		objectHandleStacks.handleCountWaterMarksOfClass[i] = 0;
695 	}
696 
697 	for (i = 0; i < TRACE_KERNEL_OBJECT_COUNT; i++)
698 	{
699 		objectHandleStacks.objectHandles[i] = 0;
700 	}
701 }
702 
703 /******************************************************************************
704 * vTraceEnable(int startOption) - snapshot mode
705 *
706 * Initializes and optionally starts the trace, depending on the start option.
707 * To use the trace recorder, the startup must call vTraceEnable before any RTOS
708 * calls are made (including "create" calls). Three start options are provided:
709 *
710 * TRC_START: Starts the tracing directly. In snapshot mode this allows for
711 * starting the trace at any point in your code, assuming vTraceEnable(TRC_INIT)
712 * has been called in the startup.
713 * Can also be used for streaming without Tracealyzer control, e.g. to a local
714 * flash file system (assuming such a "stream port", see trcStreamingPort.h).
715 *
716 * TRC_INIT: Initializes the trace recorder, but does not start the tracing.
717 * In snapshot mode, this must be followed by a vTraceEnable(TRC_START) sometime
718 * later.
719 *
720 * Usage examples, in snapshot mode:
721 *
722 * Snapshot trace, from startup:
723 * 	<board init>
724 * 	vTraceEnable(TRC_START);
725 * 	<RTOS init>
726 *
727 * Snapshot trace, from a later point:
728 * 	<board init>
729 * 	vTraceEnable(TRC_INIT);
730 * 	<RTOS init>
731 * 	...
732 * 	vTraceEnable(TRC_START); // e.g., in task context, at some relevant event
733 *
734 *
735 * Note: See other implementation of vTraceEnable in trcStreamingRecorder.c
736 ******************************************************************************/
vTraceEnable(int startOption)737 void vTraceEnable(int startOption)
738 {
739 	/* Make sure recorder data is initialized */
740 	vTraceInitialize();
741 
742 	if (startOption == TRC_START)
743 	{
744 		prvTraceInitTimestamps();
745 
746 		vTraceStart();
747 	}
748 	else if (startOption == TRC_START_AWAIT_HOST)
749 	{
750 		prvTraceError("vTraceEnable(TRC_START_AWAIT_HOST) not allowed in Snapshot mode");
751 	}
752 	else if (startOption != TRC_INIT)
753 	{
754 		prvTraceError("Unexpected argument to vTraceEnable (snapshot mode)");
755 	}
756 }
757 
758 #if defined(TRC_CFG_ENABLE_STACK_MONITOR) && (TRC_CFG_ENABLE_STACK_MONITOR == 1) && (TRC_CFG_SCHEDULING_ONLY == 0)
759 /******************************************************************************
760 * vTraceStartStackMonitor()
761 *
762 * Starts the TzCtrl task which reports stack usage.
763 * This must be called after OSInit().
764 ******************************************************************************/
vTraceStartStackMonitor()765 void vTraceStartStackMonitor()
766 {
767 	OS_ERR err;
768 
769 	if (ptrTzCtrlTCB == NULL)
770 	{
771 		/* Creates the TzCtrl task - reports unsed stack */
772 		OSTaskCreate((OS_TCB     *) &TzCtrlTCB,             /* Create the control task                              */
773 					 (CPU_CHAR   *) "TzCtrl",
774 					 (OS_TASK_PTR ) TzCtrl,
775 					 (void       *) 0,
776 					 (OS_PRIO     ) (TRC_CFG_CTRL_TASK_PRIORITY),
777 					 (CPU_STK    *) &TzCtrlStk[0],
778 					 (CPU_STK_SIZE) (TRC_CFG_CTRL_TASK_STACK_SIZE) / 10u,
779 					 (CPU_STK_SIZE) (TRC_CFG_CTRL_TASK_STACK_SIZE),
780 					 (OS_MSG_QTY  ) 0u,
781 					 (OS_TICK     ) 0u,
782 					 (void       *) 0,
783 					 (OS_OPT      ) (OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
784 					 (OS_ERR     *) &err);
785 
786 		ptrTzCtrlTCB = &TzCtrlTCB;
787 	}
788 }
789 #endif /* defined(TRC_CFG_ENABLE_STACK_MONITOR) && (TRC_CFG_ENABLE_STACK_MONITOR == 1) && (TRC_CFG_SCHEDULING_ONLY == 0) */
790 
791 #if defined(TRC_CFG_ENABLE_STACK_MONITOR) && (TRC_CFG_ENABLE_STACK_MONITOR == 1) && (TRC_CFG_SCHEDULING_ONLY == 0)
792 /*******************************************************************************
793  * TzCtrl
794  *
795  * Task used for reporting the stack usage for each task.
796  ******************************************************************************/
TzCtrl(void * p_arg)797 static void TzCtrl(void  *p_arg)
798 {
799 	OS_ERR err;
800 
801 	(void)p_arg;
802 
803 	while (1)
804 	{
805 		if (xTraceIsRecordingEnabled())
806 		{
807 			prvReportStackUsage();
808 		}
809 
810 		OSTimeDly(TRC_CFG_CTRL_TASK_DELAY, OS_OPT_TIME_DLY, &err);
811 	}
812 }
813 #endif /* defined(TRC_CFG_ENABLE_STACK_MONITOR) && (TRC_CFG_ENABLE_STACK_MONITOR == 1) && (TRC_CFG_SCHEDULING_ONLY == 0) */
814 
815 /* Returns the "Not enough handles" error message for this object class */
pszTraceGetErrorNotEnoughHandles(traceObjectClass objectclass)816 const char* pszTraceGetErrorNotEnoughHandles(traceObjectClass objectclass)
817 {
818 	switch(objectclass)
819 	{
820 	case TRACE_CLASS_QUEUE:
821 		return "Not enough QUEUE handles - increase TRC_CFG_NQUEUE in trcSnapshotConfig.h";
822 	case TRACE_CLASS_SEMAPHORE:
823 		return "Not enough SEMAPHORE handles - increase TRC_CFG_NSEMAPHORE in trcSnapshotConfig.h";
824 	case TRACE_CLASS_MUTEX:
825 		return "Not enough MUTEX handles - increase TRC_CFG_NMUTEX in trcSnapshotConfig.h";
826 	case TRACE_CLASS_FLAG:
827 		return "Not enough FLAG handles - increase TRC_CFG_NFLAG in trcSnapshotConfig.h";
828 	case TRACE_CLASS_MEM:
829 		return "Not enough MEM handles - increase TRC_CFG_NMEM in trcSnapshotConfig.h";
830 	case TRACE_CLASS_TASK_SEM:
831 		return "Not enough TASK_SEM handles - increase TRC_CFG_NTASK_SEM in trcSnapshotConfig.h";
832 	case TRACE_CLASS_TASK_Q:
833 		return "Not enough TASK_Q handles - increase TRC_CFG_NTASK_Q in trcSnapshotConfig.h";
834 	case TRACE_CLASS_TASK:
835 		return "Not enough TASK handles - increase TRC_CFG_NTASK in trcSnapshotConfig.h";
836 	case TRACE_CLASS_ISR:
837 		return "Not enough ISR handles - increase TRC_CFG_NISR in trcSnapshotConfig.h";
838 	default:
839 		return "pszTraceGetErrorHandles: Invalid objectclass!";
840 	}
841 }
842 
843 /*******************************************************************************
844  * prvTraceIsSchedulerSuspended
845  *
846  * Returns true if the RTOS scheduler currently is disabled, thus preventing any
847  * task-switches from occurring. Only called from vTraceStoreISREnd.
848  ******************************************************************************/
849 #if (TRC_CFG_INCLUDE_ISR_TRACING == 1)
prvTraceIsSchedulerSuspended(void)850 unsigned char prvTraceIsSchedulerSuspended(void)
851 {
852     return OSRunning != OS_STATE_OS_STOPPED;
853 }
854 #endif
855 
856 #endif /* Snapshot mode */
857 
858 #endif /*(TRC_USE_TRACEALYZER_RECORDER == 1)*/
859