#include #include #include "FreeRTOS.h" #include "queue.h" #include "task.h" #include "lab_freertos.h" #include "lab_io.h" #include "task01_queue.h" #include "task01_queue_model.h" #define FC05_ACTOR_MAIN 1U #define FC05_ACTOR_RECEIVER 2U #define FC05_ACTOR_SENDER 3U #define FC05_ACTOR_VERIFIER 4U QueueExperiment g_fc05; QueueEvidence g_fc05_events[ FC05_EVENT_CAPACITY ]; volatile uint32_t g_fc05_event_count; volatile uint32_t g_fc05_last_checkpoint; volatile uint32_t g_fc05_pass; static uintptr_t read_sp( void ) { uintptr_t value; __asm__ volatile( "mv %0, sp" : "=r"( value ) ); return value; } __attribute__( ( noinline, used ) ) void fc05_checkpoint_committed( uint32_t point, const void * subject ) { ( void ) point; ( void ) subject; __asm__ volatile( "" ::: "memory" ); } static void fc05_publish( uint32_t point, uint32_t actor, uint32_t value, const void * subject ) { UBaseType_t critical_state; uint32_t index; QueueEvidence * event; critical_state = taskENTER_CRITICAL_FROM_ISR(); index = g_fc05_event_count; if( index >= FC05_EVENT_CAPACITY ) { taskEXIT_CRITICAL_FROM_ISR( critical_state ); lab_fail( 0xFC050001U ); } event = &g_fc05_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 = 0xFC050000U | ( index + 1U ); g_fc05_event_count = index + 1U; g_fc05_last_checkpoint = point; taskEXIT_CRITICAL_FROM_ISR( critical_state ); fc05_checkpoint_committed( point, subject ); } static QueueMessage fc05_message( uint32_t sequence, uint32_t payload ) { QueueMessage message; message.sequence = sequence; message.payload = payload; message.checksum = fc05_message_checksum( sequence, payload ); return message; } __attribute__( ( noinline, used ) ) void fc05_receiver_entry( void * context ) { QueueExperiment * experiment = ( QueueExperiment * ) context; if( experiment == NULL ) { lab_fail( 0xFC050101U ); } experiment->receiver_sp = read_sp(); fc05_publish( 2U, FC05_ACTOR_RECEIVER, 0U, experiment ); if( xQueueReceive( experiment->queue, &experiment->received[ 0 ], portMAX_DELAY ) != pdPASS ) { lab_fail( 0xFC050102U ); } fc05_publish( 4U, FC05_ACTOR_RECEIVER, experiment->received[ 0 ].payload, &experiment->received[ 0 ] ); vTaskDelay( 2U ); experiment->sender_state_when_full = eTaskGetState( experiment->sender_handle ); experiment->waiting_when_full = uxQueueMessagesWaiting( experiment->queue ); fc05_publish( 6U, FC05_ACTOR_RECEIVER, ( uint32_t ) experiment->sender_state_when_full, experiment ); if( xQueueReceive( experiment->queue, &experiment->received[ 1 ], 0U ) != pdPASS ) { lab_fail( 0xFC050103U ); } fc05_publish( 7U, FC05_ACTOR_RECEIVER, experiment->received[ 1 ].payload, &experiment->received[ 1 ] ); if( xQueueReceive( experiment->queue, &experiment->received[ 2 ], portMAX_DELAY ) != pdPASS ) { lab_fail( 0xFC050104U ); } fc05_publish( 8U, FC05_ACTOR_RECEIVER, experiment->received[ 2 ].payload, &experiment->received[ 2 ] ); experiment->receiver_done = 1U; experiment->receiver_handle = NULL; vTaskDelete( NULL ); lab_fail( 0xFC050105U ); } __attribute__( ( noinline, used ) ) void fc05_sender_entry( void * context ) { QueueExperiment * experiment = ( QueueExperiment * ) context; QueueMessage source; if( experiment == NULL ) { lab_fail( 0xFC050201U ); } experiment->sender_sp = read_sp(); source = fc05_message( 1U, 0x1111U ); fc05_publish( 3U, FC05_ACTOR_SENDER, source.payload, &source ); if( xQueueSend( experiment->queue, &source, portMAX_DELAY ) != pdPASS ) { lab_fail( 0xFC050202U ); } source = fc05_message( 2U, 0x2222U ); if( xQueueSend( experiment->queue, &source, portMAX_DELAY ) != pdPASS ) { lab_fail( 0xFC050203U ); } source.payload = 0xDEADU; source.checksum = fc05_message_checksum( source.sequence, source.payload ); experiment->mutated_source = source; fc05_publish( 5U, FC05_ACTOR_SENDER, uxQueueMessagesWaiting( experiment->queue ), &experiment->mutated_source ); source = fc05_message( 3U, 0x3333U ); if( xQueueSend( experiment->queue, &source, portMAX_DELAY ) != pdPASS ) { lab_fail( 0xFC050204U ); } fc05_publish( 9U, FC05_ACTOR_SENDER, source.payload, &source ); experiment->sender_done = 1U; experiment->sender_handle = NULL; vTaskDelete( NULL ); lab_fail( 0xFC050205U ); } static int fc05_messages_are_correct( const QueueExperiment * experiment ) { return fc05_message_is_valid( &experiment->received[ 0 ] ) != 0 && fc05_message_is_valid( &experiment->received[ 1 ] ) != 0 && fc05_message_is_valid( &experiment->received[ 2 ] ) != 0 && experiment->received[ 0 ].sequence == 1U && experiment->received[ 0 ].payload == 0x1111U && experiment->received[ 1 ].sequence == 2U && experiment->received[ 1 ].payload == 0x2222U && experiment->received[ 2 ].sequence == 3U && experiment->received[ 2 ].payload == 0x3333U && experiment->mutated_source.payload == 0xDEADU; } __attribute__( ( noinline, used ) ) void fc05_verifier_entry( void * context ) { QueueExperiment * experiment = ( QueueExperiment * ) context; TickType_t started; if( experiment == NULL ) { lab_fail( 0xFC050301U ); } started = xTaskGetTickCount(); while( experiment->receiver_done == 0U || experiment->sender_done == 0U ) { if( ( xTaskGetTickCount() - started ) > FC05_TIMEOUT_TICKS ) { lab_fail( 0xFC050302U ); } vTaskDelay( 1U ); } experiment->pass = fc05_messages_are_correct( experiment ) != 0 && experiment->sender_state_when_full == eBlocked && experiment->waiting_when_full == 1U && experiment->receiver_sp != experiment->sender_sp && g_fc05_event_count == 9U; g_fc05_pass = experiment->pass; fc05_publish( 10U, FC05_ACTOR_VERIFIER, experiment->pass, experiment ); experiment->evidence_digest = fc05_digest( g_fc05_events, g_fc05_event_count ); if( experiment->pass == 0U ) { lab_fail( 0xFC050303U ); } lab_puts( "PASS FC05: queue empty/full blocking, FIFO, byte copy\n" ); lab_put_u32( experiment->evidence_digest ); lab_exit( 0U ); } static TaskHandle_t fc05_create_task( TaskFunction_t entry, const char * name, UBaseType_t priority ) { TaskHandle_t handle = NULL; if( xTaskCreate( entry, name, FC05_TASK_STACK_WORDS, &g_fc05, priority, &handle ) != pdPASS ) { lab_fail( 0xFC050401U + priority ); } return handle; } int main( void ) { lab_heap_initialize(); fc05_publish( 1U, FC05_ACTOR_MAIN, FC05_QUEUE_LENGTH, &g_fc05 ); g_fc05.queue = xQueueCreate( FC05_QUEUE_LENGTH, sizeof( QueueMessage ) ); if( g_fc05.queue == NULL ) { lab_fail( 0xFC050402U ); } g_fc05.receiver_handle = fc05_create_task( fc05_receiver_entry, "receiver", FC05_RECEIVER_PRIORITY ); g_fc05.sender_handle = fc05_create_task( fc05_sender_entry, "sender", FC05_SENDER_PRIORITY ); g_fc05.verifier_handle = fc05_create_task( fc05_verifier_entry, "verifier", FC05_VERIFIER_PRIORITY ); vTaskStartScheduler(); lab_fail( 0xFC050403U ); }