SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
copyrights:
- Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de)
enabled-by: true
functional-type: action
links:
- role: interface-function
uid: ../if/send
- role: interface-function
uid: ../if/urgent
post-conditions:
- name: Status
states:
- name: Ok
test-code: |
T_rsc_success( ctx->status );
text: |
The return status of the called directive (${../if/send:/name} or
${../if/urgent:/name}) shall be ${../../status/if/successful:/name}
- name: InvId
test-code: |
T_rsc( ctx->status, RTEMS_INVALID_ID );
text: |
The return status of the called directive (${../if/send:/name} or
${../if/urgent:/name}) shall be ${../../status/if/invalid-id:/name}.
- name: InvAddr
test-code: |
T_rsc( ctx->status, RTEMS_INVALID_ADDRESS );
text: |
The return status of the called directive (${../if/send:/name} or
${../if/urgent:/name}) shall be ${../../status/if/invalid-address:/name}.
- name: InvSize
test-code: |
T_rsc( ctx->status, RTEMS_INVALID_SIZE );
text: |
The return status of the called directive (${../if/send:/name} or
${../if/urgent:/name}) shall be ${../../status/if/invalid-size:/name}.
- name: TooMany
test-code: |
T_rsc( ctx->status, RTEMS_TOO_MANY );
text: |
The return status of the called directive (${../if/send:/name} or
${../if/urgent:/name}) shall be ${../../status/if/too-many:/name}.
test-epilogue: null
test-prologue: null
- name: MsgQueue
states:
- name: Empty
test-code: |
PopMessage( ctx, CheckForNoMessage );
text: |
The ${/glossary/messagequeue:/term} shall be empty after the
return of the ${../if/send:/name} or ${../if/urgent:/name} call.
- name: One
test-code: |
PopMessage( ctx, CheckForSendMessage );
PopMessage( ctx, CheckForNoMessage );
text: |
The ${/glossary/messagequeue:/term} shall contain only the send message
after the return of the ${../if/send:/name} or
${../if/urgent:/name} call.
- name: Prepend
test-code: |
PopMessage( ctx, CheckForSendMessage );
ctx->check_msgq_unchanged( ctx );
PopMessage( ctx, CheckForNoMessage );
text: |
The ${/glossary/messagequeue:/term} shall contain the message
send by the last call to ${../if/urgent:/name} as
${../glossary/firstmessage:/term} followed by all the messages
which were in the ${/glossary/messagequeue:/term} before that call
(in the same order and each message with the same content and size).
- name: Append
test-code: |
ctx->check_msgq_unchanged( ctx );
PopMessage( ctx, CheckForSendMessage );
PopMessage( ctx, CheckForNoMessage );
text: |
The ${/glossary/messagequeue:/term} shall contain the message
send by the last call to ${../if/send:/name} as
${../glossary/lastmessage:/term} preceded by all the messages
which were in the ${/glossary/messagequeue:/term} before that call
(in the same order and each message with the same content and size).
- name: Nop
test-code: |
ctx->check_msgq_unchanged( ctx );
PopMessage( ctx, CheckForNoMessage );
text: |
Objects referenced by the ${../if/send:/params[0]/name}
parameter in past call to ${../if/send:/name} or
${../if/urgent:/name} shall not be accessed by that
call (see also ${../glossary/nop:/term}).
test-epilogue: null
test-prologue: null
- name: Receiver
states:
- name: GotMsg
test-code: |
CheckForSendMessage(
ctx,
ctx->receive_status,
ctx->receive_buffer,
ctx->receive_size
);
text: |
The ${../glossary/receiver:/term} shall receive the message
send by the last call to the ${../if/send:/name} or
${../if/urgent:/name} directive.
- name: Waiting
test-code: |
T_rsc( ctx->receive_status, RTEMS_TIMEOUT );
text: |
The ${../glossary/receiver:/term} shall still wait to receive
a message after the last call to the ${../if/send:/name} or
${../if/urgent:/name} directive.
test-epilogue: null
test-prologue: null
pre-conditions:
- name: Buffer
states:
- name: Valid
test-code: |
uint8_t i;
for ( i = 0; i < MAXIMUM_MESSAGE_SIZE; ++i ) {
ctx->send_message[i] = 42 + i;
}
ctx->buffer_param = &ctx->send_message;
text: |
While the ${../if/send:/params[1]/name} parameter references a memory
area where the message to be sent is stored.
- name: 'Null'
test-code: |
ctx->buffer_param = NULL;
text: |
While the ${../if/send:/params[1]/name} parameter is ${/c/if/null:/name}.
test-epilogue: null
test-prologue: null
- name: Id
states:
- name: Valid
test-code: |
ctx->id_param = ctx->message_queue_id;
text: |
While the ${../if/send:/params[0]/name} parameter is valid.
- name: Invalid
test-code: |
ctx->id_param = RTEMS_ID_NONE;
text: |
While the ${../if/send:/params[0]/name} parameter is invalid.
test-epilogue: null
test-prologue: null
- name: Size
states:
- name: Zero
test-code: |
ctx->size_param = 0;
text: |
While the ${../if/send:/params[2]/name} parameter is 0.
- name: SomeSize
test-code: |
ctx->size_param = MAXIMUM_MESSAGE_SIZE / 2 + 1;
text: |
While the ${../if/send:/params[2]/name} parameter has a value
between 0 and the ${../glossary/maximummessagesize:/term}.
- name: MaxSize
test-code: |
ctx->size_param = MAXIMUM_MESSAGE_SIZE;
text: |
While the ${../if/send:/params[2]/name} parameter has a value
of the ${../glossary/maximummessagesize:/term}.
- name: TooLarge
test-code: |
ctx->size_param = MAXIMUM_MESSAGE_SIZE + 1;
text: |
While the ${../if/send:/params[2]/name} parameter has a value
greater than the ${../glossary/maximummessagesize:/term}.
test-epilogue: null
test-prologue: null
- name: MsgQueue
states:
- name: Empty
test-code: |
/* Message queue is already empty. */
ctx->check_msgq_unchanged = CheckForNoMessageInQueue;
text: |
While there is no message in the ${/glossary/messagequeue:/term}.
- name: One
test-code: |
SendMsg( ctx );
ctx->check_msgq_unchanged = CheckForOneMessageInQueue;
text: |
While there is exactly one message in the ${/glossary/messagequeue:/term}.
- name: Several
test-code: |
SendMsg( ctx );
SendMsg( ctx );
ctx->check_msgq_unchanged = CheckForSeveralMessagesInQueue;
text: |
While there are more than one and less than
${../glossary/maximumpendingmessages:/term} in the
${/glossary/messagequeue:/term}.
- name: Full
test-code: |
SendMsg( ctx );
SendMsg( ctx );
SendMsg( ctx );
ctx->check_msgq_unchanged = CheckForAllMessagesInQueue;
text: |
While there are ${../glossary/maximumpendingmessages:/term} in the
${/glossary/messagequeue:/term}.
test-epilogue: null
test-prologue: null
- name: Receiver
states:
- name: Waiting
test-code: |
ctx->is_receiver_waiting = true;
text: |
While a ${../glossary/receiver:/term} is waiting to receive a message.
- name: 'No'
test-code: |
ctx->is_receiver_waiting = false;
text: |
While no ${../glossary/receiver:/term} is waiting to receive a message.
test-epilogue: null
test-prologue: null
- name: Directive
states:
- name: Send
test-code: |
ctx->action = rtems_message_queue_send;
text: |
While the directive ${../if/send:/name} is called.
- name: Urgent
test-code: |
ctx->action = rtems_message_queue_urgent;
text: |
While the directive ${../if/urgent:/name} is called.
test-epilogue: null
test-prologue: null
- name: Storage
states:
- name: Nop
test-code: |
/* Only a requirement text. */
text: |
While the memory area to which a pointer is provided as member
${../if/config:/definition[3]/default/name} of type
${../if/config:/name} when the ${/glossary/messagequeue:/term} is
constructed by ${../if/construct:/name} is altered only by the
${/glossary/rtems:/term} operating system.
test-epilogue: null
test-prologue: null
rationale: null
references: []
requirement-type: functional
skip-reasons:
NoWait: |
The ${/glossary/messagequeue:/term} must be empty for an
${../glossary/receiver:/term} to wait for a message.
test-action: |
if ( ctx->is_receiver_waiting ) {
SendEvents( ctx->worker_id, EVENT_RECEIVE );
}
ctx->status = (ctx->action)(
ctx->id_param,
ctx->buffer_param,
ctx->size_param
);
if ( ctx->is_receiver_waiting ) {
FinalClockTick();
}
test-brief: null
test-cleanup: |
T_rsc_success( rtems_message_queue_delete( ctx->message_queue_id ) );
test-context:
- brief: |
This member contains a valid ${/glossary/id:/term} of a
${/glossary/messagequeue:/term}.
description: null
member: |
rtems_id message_queue_id
- brief: |
This member is used as storage area for the
${/glossary/messagequeue:/term}.
description: null
member: |
RTEMS_MESSAGE_QUEUE_BUFFER( MAXIMUM_MESSAGE_SIZE )
storage_area[ MAXIMUM_PENDING_MESSAGES]
- brief: |
This member contains always the same arbitrary number ``magic``.
description: |
It is used for run-time type checking.
member: |
uint32_t magic;
- brief: |
This member contains a number which is sent as next message.
description: null
member: |
uint8_t send_msg_counter
- brief: |
This member contains a buffer to receive messages from the queue.
description: null
member: |
uint8_t receive_buffer[ MAXIMUM_MESSAGE_SIZE ]
- brief: |
This member contains a buffer to receive the messages size.
description: null
member: |
size_t receive_size
- brief: |
This member contains the returned ${/glossary/statuscode:/term}
of the receiver.
description: null
member: |
rtems_status_code receive_status
- brief: |
This member indicates whether the a receiver task should be started
to receive a message.
description: null
member: |
bool is_receiver_waiting
- brief: |
This member contains the message to be sent by the action.
description: null
member: |
uint8_t send_message[ MAXIMUM_MESSAGE_SIZE ]
- brief: |
This member specifies the directive to be called as action.
description: |
This is either ${../if/send:/name} or ${../if/urgent:/name}.
member:
rtems_status_code (*action)( rtems_id id, const void *buffer, size_t size )
- brief: |
This member specifies the ${../if/send:/params[0]/name} parameter
for the action.
description: null
member: |
rtems_id id_param
- brief: |
This member specifies the ${../if/send:/params[1]/name} parameter
for the action.
description: null
member: |
void *buffer_param
- brief: |
This member specifies the ${../if/send:/params[2]/name} parameter
for the action.
description: null
member: |
size_t size_param
- brief: |
This member contains the returned ${/glossary/statuscode:/term}
of the action.
description: null
member: |
rtems_status_code status
- brief: |
This member contains the ${/glossary/task:/term} identifier of the
worker ${/glossary/task:/term}.
description: null
member: |
rtems_id worker_id
- brief: |
This member contains a pointer to a function which is executed
to check that the action has not changed the content of the
${/glossary/messagequeue:/term}.
description: null
member: |
void (*check_msgq_unchanged)( void *ctx_in )
test-context-support: |
#define MAXIMUM_PENDING_MESSAGES 3
#define MAXIMUM_MESSAGE_SIZE 5
test-description: null
test-header: null
test-includes:
- rtems.h
test-local-includes:
- tx-support.h
test-prepare: |
rtems_status_code status;
ctx->send_msg_counter = 0;
rtems_message_queue_config config = {
.name = rtems_build_name( 'M', 'S', 'G', 'Q' ),
.maximum_pending_messages = MAXIMUM_PENDING_MESSAGES,
.maximum_message_size = MAXIMUM_MESSAGE_SIZE,
.storage_area = ctx->storage_area,
.storage_size = sizeof( ctx->storage_area ),
.storage_free = NULL,
.attributes = RTEMS_DEFAULT_ATTRIBUTES
};
status = rtems_message_queue_construct(
&config,
&ctx->message_queue_id
);
T_rsc_success( status );
test-setup:
brief: null
code: |
ctx->magic = MAGIC;
SetSelfPriority( PRIO_NORMAL );
ctx->worker_id = CreateTask( "WORK", PRIO_HIGH );
StartTask( ctx->worker_id, WorkerTask, ctx );
description: null
test-stop: null
test-support: |
typedef ${.:/test-context-type} Context;
static const uint32_t MAGIC = 0xA66FE31; /* an arbitrary number */
static const rtems_interval TIMEOUT_TICKS = 1;
static const rtems_event_set EVENT_RECEIVE = RTEMS_EVENT_17;
static void Receive( Context *ctx )
{
ctx->receive_status = rtems_message_queue_receive(
ctx->message_queue_id,
ctx->receive_buffer,
&ctx->receive_size,
RTEMS_WAIT,
TIMEOUT_TICKS
);
}
static void WorkerTask( rtems_task_argument argument )
{
Context *ctx = (Context *) argument;
while ( true ) {
rtems_event_set events;
events = ReceiveAnyEvents();
if ( ( events & EVENT_RECEIVE ) != 0 ) {
Receive( ctx );
}
}
}
static void CheckForNoMessage(
Context *ctx,
rtems_status_code status,
uint8_t *message_buffer,
size_t message_size
)
{
(void) ctx;
T_rsc( status, RTEMS_UNSATISFIED );
}
static void CheckForFirstMessage(
Context *ctx,
rtems_status_code status,
uint8_t *message_buffer,
size_t message_size
)
{
(void) ctx;
T_rsc_success( status );
T_eq_u32( message_size, 1 );
T_eq_u8( message_buffer[0], 0 );
}
static void CheckForSecondMessage(
Context *ctx,
rtems_status_code status,
uint8_t *message_buffer,
size_t message_size
)
{
(void) ctx;
T_rsc_success( status );
T_eq_u32( message_size, 3 );
T_eq_u8( message_buffer[0], 1 );
T_eq_u8( message_buffer[1], 1 );
T_eq_u8( message_buffer[2], 1 );
}
static void CheckForThirdMessage(
Context *ctx,
rtems_status_code status,
uint8_t *message_buffer,
size_t message_size
)
{
(void) ctx;
T_rsc_success( status );
T_eq_u32( message_size, 5 );
T_eq_u8( message_buffer[0], 2 );
T_eq_u8( message_buffer[1], 2 );
T_eq_u8( message_buffer[2], 2 );
T_eq_u8( message_buffer[3], 2 );
T_eq_u8( message_buffer[4], 2 );
}
static void CheckForSendMessage(
Context *ctx,
rtems_status_code status,
uint8_t *message_buffer,
size_t message_size
)
{
size_t i;
T_rsc_success( status );
T_eq_u32( message_size, ctx->size_param );
for ( i = 0; i < ctx->size_param; ++i ) {
T_eq_u8( message_buffer[i], ctx->send_message[i] );
}
}
static void PopMessage(
Context *ctx,
void (*check_fn)(
Context *ctx,
rtems_status_code status,
uint8_t *message_buffer,
size_t message_size
)
)
{
rtems_status_code status;
uint8_t message_buffer[ MAXIMUM_MESSAGE_SIZE ];
size_t message_size;
status = rtems_message_queue_receive(
ctx->message_queue_id,
&message_buffer,
&message_size,
RTEMS_LOCAL | RTEMS_NO_WAIT,
RTEMS_NO_TIMEOUT
);
check_fn( ctx, status, message_buffer, message_size );
}
static void CheckForNoMessageInQueue( void *ctx_in )
{}
static void CheckForOneMessageInQueue( void *ctx_in )
{
Context *ctx = ctx_in;
T_assert_eq_u32( ctx->magic, MAGIC ); /* Run-time type check */
PopMessage( ctx, CheckForFirstMessage );
}
static void CheckForSeveralMessagesInQueue( void *ctx_in )
{
Context *ctx = ctx_in;
T_assert_eq_u32( ctx->magic, MAGIC ); /* Run-time type check */
PopMessage( ctx, CheckForFirstMessage );
PopMessage( ctx, CheckForSecondMessage );
}
static void CheckForAllMessagesInQueue( void *ctx_in )
{
Context *ctx = ctx_in;
T_assert_eq_u32( ctx->magic, MAGIC ); /* Run-time type check */
PopMessage( ctx, CheckForFirstMessage );
PopMessage( ctx, CheckForSecondMessage );
PopMessage( ctx, CheckForThirdMessage );
}
static void SendMsg( Context *ctx )
{
rtems_status_code status;
uint8_t msg[ MAXIMUM_MESSAGE_SIZE ];
memset( msg, ctx->send_msg_counter, MAXIMUM_MESSAGE_SIZE );
status = rtems_message_queue_send(
ctx->message_queue_id,
msg,
( ctx->send_msg_counter * 2 ) % MAXIMUM_MESSAGE_SIZE + 1
);
T_rsc_success( status );
++ctx->send_msg_counter;
}
test-target: testsuites/validation/tc-message-urgent-send.c
test-teardown:
brief: null
code: |
DeleteTask( ctx->worker_id );
RestoreRunnerPriority();
description: null
text: ${.:text-template}
transition-map:
# ---- Ok Case ----
- enabled-by: true
post-conditions:
Status: Ok
MsgQueue:
- if:
pre-conditions:
MsgQueue: Empty
Receiver: Waiting
then: Empty
- if:
pre-conditions:
MsgQueue: Empty
Receiver: 'No'
then: One
- if:
pre-conditions:
MsgQueue: One
Directive: Urgent
then: Prepend
- if:
pre-conditions:
MsgQueue: Several
Directive: Urgent
then: Prepend
- else: Append
Receiver:
- if:
pre-conditions:
MsgQueue: Empty
Receiver: Waiting
then: GotMsg
- else: N/A
pre-conditions:
Buffer:
- Valid
Id:
- Valid
Size:
- Zero
- SomeSize
- MaxSize
MsgQueue:
- Empty
- One
- Several
Receiver: all
Directive: all
Storage: all
# ---- InvAddr: Buffer ----
- enabled-by: true
post-conditions:
Status: InvAddr
MsgQueue: Nop
Receiver:
- if:
pre-conditions:
Receiver: Waiting
then: Waiting
- else: N/A
pre-conditions:
Buffer:
- 'Null'
Id: all
Size: all
MsgQueue: all
Receiver: all
Directive: all
Storage: all
# ---- InvId ----
- enabled-by: true
post-conditions:
Status: InvId
MsgQueue: Nop
Receiver:
- if:
pre-conditions:
Receiver: Waiting
then: Waiting
- else: N/A
pre-conditions:
Buffer:
- Valid
Id:
- Invalid
Size: all
MsgQueue: all
Receiver: all
Directive: all
Storage: all
# ---- InvSize ----
- enabled-by: true
post-conditions:
Status: InvSize
MsgQueue: Nop
Receiver:
- if:
pre-conditions:
Receiver: Waiting
then: Waiting
- else: N/A
pre-conditions:
Buffer:
- Valid
Id:
- Valid
Size:
- TooLarge
MsgQueue: all
Receiver: all
Directive: all
Storage: all
# ---- TooMany: Queue Full ----
- enabled-by: true
post-conditions:
Status: TooMany
MsgQueue: Nop
Receiver: N/A
pre-conditions:
Buffer:
- Valid
Id:
- Valid
Size:
- Zero
- SomeSize
- MaxSize
MsgQueue:
- Full
Receiver:
- 'No'
Directive: all
Storage: all
# ---- Impossible Cases ----
- enabled-by: true
post-conditions: NoWait
pre-conditions:
Buffer: all
Id: all
Size: all
MsgQueue:
- One
- Several
- Full
Receiver:
- Waiting
Directive: all
Storage: all
type: requirement