275 lines
8.1 KiB
C
275 lines
8.1 KiB
C
#include <stddef.h>
|
|
#include <stdint.h>
|
|
|
|
#include "FreeRTOS.h"
|
|
#include "task.h"
|
|
#include "timers.h"
|
|
#include "lab_freertos.h"
|
|
#include "lab_io.h"
|
|
#include "task01_software_timers.h"
|
|
|
|
#define FC06_ACTOR_MAIN 1U
|
|
#define FC06_ACTOR_CONTROLLER 2U
|
|
#define FC06_ACTOR_DAEMON 3U
|
|
#define FC06_ACTOR_VERIFIER 4U
|
|
|
|
TimerExperiment g_fc06;
|
|
TimerEvidence g_fc06_events[ FC06_EVENT_CAPACITY ];
|
|
volatile uint32_t g_fc06_event_count;
|
|
volatile uint32_t g_fc06_last_checkpoint;
|
|
volatile uint32_t g_fc06_pass;
|
|
|
|
static uintptr_t read_sp( void )
|
|
{
|
|
uintptr_t value;
|
|
__asm__ volatile( "mv %0, sp" : "=r"( value ) );
|
|
return value;
|
|
}
|
|
|
|
__attribute__( ( noinline, used ) )
|
|
void fc06_checkpoint_committed( uint32_t point, const void * subject )
|
|
{
|
|
( void ) point;
|
|
( void ) subject;
|
|
__asm__ volatile( "" ::: "memory" );
|
|
}
|
|
|
|
static void fc06_publish( uint32_t point,
|
|
uint32_t actor,
|
|
uint32_t value,
|
|
const void * subject )
|
|
{
|
|
UBaseType_t state;
|
|
uint32_t index;
|
|
TimerEvidence * event;
|
|
|
|
state = taskENTER_CRITICAL_FROM_ISR();
|
|
index = g_fc06_event_count;
|
|
if( index >= FC06_EVENT_CAPACITY )
|
|
{
|
|
taskEXIT_CRITICAL_FROM_ISR( state );
|
|
lab_fail( 0xFC060001U );
|
|
}
|
|
event = &g_fc06_events[ index ];
|
|
event->sequence = index + 1U;
|
|
event->event = point;
|
|
event->tick = ( uint32_t ) xTaskGetTickCount();
|
|
event->actor = actor;
|
|
event->value = value;
|
|
__asm__ volatile( "" ::: "memory" );
|
|
event->committed = 0xFC060000U | ( index + 1U );
|
|
g_fc06_event_count = index + 1U;
|
|
g_fc06_last_checkpoint = point;
|
|
taskEXIT_CRITICAL_FROM_ISR( state );
|
|
fc06_checkpoint_committed( point, subject );
|
|
}
|
|
|
|
__attribute__( ( noinline, used ) )
|
|
void fc06_timer_callback( TimerHandle_t timer )
|
|
{
|
|
TimerTag * tag = ( TimerTag * ) pvTimerGetTimerID( timer );
|
|
TickType_t tick = xTaskGetTickCount();
|
|
|
|
if( tag == NULL || tag->marker != 0xFC0600A5U )
|
|
{
|
|
lab_fail( 0xFC060101U );
|
|
}
|
|
g_fc06.daemon_seen = xTimerGetTimerDaemonTaskHandle();
|
|
g_fc06.callback_sp = read_sp();
|
|
|
|
if( tag->kind == FC06_TIMER_AUTO )
|
|
{
|
|
uint32_t index = g_fc06.auto_count;
|
|
if( index >= 3U )
|
|
{
|
|
lab_fail( 0xFC060102U );
|
|
}
|
|
g_fc06.auto_tick[ index ] = ( uint32_t ) tick;
|
|
g_fc06.auto_count = index + 1U;
|
|
fc06_publish( index == 0U ? 4U : ( index == 1U ? 5U : 8U ),
|
|
FC06_ACTOR_DAEMON,
|
|
( uint32_t ) tick,
|
|
timer );
|
|
}
|
|
else if( tag->kind == FC06_TIMER_ONE_SHOT )
|
|
{
|
|
++g_fc06.one_shot_count;
|
|
g_fc06.one_shot_tick = ( uint32_t ) tick;
|
|
fc06_publish( 7U,
|
|
FC06_ACTOR_DAEMON,
|
|
( uint32_t ) tick,
|
|
timer );
|
|
}
|
|
else
|
|
{
|
|
lab_fail( 0xFC060103U );
|
|
}
|
|
}
|
|
|
|
__attribute__( ( noinline, used ) )
|
|
void fc06_controller_entry( void * context )
|
|
{
|
|
TimerExperiment * experiment = ( TimerExperiment * ) context;
|
|
TickType_t started;
|
|
|
|
if( experiment == NULL )
|
|
{
|
|
lab_fail( 0xFC060201U );
|
|
}
|
|
experiment->controller_sp = read_sp();
|
|
started = xTaskGetTickCount();
|
|
|
|
experiment->start_accepted =
|
|
( xTimerStart( experiment->one_shot, 0U ) == pdPASS ) &&
|
|
( xTimerStart( experiment->automatic, 0U ) == pdPASS );
|
|
fc06_publish( 2U,
|
|
FC06_ACTOR_CONTROLLER,
|
|
experiment->start_accepted,
|
|
experiment );
|
|
|
|
vTaskDelay( 1U );
|
|
experiment->reset_accepted =
|
|
xTimerReset( experiment->one_shot, 0U ) == pdPASS;
|
|
fc06_publish( 3U,
|
|
FC06_ACTOR_CONTROLLER,
|
|
experiment->reset_accepted,
|
|
experiment->one_shot );
|
|
|
|
while( experiment->auto_count < 2U )
|
|
{
|
|
if( ( xTaskGetTickCount() - started ) > FC06_TIMEOUT_TICKS )
|
|
{
|
|
lab_fail( 0xFC060202U );
|
|
}
|
|
vTaskDelay( 1U );
|
|
}
|
|
|
|
experiment->change_accepted =
|
|
xTimerChangePeriod( experiment->automatic, 3U, 0U ) == pdPASS;
|
|
fc06_publish( 6U,
|
|
FC06_ACTOR_CONTROLLER,
|
|
experiment->change_accepted,
|
|
experiment->automatic );
|
|
|
|
while( experiment->one_shot_count < 1U || experiment->auto_count < 3U )
|
|
{
|
|
if( ( xTaskGetTickCount() - started ) > FC06_TIMEOUT_TICKS )
|
|
{
|
|
lab_fail( 0xFC060203U );
|
|
}
|
|
vTaskDelay( 1U );
|
|
}
|
|
|
|
experiment->stop_accepted =
|
|
xTimerStop( experiment->automatic, 0U ) == pdPASS;
|
|
experiment->controller_done = 1U;
|
|
fc06_publish( 9U,
|
|
FC06_ACTOR_CONTROLLER,
|
|
experiment->stop_accepted,
|
|
experiment->automatic );
|
|
vTaskDelete( NULL );
|
|
lab_fail( 0xFC060204U );
|
|
}
|
|
|
|
__attribute__( ( noinline, used ) )
|
|
void fc06_verifier_entry( void * context )
|
|
{
|
|
TimerExperiment * experiment = ( TimerExperiment * ) context;
|
|
TickType_t started;
|
|
|
|
if( experiment == NULL )
|
|
{
|
|
lab_fail( 0xFC060301U );
|
|
}
|
|
started = xTaskGetTickCount();
|
|
while( experiment->controller_done == 0U )
|
|
{
|
|
if( ( xTaskGetTickCount() - started ) > FC06_TIMEOUT_TICKS )
|
|
{
|
|
lab_fail( 0xFC060302U );
|
|
}
|
|
vTaskDelay( 1U );
|
|
}
|
|
|
|
experiment->pass =
|
|
experiment->start_accepted != 0U &&
|
|
experiment->reset_accepted != 0U &&
|
|
experiment->change_accepted != 0U &&
|
|
experiment->stop_accepted != 0U &&
|
|
experiment->one_shot_count == 1U &&
|
|
experiment->auto_count == 3U &&
|
|
fc06_timeline_is_exact( experiment->auto_tick,
|
|
experiment->one_shot_tick ) != 0 &&
|
|
experiment->daemon_seen == xTimerGetTimerDaemonTaskHandle() &&
|
|
experiment->daemon_seen != experiment->controller &&
|
|
experiment->callback_sp != experiment->controller_sp &&
|
|
g_fc06_event_count == 9U;
|
|
g_fc06_pass = experiment->pass;
|
|
fc06_publish( 10U,
|
|
FC06_ACTOR_VERIFIER,
|
|
experiment->pass,
|
|
experiment );
|
|
experiment->digest = fc06_digest( g_fc06_events, g_fc06_event_count );
|
|
|
|
if( experiment->pass == 0U )
|
|
{
|
|
lab_fail( 0xFC060303U );
|
|
}
|
|
lab_puts( "PASS FC06: one-shot reset, auto-reload period change, daemon\n" );
|
|
lab_put_u32( experiment->digest );
|
|
lab_exit( 0U );
|
|
}
|
|
|
|
static TaskHandle_t fc06_create_task( TaskFunction_t entry,
|
|
const char * name,
|
|
UBaseType_t priority )
|
|
{
|
|
TaskHandle_t handle = NULL;
|
|
if( xTaskCreate( entry,
|
|
name,
|
|
FC06_TASK_STACK_WORDS,
|
|
&g_fc06,
|
|
priority,
|
|
&handle ) != pdPASS )
|
|
{
|
|
lab_fail( 0xFC060401U + priority );
|
|
}
|
|
return handle;
|
|
}
|
|
|
|
int main( void )
|
|
{
|
|
lab_heap_initialize();
|
|
g_fc06.one_shot_tag.kind = FC06_TIMER_ONE_SHOT;
|
|
g_fc06.one_shot_tag.marker = 0xFC0600A5U;
|
|
g_fc06.automatic_tag.kind = FC06_TIMER_AUTO;
|
|
g_fc06.automatic_tag.marker = 0xFC0600A5U;
|
|
fc06_publish( 1U, FC06_ACTOR_MAIN, configTIMER_QUEUE_LENGTH, &g_fc06 );
|
|
|
|
g_fc06.one_shot = xTimerCreate( "one-shot",
|
|
5U,
|
|
pdFALSE,
|
|
&g_fc06.one_shot_tag,
|
|
fc06_timer_callback );
|
|
g_fc06.automatic = xTimerCreate( "auto",
|
|
2U,
|
|
pdTRUE,
|
|
&g_fc06.automatic_tag,
|
|
fc06_timer_callback );
|
|
if( g_fc06.one_shot == NULL || g_fc06.automatic == NULL )
|
|
{
|
|
lab_fail( 0xFC060405U );
|
|
}
|
|
|
|
g_fc06.controller =
|
|
fc06_create_task( fc06_controller_entry,
|
|
"controller",
|
|
FC06_CONTROLLER_PRIORITY );
|
|
g_fc06.verifier =
|
|
fc06_create_task( fc06_verifier_entry,
|
|
"verifier",
|
|
FC06_VERIFIER_PRIORITY );
|
|
vTaskStartScheduler();
|
|
lab_fail( 0xFC060406U );
|
|
}
|