#include #include #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 ); }