summaryrefslogblamecommitdiffstats
path: root/spec/rtems/message/req/urgent-send.yml
blob: 727653df72d29364249f8723c81d096b469ea6ca (plain) (tree)










































































































































































































































































































































                                                                                

                                                                
         
                                                                               

























                                                                      











































                                                                       


























































































































































































































































































































































                                                                    
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