blob: 39f7ff88dd3415044410bbec7d655f0dd571f8be [file] [log] [blame]
/*******************************************************************************
* 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;
}