1 /*******************************************************************************
\r
2 * Tracealyzer v3.0.0 Demo Application
\r
3 * Percepio AB, www.percepio.com
\r
7 * Demo application for Tracealyzer demo project.
\r
10 * This software is copyright Percepio AB. The recorder library is free for
\r
11 * use together with Percepio products. You may distribute the recorder library
\r
12 * in its original form, including modifications in trcHardwarePort.c/.h
\r
13 * given that these modification are clearly marked as your own modifications
\r
14 * and documented in the initial comment section of these source files.
\r
15 * This software is the intellectual property of Percepio AB and may not be
\r
16 * sold or in other ways commercially redistributed without explicit written
\r
17 * permission by Percepio AB.
\r
20 * The trace tool and recorder library is being delivered to you AS IS and
\r
21 * Percepio AB makes no warranty as to its use or performance. Percepio AB does
\r
22 * not and cannot warrant the performance or results you may obtain by using the
\r
23 * software or documentation. Percepio AB make no warranties, express or
\r
24 * implied, as to noninfringement of third party rights, merchantability, or
\r
25 * fitness for any particular purpose. In no event will Percepio AB, its
\r
26 * technology partners, or distributors be liable to you for any consequential,
\r
27 * incidental or special damages, including any lost profits or lost savings,
\r
28 * even if a representative of Percepio AB has been advised of the possibility
\r
29 * of such damages, or for any claim by any third party. Some jurisdictions do
\r
30 * not allow the exclusion or limitation of incidental, consequential or special
\r
31 * damages, or the exclusion of implied warranties or limitations on how long an
\r
32 * implied warranty may last, so the above limitations may not apply to you.
\r
34 * Tabs are used for indent in this file (1 tab = 4 spaces)
\r
36 * Copyright Percepio AB, 2014.
\r
38 ******************************************************************************/
\r
41 /* Standard includes. */
\r
45 /* Kernel includes. */
\r
46 #include <FreeRTOS.h>
\r
51 #if (configUSE_TIMERS == 1)
\r
55 #include "trcRecorder.h"
\r
57 #define ISR3_PERIOD 18
\r
58 #define ISR2_PERIOD 24
\r
59 #define ISR1_PERIOD 30
\r
61 #define EXECTIME_CONTROLLER 1
\r
62 #define EXECTIME_SUPERV 2
\r
63 #define EXECTIME_SENSOR 1
\r
69 char data[512]; // Makes the Memory Heap Utilization graph more interresting!
\r
72 #define MSGCODE_SENSOR_VALUE 1
\r
73 #define MSGCODE_CONTROL_VALUE 10
\r
74 #define MSGCODE_CONTROL_DEFAULT_VALUE 99
\r
76 static portTASK_FUNCTION_PROTO( trcDemoTaskSensor, pvParameters );
\r
77 static portTASK_FUNCTION_PROTO( trcDemoTaskActuator, pvParameters );
\r
78 static portTASK_FUNCTION_PROTO( trcDemoTaskController, pvParameters );
\r
79 static portTASK_FUNCTION( trcDemoTaskSuperv, pvParameters );
\r
80 static portTASK_FUNCTION( trcDemoISR, pvParameters );
\r
82 #if (configUSE_TIMERS == 1)
\r
84 void myTimerHandler(xTimerHandle tmr);
\r
87 xQueueHandle sensorQ, actuatorQ;
\r
88 xSemaphoreHandle Sem1, Sem2, Sem3;
\r
90 void doSomeWork(uint32_t n);
\r
92 int readSensor(int i);
\r
94 /******************************************************************************
\r
97 * Performs a busy wait for X milliseconds. Used to generate suitable execution
\r
98 * times in the demo application, in a portable way.
\r
99 ******************************************************************************/
\r
100 void doSomeWork(uint32_t ms)
\r
102 portTickType old = xTaskGetTickCount();
\r
103 portTickType new = 0;
\r
106 new = xTaskGetTickCount();
\r
109 /* If uiTraceTickCount has changed, we only reduce 1ms of the wait
\r
110 time. This way we do not count time that this task has waited
\r
111 for other tasks. This will result in somewhat correct execution
\r
119 /******************************************************************************
\r
122 * Simulates a set of sensors/inputs, using a simple physics simulation.
\r
123 * The values are intentionally ints (rather than floats) to avoid very slow
\r
124 * execution times on chips without hardware floating point support.
\r
125 ******************************************************************************/
\r
126 int readSensor(int i)
\r
128 static int pos[3] = {40, 80, 120};
\r
129 static int speed[3] = {0, 0, -3};
\r
130 static int acc[3] = {0, 0, 0};
\r
134 acc[i] = (-pos[i] >> 3);
\r
135 speed[i] += acc[i];
\r
136 pos[i] += speed[i];
\r
138 return (int)pos[i];
\r
141 /******************************************************************************
\r
142 * trcDemoTaskSensor
\r
144 * The "Sensor" tasks (three instances of this code). Reads data using
\r
145 * "readSensor" when trigged by the timer interrupt through a semaphore.
\r
146 ******************************************************************************/
\r
147 static portTASK_FUNCTION( trcDemoTaskSensor, pvParameters )
\r
149 char name[30] = "SensorX\0";
\r
150 QueueMessage sensorReading;
\r
151 unsigned char idx = (unsigned char)(*(int*)pvParameters);
\r
152 xSemaphoreHandle mySem = NULL;
\r
154 /* Change 'X' to the index */
\r
155 name[6] = '0' + idx;
\r
159 case 1: mySem = Sem1; break;
\r
160 case 2: mySem = Sem2; break;
\r
161 case 3: mySem = Sem3; break;
\r
164 vTraceStoreUserEventChannelName(name);
\r
166 /* Initialize xNextWakeTime - this only needs to be done once. */
\r
168 sensorReading.value = 0;
\r
169 sensorReading.code = 0;
\r
174 xSemaphoreTake(mySem, 0xFFFFFFFF);
\r
176 sensorReading.code = idx;
\r
177 sensorReading.value = readSensor(idx);
\r
179 doSomeWork(EXECTIME_SENSOR);
\r
181 vTracePrintF(name , "Sending msg %d", sensorReading.value);
\r
183 if (xQueueSend(sensorQ, &sensorReading, 1) != pdTRUE)
\r
185 vTracePrint(name, "Sensor queue full. Sample dropped!");
\r
187 vTraceInstanceFinishedNow();
\r
193 /******************************************************************************
\r
194 * trcDemoTaskSuperv
\r
196 * The "Supervisor" task. Performs no action in the simulation, apart from
\r
197 * preempting other tasks in the scheduling.
\r
198 ******************************************************************************/
\r
199 static portTASK_FUNCTION( trcDemoTaskSuperv, pvParameters )
\r
203 #if (configUSE_TIMERS == 1)
\r
204 static int timerState = 0;
\r
207 portTickType xNextWakeTime;
\r
208 (void)pvParameters;
\r
210 xNextWakeTime = xTaskGetTickCount();
\r
212 #if (configUSE_TIMERS == 1)
\r
213 timer = xTimerCreate("Tmr5", 5, 1, (void*)42, myTimerHandler);
\r
214 xTimerChangePeriod(timer, 10, 0);
\r
219 vTaskDelayUntil( &xNextWakeTime, 40);
\r
221 counter = (counter + 1) % 16;
\r
223 if (counter == 8) vTaskPrioritySet(NULL, 2);
\r
225 if (counter == 0) vTaskPrioritySet(NULL, 3);
\r
227 doSomeWork(EXECTIME_SUPERV);
\r
229 #if (configUSE_TIMERS == 1)
\r
230 if (timerState == 0)
\r
232 xTimerStart(timer, 0);
\r
235 else if (timerState == 1)
\r
237 xTimerStop(timer, 0);
\r
244 /******************************************************************************
\r
245 * trcDemoTaskController
\r
247 * The "Controller" task. Periodically reads all accumulated messages in SensorQ
\r
248 * (i.e., those produced by the Sensor tasks since the last execution of
\r
249 * the Controller task). Calculates their mean value and send this to Actuator.
\r
250 ******************************************************************************/
\r
251 static portTASK_FUNCTION( trcDemoTaskController, pvParameters )
\r
253 portTickType xNextWakeTime;
\r
254 QueueMessage* sensorReading;
\r
255 QueueMessage actuatorMessage;
\r
259 (void)pvParameters;
\r
261 vTraceStoreUserEventChannelName("UE TEST");
\r
263 /* Initialize xNextWakeTime - this only needs to be done once. */
\r
264 xNextWakeTime = xTaskGetTickCount();
\r
274 vTaskDelayUntil(&xNextWakeTime, 60);
\r
278 // To demostrate malloc/free tracing
\r
279 sensorReading = ( QueueMessage * ) pvPortMalloc( sizeof( QueueMessage ) );
\r
281 if (xQueueReceive(sensorQ, sensorReading, 0) != pdTRUE)
\r
283 vPortFree(sensorReading);
\r
288 if (sensorReading->code >= 1 && sensorReading->code <= 3)
\r
290 sum[sensorReading->code] += sensorReading->value;
\r
291 count[sensorReading->code]++;
\r
294 doSomeWork(EXECTIME_CONTROLLER);
\r
296 //vTracePrintF(0, "0x%4x", 111);
\r
297 //vTracePrintF(0, "0x%04x", 111);
\r
298 //vTracePrintF(0, "0x%4X", 111);
\r
299 //vTracePrintF(0, "0x%04X", 111);
\r
301 //vTracePrint(0, "123456789012345678901234567890123456789012345678901234567890");
\r
302 //vTracePrint("UE TEST", "1234567890123456789012345678901234567890123456789012345");
\r
303 //vTracePrint("UE TEST", "12345678901234567890123456789012345678901234567890123456");
\r
304 //vTracePrint("UE TEST", "123456789012345678901234567890123456789012345678901234567");
\r
305 //vTracePrint("UE TEST", "12345678901234567890123456789012345678901234567890");
\r
307 //vTracePrintF("UE TEST", "%5d", 42);
\r
308 //vTracePrintF("UE TEST", "%05d", 42);
\r
309 //vTracePrintF("UE TEST", "%5d", -42);
\r
310 //vTracePrintF("UE TEST", "%05d", -42);
\r
311 //vTracePrintF("UE TEST", "%05d", -1042);
\r
312 //vTracePrintF("UE TEST", "%05d", -11042);
\r
314 //vTracePrintF("UE TEST", "%5u", -1);
\r
315 //vTracePrintF("UE TEST", "%05u", -1);
\r
316 //vTracePrintF("UE TEST", "%5u", 10);
\r
317 //vTracePrintF("UE TEST", "%05u", 10);
\r
319 //vTracePrintF("UE TEST", "%5u", 11042);
\r
320 //vTracePrintF("UE TEST", "%05u", 11042);
\r
322 //vTracePrintF("UE TEST", "%5u", 111042);
\r
323 //vTracePrintF("UE TEST", "%05u", 111042);
\r
325 //vTracePrintF("UE TEST", "%15d", 111042);
\r
326 //vTracePrintF("UE TEST", "%015d", 111042);
\r
328 vPortFree(sensorReading);
\r
329 vTraceInstanceFinishedNow();
\r
333 actuatorMessage.code = MSGCODE_CONTROL_VALUE;
\r
334 actuatorMessage.value = 0;
\r
337 actuatorMessage.value += (int32_t)(0.5 * sum[1]/count[1]);
\r
339 actuatorMessage.value += (int32_t)(0.25 * sum[2]/count[2]);
\r
341 actuatorMessage.value += (int32_t)(0.25 * sum[3]/count[3]);
\r
343 xQueueSend(actuatorQ, &actuatorMessage, 10000);
\r
347 /******************************************************************************
\r
350 * The "FakeISR" task, that simulates the ISRTimer interrupts, which triggers
\r
351 * the Sensor tasks.
\r
352 ******************************************************************************/
\r
353 static portTASK_FUNCTION( trcDemoISR, pvParameters )
\r
355 portTickType xNextWakeTime;
\r
356 portBASE_TYPE dummy;
\r
359 (void)pvParameters;
\r
361 /* Initialize xNextWakeTime - this only needs to be done once. */
\r
362 xNextWakeTime = xTaskGetTickCount();
\r
363 vTraceSetISRProperties("ISRTimer1", 3);
\r
364 vTraceSetISRProperties("ISRTimer2", 2);
\r
365 vTraceSetISRProperties("ISRTimer3", 1);
\r
366 vTaskDelayUntil( &xNextWakeTime, 1);
\r
372 if (i % ISR3_PERIOD == 0)
\r
374 portENTER_CRITICAL();
\r
375 vTraceStoreISRBegin((void*)"ISRTimer3");
\r
376 xSemaphoreGiveFromISR(Sem3, &dummy);
\r
377 vTraceStoreISREndManual(dummy);
\r
378 portEXIT_CRITICAL();
\r
381 if (i % ISR2_PERIOD == 0)
\r
383 portENTER_CRITICAL();
\r
384 vTraceStoreISRBegin((void*)"ISRTimer2");
\r
385 xSemaphoreGiveFromISR(Sem2, &dummy);
\r
386 vTraceStoreISREndManual(dummy);
\r
387 portEXIT_CRITICAL();
\r
390 if (i % ISR1_PERIOD == 0)
\r
392 portENTER_CRITICAL();
\r
393 vTraceStoreISRBegin((void*)"ISRTimer1");
\r
394 xSemaphoreGiveFromISR(Sem1, &dummy);
\r
395 vTraceStoreISREndManual(dummy);
\r
396 portEXIT_CRITICAL();
\r
401 vTaskDelayUntil( &xNextWakeTime, 1);
\r
405 /******************************************************************************
\r
406 * trcDemoTaskActuator
\r
408 * The "Actuator" task, just reads the data from Controller and logs it in a
\r
409 * User Event (i.e., the "vTracePrintF" calls).
\r
410 ******************************************************************************/
\r
411 static portTASK_FUNCTION( trcDemoTaskActuator, pvParameters )
\r
413 QueueMessage inMessage;
\r
414 (void)pvParameters;
\r
415 vTraceStoreUserEventChannelName("Actuator Out Signal");
\r
419 vTraceInstanceFinishedNow();
\r
420 /* Place this task in blocked state until it is time to run again. */
\r
421 if (xQueueReceive(actuatorQ, &inMessage, 35) != pdTRUE)
\r
423 vTracePrintF("Actuator Out Signal", "No data...");
\r
427 if (inMessage.code == MSGCODE_CONTROL_VALUE)
\r
429 vTracePrintF("Actuator Out Signal", "Out: %d",
\r
436 #if (configUSE_TIMERS == 1)
\r
437 void myTimerHandler(xTimerHandle tmr)
\r
440 vTracePrintF("Timer", "Timer handler!");
\r
444 int sensorTaskID1 = 1;
\r
445 int sensorTaskID2 = 2;
\r
446 int sensorTaskID3 = 3;
\r
448 #define vTaskCreateNotTraced( pvTaskCode, pcName, usStackDepth, pvParameters, uxPriority ) \
\r
449 { void* this_pxCreatedTask; \
\r
450 vTraceSetReadyEventsEnabled(0); \
\r
451 xTaskGenericCreate( ( pvTaskCode ), ( pcName ), ( usStackDepth ), ( pvParameters ), ( uxPriority ), ( &this_pxCreatedTask ), ( NULL ), ( NULL ) ); \
\r
452 vTraceSetReadyEventsEnabled(1); \
\r
453 if (this_pxCreatedTask != NULL){ vTraceExcludeTaskFromTrace(this_pxCreatedTask); }else{ return -42;} }
\r
455 /******************************************************************************
\r
456 * trcDemoTaskActuator
\r
458 * The "Actuator" task, just reads the data from Controller and logs it in a
\r
459 * User Event (i.e., the "vTracePrintF" calls).
\r
460 ******************************************************************************/
\r
461 int vStartDemoApplication(void)
\r
463 void* objectHandle = NULL;
\r
465 vTraceStoreUserEventChannelName("Messages");
\r
467 vTracePrint("Messages", "Demo starting...");
\r
468 vTracePrint("Messages", "vTraceUserEvent creates basic User Events.");
\r
469 vTracePrint("Messages", "vTracePrintF creates advanced user events, like printf");
\r
470 //vTracePrintF("Messages", "A float: %f (should be 1)", (float)1.0);
\r
471 //vTracePrintF("Messages", "A double: %lf (should be 1)", (double)1.0);
\r
472 //vTracePrintF("Messages", "A signed 8-bit value: %bd (should be -1)", -1);
\r
474 vTraceStoreUserEventChannelName("Timer");
\r
476 sensorQ = xQueueCreate(15, sizeof(QueueMessage) );
\r
479 vTracePrint("Messages", "Could not create SensorQ!\n");
\r
482 vTraceSetQueueName(sensorQ, "SensorQueue");
\r
484 actuatorQ = xQueueCreate(3, sizeof(QueueMessage) );
\r
485 if( actuatorQ == 0 )
\r
487 vTracePrint("Messages", "Could not create ActuatorQ!\n");
\r
490 vTraceSetQueueName(actuatorQ, "ActuatorQueue");
\r
492 vSemaphoreCreateBinary(Sem1);
\r
495 vTracePrint("Messages", "Could not create Sem1!\n");
\r
498 vTraceSetSemaphoreName(Sem1, "SemaphSenX");
\r
500 vSemaphoreCreateBinary(Sem2);
\r
503 vTracePrint("Messages", "Could not create Sem2!\n");
\r
506 vTraceSetSemaphoreName(Sem2, "SemaphSenY");
\r
508 vSemaphoreCreateBinary(Sem3);
\r
511 vTracePrint("Messages", "Could not create Sem3!\n");
\r
514 vTraceSetSemaphoreName(Sem3, "SemaphSenZ");
\r
516 xTaskCreate( trcDemoTaskSensor, "SensorX",
\r
517 configMINIMAL_STACK_SIZE*2, &sensorTaskID1, 8, &objectHandle );
\r
518 if (objectHandle == NULL)
\r
523 xTaskCreate( trcDemoTaskSensor, "SensorY",
\r
524 configMINIMAL_STACK_SIZE*2, &sensorTaskID2, 7, &objectHandle );
\r
525 if (objectHandle == NULL)
\r
530 xTaskCreate( trcDemoTaskSensor, "SensorZ",
\r
531 configMINIMAL_STACK_SIZE*2, &sensorTaskID3, 6, &objectHandle );
\r
532 if (objectHandle == NULL)
\r
537 xTaskCreate( trcDemoTaskController, "Control",
\r
538 configMINIMAL_STACK_SIZE*2, NULL, 4, &objectHandle );
\r
539 if (objectHandle == NULL)
\r
544 xTaskCreate( trcDemoTaskActuator, "Actuator",
\r
545 configMINIMAL_STACK_SIZE*2, NULL, 5, &objectHandle );
\r
546 if (objectHandle == NULL)
\r
551 xTaskCreate( trcDemoTaskSuperv, "Superv",
\r
552 configMINIMAL_STACK_SIZE*2, NULL, 3, &objectHandle );
\r
553 if (objectHandle == NULL)
\r
558 xTaskCreate( trcDemoISR, "(Hide)FakeISR",
\r
559 configMINIMAL_STACK_SIZE*2, NULL, configMAX_PRIORITIES-1, &objectHandle);
\r
560 if (objectHandle == NULL)
\r