/******************************************************************************* | |
* Tracealyzer v3.0.0 Demo Application | |
* Percepio AB, www.percepio.com | |
* | |
* traceDemoApp.c | |
* | |
* Demo application for Tracealyzer demo project. | |
* | |
* Terms of Use | |
* This software is copyright Percepio AB. The recorder library is free for | |
* use together with Percepio products. You may distribute the recorder library | |
* in its original form, including modifications in trcHardwarePort.c/.h | |
* given that these modification are clearly marked as your own modifications | |
* and documented in the initial comment section of these source files. | |
* This software is the intellectual property of Percepio AB and may not be | |
* sold or in other ways commercially redistributed without explicit written | |
* permission by Percepio AB. | |
* | |
* Disclaimer | |
* The trace tool and recorder library is being delivered to you AS IS and | |
* Percepio AB makes no warranty as to its use or performance. Percepio AB does | |
* not and cannot warrant the performance or results you may obtain by using the | |
* software or documentation. Percepio AB make no warranties, express or | |
* implied, as to noninfringement of third party rights, merchantability, or | |
* fitness for any particular purpose. In no event will Percepio AB, its | |
* technology partners, or distributors be liable to you for any consequential, | |
* incidental or special damages, including any lost profits or lost savings, | |
* even if a representative of Percepio AB has been advised of the possibility | |
* of such damages, or for any claim by any third party. Some jurisdictions do | |
* not allow the exclusion or limitation of incidental, consequential or special | |
* damages, or the exclusion of implied warranties or limitations on how long an | |
* implied warranty may last, so the above limitations may not apply to you. | |
* | |
* Tabs are used for indent in this file (1 tab = 4 spaces) | |
* | |
* Copyright Percepio AB, 2014. | |
* www.percepio.com | |
******************************************************************************/ | |
/* Standard includes. */ | |
#include <stdio.h> | |
#include <stdint.h> | |
/* Kernel includes. */ | |
#include <FreeRTOS.h> | |
#include "task.h" | |
#include "queue.h" | |
#include "semphr.h" | |
#if (configUSE_TIMERS == 1) | |
#include "timers.h" | |
#endif | |
#include "trcRecorder.h" | |
#define ISR3_PERIOD 18 | |
#define ISR2_PERIOD 24 | |
#define ISR1_PERIOD 30 | |
#define EXECTIME_CONTROLLER 1 | |
#define EXECTIME_SUPERV 2 | |
#define EXECTIME_SENSOR 1 | |
typedef struct | |
{ | |
int32_t code; | |
int32_t value; | |
char data[512]; // Makes the Memory Heap Utilization graph more interresting! | |
} QueueMessage; | |
#define MSGCODE_SENSOR_VALUE 1 | |
#define MSGCODE_CONTROL_VALUE 10 | |
#define MSGCODE_CONTROL_DEFAULT_VALUE 99 | |
static portTASK_FUNCTION_PROTO( trcDemoTaskSensor, pvParameters ); | |
static portTASK_FUNCTION_PROTO( trcDemoTaskActuator, pvParameters ); | |
static portTASK_FUNCTION_PROTO( trcDemoTaskController, pvParameters ); | |
static portTASK_FUNCTION( trcDemoTaskSuperv, pvParameters ); | |
static portTASK_FUNCTION( trcDemoISR, pvParameters ); | |
#if (configUSE_TIMERS == 1) | |
xTimerHandle timer; | |
void myTimerHandler(xTimerHandle tmr); | |
#endif | |
xQueueHandle sensorQ, actuatorQ; | |
xSemaphoreHandle Sem1, Sem2, Sem3; | |
void doSomeWork(uint32_t n); | |
int readSensor(int i); | |
/****************************************************************************** | |
* doSomeWork | |
* | |
* Performs a busy wait for X milliseconds. Used to generate suitable execution | |
* times in the demo application, in a portable way. | |
******************************************************************************/ | |
void doSomeWork(uint32_t ms) | |
{ | |
portTickType old = xTaskGetTickCount(); | |
portTickType new = 0; | |
while (ms > 0) | |
{ | |
new = xTaskGetTickCount(); | |
if (old < new) | |
{ | |
/* If uiTraceTickCount has changed, we only reduce 1ms of the wait | |
time. This way we do not count time that this task has waited | |
for other tasks. This will result in somewhat correct execution | |
times. */ | |
old = new; | |
ms--; | |
} | |
} | |
} | |
/****************************************************************************** | |
* readSensor | |
* | |
* Simulates a set of sensors/inputs, using a simple physics simulation. | |
* The values are intentionally ints (rather than floats) to avoid very slow | |
* execution times on chips without hardware floating point support. | |
******************************************************************************/ | |
int readSensor(int i) | |
{ | |
static int pos[3] = {40, 80, 120}; | |
static int speed[3] = {0, 0, -3}; | |
static int acc[3] = {0, 0, 0}; | |
i--; | |
acc[i] = (-pos[i] >> 3); | |
speed[i] += acc[i]; | |
pos[i] += speed[i]; | |
return (int)pos[i]; | |
} | |
/****************************************************************************** | |
* trcDemoTaskSensor | |
* | |
* The "Sensor" tasks (three instances of this code). Reads data using | |
* "readSensor" when trigged by the timer interrupt through a semaphore. | |
******************************************************************************/ | |
static portTASK_FUNCTION( trcDemoTaskSensor, pvParameters ) | |
{ | |
char name[30] = "SensorX\0"; | |
QueueMessage sensorReading; | |
unsigned char idx = (unsigned char)(*(int*)pvParameters); | |
xSemaphoreHandle mySem = NULL; | |
/* Change 'X' to the index */ | |
name[6] = '0' + idx; | |
switch (idx) | |
{ | |
case 1: mySem = Sem1; break; | |
case 2: mySem = Sem2; break; | |
case 3: mySem = Sem3; break; | |
} | |
vTraceStoreUserEventChannelName(name); | |
/* Initialize xNextWakeTime - this only needs to be done once. */ | |
sensorReading.value = 0; | |
sensorReading.code = 0; | |
for( ;; ) | |
{ | |
xSemaphoreTake(mySem, 0xFFFFFFFF); | |
sensorReading.code = idx; | |
sensorReading.value = readSensor(idx); | |
doSomeWork(EXECTIME_SENSOR); | |
vTracePrintF(name , "Sending msg %d", sensorReading.value); | |
if (xQueueSend(sensorQ, &sensorReading, 1) != pdTRUE) | |
{ | |
vTracePrint(name, "Sensor queue full. Sample dropped!"); | |
} | |
vTraceInstanceFinishedNow(); | |
} | |
} | |
/****************************************************************************** | |
* trcDemoTaskSuperv | |
* | |
* The "Supervisor" task. Performs no action in the simulation, apart from | |
* preempting other tasks in the scheduling. | |
******************************************************************************/ | |
static portTASK_FUNCTION( trcDemoTaskSuperv, pvParameters ) | |
{ | |
int counter = 0; | |
#if (configUSE_TIMERS == 1) | |
static int timerState = 0; | |
#endif | |
portTickType xNextWakeTime; | |
(void)pvParameters; | |
xNextWakeTime = xTaskGetTickCount(); | |
#if (configUSE_TIMERS == 1) | |
timer = xTimerCreate("Tmr5", 5, 1, (void*)42, myTimerHandler); | |
xTimerChangePeriod(timer, 10, 0); | |
#endif | |
for( ;; ) | |
{ | |
vTaskDelayUntil( &xNextWakeTime, 40); | |
counter = (counter + 1) % 16; | |
if (counter == 8) vTaskPrioritySet(NULL, 2); | |
if (counter == 0) vTaskPrioritySet(NULL, 3); | |
doSomeWork(EXECTIME_SUPERV); | |
#if (configUSE_TIMERS == 1) | |
if (timerState == 0) | |
{ | |
xTimerStart(timer, 0); | |
timerState = 1; | |
} | |
else if (timerState == 1) | |
{ | |
xTimerStop(timer, 0); | |
timerState = 0; | |
} | |
#endif | |
} | |
} | |
/****************************************************************************** | |
* trcDemoTaskController | |
* | |
* The "Controller" task. Periodically reads all accumulated messages in SensorQ | |
* (i.e., those produced by the Sensor tasks since the last execution of | |
* the Controller task). Calculates their mean value and send this to Actuator. | |
******************************************************************************/ | |
static portTASK_FUNCTION( trcDemoTaskController, pvParameters ) | |
{ | |
portTickType xNextWakeTime; | |
QueueMessage* sensorReading; | |
QueueMessage actuatorMessage; | |
int32_t sum[4]; | |
int32_t count[4]; | |
(void)pvParameters; | |
vTraceStoreUserEventChannelName("UE TEST"); | |
/* Initialize xNextWakeTime - this only needs to be done once. */ | |
xNextWakeTime = xTaskGetTickCount(); | |
for(;;) | |
{ | |
sum[1] = 0; | |
sum[2] = 0; | |
sum[3] = 0; | |
count[1] = 0; | |
count[2] = 0; | |
count[3] = 0; | |
vTaskDelayUntil(&xNextWakeTime, 60); | |
for(;;) | |
{ | |
// To demostrate malloc/free tracing | |
sensorReading = ( QueueMessage * ) pvPortMalloc( sizeof( QueueMessage ) ); | |
if (xQueueReceive(sensorQ, sensorReading, 0) != pdTRUE) | |
{ | |
vPortFree(sensorReading); | |
break; | |
} | |
else | |
{ | |
if (sensorReading->code >= 1 && sensorReading->code <= 3) | |
{ | |
sum[sensorReading->code] += sensorReading->value; | |
count[sensorReading->code]++; | |
} | |
} | |
doSomeWork(EXECTIME_CONTROLLER); | |
//vTracePrintF(0, "0x%4x", 111); | |
//vTracePrintF(0, "0x%04x", 111); | |
//vTracePrintF(0, "0x%4X", 111); | |
//vTracePrintF(0, "0x%04X", 111); | |
// | |
//vTracePrint(0, "123456789012345678901234567890123456789012345678901234567890"); | |
//vTracePrint("UE TEST", "1234567890123456789012345678901234567890123456789012345"); | |
//vTracePrint("UE TEST", "12345678901234567890123456789012345678901234567890123456"); | |
//vTracePrint("UE TEST", "123456789012345678901234567890123456789012345678901234567"); | |
//vTracePrint("UE TEST", "12345678901234567890123456789012345678901234567890"); | |
// | |
//vTracePrintF("UE TEST", "%5d", 42); | |
//vTracePrintF("UE TEST", "%05d", 42); | |
//vTracePrintF("UE TEST", "%5d", -42); | |
//vTracePrintF("UE TEST", "%05d", -42); | |
//vTracePrintF("UE TEST", "%05d", -1042); | |
//vTracePrintF("UE TEST", "%05d", -11042); | |
// | |
//vTracePrintF("UE TEST", "%5u", -1); | |
//vTracePrintF("UE TEST", "%05u", -1); | |
//vTracePrintF("UE TEST", "%5u", 10); | |
//vTracePrintF("UE TEST", "%05u", 10); | |
// | |
//vTracePrintF("UE TEST", "%5u", 11042); | |
//vTracePrintF("UE TEST", "%05u", 11042); | |
// | |
//vTracePrintF("UE TEST", "%5u", 111042); | |
//vTracePrintF("UE TEST", "%05u", 111042); | |
// | |
//vTracePrintF("UE TEST", "%15d", 111042); | |
//vTracePrintF("UE TEST", "%015d", 111042); | |
vPortFree(sensorReading); | |
vTraceInstanceFinishedNow(); | |
} | |
actuatorMessage.code = MSGCODE_CONTROL_VALUE; | |
actuatorMessage.value = 0; | |
if (count[1] > 0) | |
actuatorMessage.value += (int32_t)(0.5 * sum[1]/count[1]); | |
if (count[2] > 0) | |
actuatorMessage.value += (int32_t)(0.25 * sum[2]/count[2]); | |
if (count[3] > 0) | |
actuatorMessage.value += (int32_t)(0.25 * sum[3]/count[3]); | |
xQueueSend(actuatorQ, &actuatorMessage, 10000); | |
} | |
} | |
/****************************************************************************** | |
* trcDemoISR | |
* | |
* The "FakeISR" task, that simulates the ISRTimer interrupts, which triggers | |
* the Sensor tasks. | |
******************************************************************************/ | |
static portTASK_FUNCTION( trcDemoISR, pvParameters ) | |
{ | |
portTickType xNextWakeTime; | |
portBASE_TYPE dummy; | |
int i = 0; | |
(void)pvParameters; | |
/* Initialize xNextWakeTime - this only needs to be done once. */ | |
xNextWakeTime = xTaskGetTickCount(); | |
vTraceSetISRProperties("ISRTimer1", 3); | |
vTraceSetISRProperties("ISRTimer2", 2); | |
vTraceSetISRProperties("ISRTimer3", 1); | |
vTaskDelayUntil( &xNextWakeTime, 1); | |
for( ;; ) | |
{ | |
i++; | |
if (i % ISR3_PERIOD == 0) | |
{ | |
portENTER_CRITICAL(); | |
vTraceStoreISRBegin((void*)"ISRTimer3"); | |
xSemaphoreGiveFromISR(Sem3, &dummy); | |
vTraceStoreISREndManual(dummy); | |
portEXIT_CRITICAL(); | |
} | |
if (i % ISR2_PERIOD == 0) | |
{ | |
portENTER_CRITICAL(); | |
vTraceStoreISRBegin((void*)"ISRTimer2"); | |
xSemaphoreGiveFromISR(Sem2, &dummy); | |
vTraceStoreISREndManual(dummy); | |
portEXIT_CRITICAL(); | |
} | |
if (i % ISR1_PERIOD == 0) | |
{ | |
portENTER_CRITICAL(); | |
vTraceStoreISRBegin((void*)"ISRTimer1"); | |
xSemaphoreGiveFromISR(Sem1, &dummy); | |
vTraceStoreISREndManual(dummy); | |
portEXIT_CRITICAL(); | |
} | |
vTaskDelayUntil( &xNextWakeTime, 1); | |
} | |
} | |
/****************************************************************************** | |
* trcDemoTaskActuator | |
* | |
* The "Actuator" task, just reads the data from Controller and logs it in a | |
* User Event (i.e., the "vTracePrintF" calls). | |
******************************************************************************/ | |
static portTASK_FUNCTION( trcDemoTaskActuator, pvParameters ) | |
{ | |
QueueMessage inMessage; | |
(void)pvParameters; | |
vTraceStoreUserEventChannelName("Actuator Out Signal"); | |
for( ;; ) | |
{ | |
vTraceInstanceFinishedNow(); | |
/* Place this task in blocked state until it is time to run again. */ | |
if (xQueueReceive(actuatorQ, &inMessage, 35) != pdTRUE) | |
{ | |
vTracePrintF("Actuator Out Signal", "No data..."); | |
} | |
else | |
{ | |
if (inMessage.code == MSGCODE_CONTROL_VALUE) | |
{ | |
vTracePrintF("Actuator Out Signal", "Out: %d", | |
inMessage.value); | |
} | |
} | |
} | |
} | |
#if (configUSE_TIMERS == 1) | |
void myTimerHandler(xTimerHandle tmr) | |
{ | |
(void) tmr; | |
vTracePrintF("Timer", "Timer handler!"); | |
} | |
#endif | |
int sensorTaskID1 = 1; | |
int sensorTaskID2 = 2; | |
int sensorTaskID3 = 3; | |
#define vTaskCreateNotTraced( pvTaskCode, pcName, usStackDepth, pvParameters, uxPriority ) \ | |
{ void* this_pxCreatedTask; \ | |
vTraceSetReadyEventsEnabled(0); \ | |
xTaskGenericCreate( ( pvTaskCode ), ( pcName ), ( usStackDepth ), ( pvParameters ), ( uxPriority ), ( &this_pxCreatedTask ), ( NULL ), ( NULL ) ); \ | |
vTraceSetReadyEventsEnabled(1); \ | |
if (this_pxCreatedTask != NULL){ vTraceExcludeTaskFromTrace(this_pxCreatedTask); }else{ return -42;} } | |
/****************************************************************************** | |
* trcDemoTaskActuator | |
* | |
* The "Actuator" task, just reads the data from Controller and logs it in a | |
* User Event (i.e., the "vTracePrintF" calls). | |
******************************************************************************/ | |
int vStartDemoApplication(void) | |
{ | |
void* objectHandle = NULL; | |
vTraceStoreUserEventChannelName("Messages"); | |
vTracePrint("Messages", "Demo starting..."); | |
vTracePrint("Messages", "vTraceUserEvent creates basic User Events."); | |
vTracePrint("Messages", "vTracePrintF creates advanced user events, like printf"); | |
//vTracePrintF("Messages", "A float: %f (should be 1)", (float)1.0); | |
//vTracePrintF("Messages", "A double: %lf (should be 1)", (double)1.0); | |
//vTracePrintF("Messages", "A signed 8-bit value: %bd (should be -1)", -1); | |
vTraceStoreUserEventChannelName("Timer"); | |
sensorQ = xQueueCreate(15, sizeof(QueueMessage) ); | |
if( sensorQ == 0 ) | |
{ | |
vTracePrint("Messages", "Could not create SensorQ!\n"); | |
return -1; | |
} | |
vTraceSetQueueName(sensorQ, "SensorQueue"); | |
actuatorQ = xQueueCreate(3, sizeof(QueueMessage) ); | |
if( actuatorQ == 0 ) | |
{ | |
vTracePrint("Messages", "Could not create ActuatorQ!\n"); | |
return -2; | |
} | |
vTraceSetQueueName(actuatorQ, "ActuatorQueue"); | |
vSemaphoreCreateBinary(Sem1); | |
if( Sem1 == NULL ) | |
{ | |
vTracePrint("Messages", "Could not create Sem1!\n"); | |
return -3; | |
} | |
vTraceSetSemaphoreName(Sem1, "SemaphSenX"); | |
vSemaphoreCreateBinary(Sem2); | |
if( Sem2 == NULL ) | |
{ | |
vTracePrint("Messages", "Could not create Sem2!\n"); | |
return -4; | |
} | |
vTraceSetSemaphoreName(Sem2, "SemaphSenY"); | |
vSemaphoreCreateBinary(Sem3); | |
if( Sem3 == NULL ) | |
{ | |
vTracePrint("Messages", "Could not create Sem3!\n"); | |
return -5; | |
} | |
vTraceSetSemaphoreName(Sem3, "SemaphSenZ"); | |
xTaskCreate( trcDemoTaskSensor, "SensorX", | |
configMINIMAL_STACK_SIZE*2, &sensorTaskID1, 8, &objectHandle ); | |
if (objectHandle == NULL) | |
{ | |
return -6; | |
} | |
xTaskCreate( trcDemoTaskSensor, "SensorY", | |
configMINIMAL_STACK_SIZE*2, &sensorTaskID2, 7, &objectHandle ); | |
if (objectHandle == NULL) | |
{ | |
return -7; | |
} | |
xTaskCreate( trcDemoTaskSensor, "SensorZ", | |
configMINIMAL_STACK_SIZE*2, &sensorTaskID3, 6, &objectHandle ); | |
if (objectHandle == NULL) | |
{ | |
return -8; | |
} | |
xTaskCreate( trcDemoTaskController, "Control", | |
configMINIMAL_STACK_SIZE*2, NULL, 4, &objectHandle ); | |
if (objectHandle == NULL) | |
{ | |
return -9; | |
} | |
xTaskCreate( trcDemoTaskActuator, "Actuator", | |
configMINIMAL_STACK_SIZE*2, NULL, 5, &objectHandle ); | |
if (objectHandle == NULL) | |
{ | |
return -10; | |
} | |
xTaskCreate( trcDemoTaskSuperv, "Superv", | |
configMINIMAL_STACK_SIZE*2, NULL, 3, &objectHandle ); | |
if (objectHandle == NULL) | |
{ | |
return -11; | |
} | |
xTaskCreate( trcDemoISR, "(Hide)FakeISR", | |
configMINIMAL_STACK_SIZE*2, NULL, configMAX_PRIORITIES-1, &objectHandle); | |
if (objectHandle == NULL) | |
{ | |
return -12; | |
} | |
return 0; | |
} |