You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
567 lines
16 KiB
C
567 lines
16 KiB
C
/*******************************************************************************
|
|
* 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;
|
|
}
|