Files
lab-rv32i-freertos-c-queue/src/tasks/task01_queue.c
T

289 lines
8.4 KiB
C

#include <stddef.h>
#include <stdint.h>
#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 );
}