11

Mailboxes

Abstract

Mailboxes are a simple method of intertask communication supported by Nucleus SE. They provide a low-cost, but flexible, means of passing simple data messages between tasks. In this chapter, the operation of mailboxes is outlined, with details of all the relevant application program interfaces. The implementation of mailboxes in Nucleus SE is also detailed.

Keywords

RTOS; Nucleus; mailbox

Mailboxes were introduced in Chapter 3, RTOS Services and Facilities. They are perhaps the second simplest method of intertask communication—after signals—supported by Nucleus SE. They provide a low-cost, but flexible, means of passing simple messages between tasks.

Using mailboxes

In Nucleus SE, mailboxes are configured at build time. There may be a maximum of 16 mailboxes configured for an application. If no mailboxes are configured, no data structures or service call code appertaining to mailboxes are included in the application.

A mailbox is simply a storage location, big enough to hold a single variable of type ADDR, access to which is controlled so that it may be safely utilized by multiple tasks. One task can write to a mailbox. It is then full, and no task can write to it until a task does a read on the mailbox or the mailbox is reset. Trying to write to a full mailbox or read from an empty one may result in an error or task suspension, depending on options selected in the application program interface (API) call and the Nucleus SE configuration.

Mailboxes and queues

In some operating system implementations, mailboxes are not supported, and the use of a single-entry queue is recommended as an alternative. This sounds reasonable, as such a queue would provide the same functionality as a mailbox. However, a queue is a rather more complex data structure than a mailbox and carries considerably more overhead in data (head and tail pointers, etc.), code and execution time.

With Nucleus SE, like Nucleus RTOS, you have the choice of both object types and can make the decision for yourself.

It is, however, worth considering this alternative approach if your application includes multiple queues, but perhaps a single mailbox. Replacing that mailbox with a queue will incur a small data overhead, but eliminates all the mailbox-related API code. It would be very easy to configure the application both ways and compare the memory footprints and performance.

Queues will be discussed in the next chapter.

Configuring mailboxes

Number of mailboxes

As with most aspects of Nucleus SE, the configuration of mailboxes is primarily controlled by #define statements in nuse_config.h. The key setting is NUSE_MAILBOX_NUMBER, which determines how many mailboxes are configured for the application. The default setting is 0 (i.e., no mailboxes are in use) and you can set it to any value up to 16. An erroneous value will result in a compile time error, which is generated by a test in nuse_config_check.h (this is included into nuse_config.c and hence compiled with this module), resulting in a #error statement being compiled.

Choosing a nonzero value is the “master enable” for mailboxes. This results in some data structures being defined and sized accordingly, of which more later in this chapter. It also activates the API enabling settings.

API enables

Every API function (service call) in Nucleus SE has an enabling #define symbol in nuse_config.h. For mailboxes, these are:

NUSE_MAILBOX_SEND
NUSE_MAILBOX_RECEIVE
NUSE_MAILBOX_RESET
NUSE_MAILBOX_INFORMATION
NUSE_MAILBOX_COUNT

By default, all of these are set to FALSE, thus disabling each service call and inhibiting the inclusion of any implementation code. To configure mailboxes for an application, you need to select the API calls that you want to use and set their enabling symbols to TRUE.

Here is an extract from the default nuse_config.h file.

#define NUSE_MAILBOX_NUMBER 0         /* Number of mailboxes in the system - 0–16 */

           /* Service call enablers: */

 #define NUSE_MAILBOX_SEND   FALSE

 #define NUSE_MAILBOX_RECEIVE   FALSE

 #define NUSE_MAILBOX_RESET   FALSE

 #define NUSE_MAILBOX_INFORMATION   FALSE

 #define NUSE_MAILBOX_COUNT   FALSE

A compile time error will result if a mailbox API function is enabled and no mailboxes are configured (except for NUSE_Mailbox_Count(), which is always permitted). If your code uses an API call, which has not been enabled, a link time error will result, as no implementation code will have been included in the application.

Mailbox service calls

Nucleus RTOS supports nine service calls that appertain to mailboxes, which provide the following functionality:

  • Send a message to a mailbox. Implemented by NUSE_Mailbox_Send() in Nucleus SE.
  • Receive a message from a mailbox. Implemented by NUSE_Mailbox_Receive() in Nucleus SE.
  • Restore a mailbox to the unused state, with no tasks suspended (reset). Implemented by NUSE_Mailbox_Reset() in Nucleus SE.
  • Provide information about a specified mailbox. Implemented by NUSE_Mailbox_Information() in Nucleus SE.
  • Return a count of how many mailboxes are (currently) configured for the application. Implemented by NUSE_Mailbox_Count() in Nucleus SE.
  • Add a new mailbox to the application (create). Not implemented in Nucleus SE.
  • Remove a mailbox from the application (delete). Not implemented in Nucleus SE.
  • Return pointers to all the mailboxes (currently) in the application. Not implemented in Nucleus SE.
  • Send a message to all the tasks that are suspended on a mailbox (broadcast). Not implemented in Nucleus SE.

The implementation of each of these service calls is examined in detail.

Mailbox write and read services

The fundamental operations, which can be performed on a mailbox, are writing data to it—which is sometimes termed sending or posting—and reading data from it—which is also termed receiving. Nucleus RTOS and Nucleus SE each provide two basic API calls for these operations, which will be discussed here.

Writing to a mailbox

The Nucleus RTOS API call for writing to a mailbox is very flexible, enabling you to suspend indefinitely, or with a timeout, if the operation cannot be completed immediately; that is, you try to write to a full mailbox. Nucleus SE provides the same service, except task suspend is optional and timeout is not implemented.

Nucleus RTOS also offers a facility to broadcast to a mailbox, but this is not supported by Nucleus SE. It will be described under the “Unimplemented API calls” section later in this chapter.

Nucleus RTOS API call for sending to a mailbox

Service call prototype:

  • STATUS NU_Send_To_Mailbox(
  • NU_MAILBOX *mailbox,
  • VOID *message,
  • UNSIGNED suspend);

Parameters:

  • mailbox—pointer to the mailbox to be utilized;
  • message—a pointer to the message to be sent, which is  four unsigned elements;
  • suspend—specification for task suspend; may be  NU_NO_SUSPEND or NU_SUSPEND or a timeout value.

Returns:

  • NU_SUCCESS—The call was completed successfully.
  • NU_INVALID_MAILBOX—The mailbox pointer is invalid.
  • NU_INVALID_POINTER—The message pointer is NULL.
  • NU_INVALID_SUSPEND—Suspend was attempted from a  nontask thread.
  • NU_MAILBOX_FULL—The mailbox is full and suspend was  not specified.
  • NU_TIMEOUT—The mailbox is still full even after suspending  for the specified period.
  • NU_MAILBOX_DELETED—The mailbox was deleted, while the  task was suspended.
  • NU_MAILBOX_WAS_RESET—The mailbox was reset, while the  task was suspended.

Nucleus SE API call for sending to a mailbox

This API call supports the key functionality of the Nucleus RTOS API.

Service call prototype:

  • STATUS NUSE_Mailbox_Send(
  • NUSE_MAILBOX mailbox,
  • ADDR *message,
  • U8 suspend);

Parameters:

  • mailbox—the index (ID) of the mailbox to be utilized;
  • message—a pointer to the message to be sent, which is a  single variable of type ADDR;
  • suspend—specification for task suspend; may be  NUSE_NO_SUSPEND or NUSE_SUSPEND.

Returns:

  • NUSE_SUCCESS—The call was completed successfully.
  • NUSE_INVALID_MAILBOX—The mailbox index is invalid.
  • NUSE_INVALID_POINTER—The message pointer is NULL.
  • NUSE_INVALID_SUSPEND—Suspend was attempted from a  nontask thread or when blocking API calls were not  enabled.
  • NUSE_MAILBOX_FULL—The mailbox is full and suspend was  not specified.
  • NUSE_MAILBOX_WAS_RESET—The mailbox was reset, while  the task was suspended.

Nucleus SE implementation of mailbox send

The bulk of the code of the NUSE_Mailbox_Send() API function—after parameter checking—is selected by conditional compilation, dependent on whether support for blocking (task suspend) API calls is enabled. We will look at the two variants separately here.

If blocking is not enabled, the logic for this API call is quite simple and the code requires little explanation:

if (NUSE_Mailbox_Status[mailbox])   /* mailbox full */
{

 return_value = NUSE_MAILBOX_FULL;

}
else           /* mailbox empty */
{

 NUSE_Mailbox_Data[mailbox] = *message;

 NUSE_Mailbox_Status[mailbox] = TRUE;

 return_value = NUSE_SUCCESS;
}

The message is stored in the appropriate element of NUSE_Mailbox_Data[] and the mailbox marked as being in use.

When blocking is enabled, the code becomes more complex:

do
{
 if (!NUSE_Mailbox_Status[mailbox])   /* mailbox empty */
 {
  NUSE_Mailbox_Data[mailbox] = *message;
  NUSE_Mailbox_Status[mailbox] = TRUE;
  if (NUSE_Mailbox_Blocking_Count[mailbox]!= 0)
  {
   U8 index;   /* check whether a task is blocked */
       /* on this mailbox */
   NUSE_Mailbox_Blocking_Count[mailbox]--;
   for (index=0; index<NUSE_TASK_NUMBER; index++)
   {
    if ((LONIB(NUSE_Task_Status[index]) == NUSE_MAILBOX_SUSPEND)
     && (HINIB(NUSE_Task_Status[index]) == mailbox))
    {
     NUSE_Task_Blocking_Return[index] = NUSE_SUCCESS;
     NUSE_Wake_Task(index);
     break;
    }
   }

  }

  return_value = NUSE_SUCCESS;
  suspend = NUSE_NO_SUSPEND;
 }
 else       /* mailbox full */
 {
  if (suspend == NUSE_NO_SUSPEND)
  {
   return_value = NUSE_MAILBOX_FULL;

  }

  else
  {          /* block task */
   NUSE_Mailbox_Blocking_Count[mailbox]++;
   NUSE_Suspend_Task(NUSE_Task_Active, (mailbox << 4) | NUSE_MAILBOX_SUSPEND);
   return_value = NUSE_Task_Blocking_Return[NUSE_Task_Active];
   if (return_value!= NUSE_SUCCESS)
   {
    suspend = NUSE_NO_SUSPEND;
   }
  }
 }
} while (suspend == NUSE_SUSPEND);

Some explanation may be useful:

  • The code is enclosed in a do...while loop, which continues while the parameter suspend has the value NUSE_SUSPEND.
  • If the mailbox is empty, the supplied message is stored, and the mailbox status changed to indicate that it is full. A check is made on whether any tasks are suspended (waiting to receive) on the mailbox. If there are any tasks waiting, the first one is woken. The suspend variable is set to NUSE_NO_SUSPEND and the API call exits with NUSE_SUCCESS.
  • If the mailbox is full and suspend is set to NUSE_NO_SUSPEND, the API call exits with NUSE_MAILBOX_FULL. If suspend was set to NUSE_SUSPEND, the task is suspended. On return (i.e., when the task is woken up), if the return value is NUSE_SUCCESS, indicating that the task was woken because a message had been read (as opposed to a reset of the mailbox) the code loops back to the top.

Reading from a mailbox

The Nucleus RTOS API call for reading from a mailbox is very flexible, enabling you to suspend indefinitely, or with a timeout, if the operation cannot be completed immediately; that is, you try to read from an empty mailbox. Nucleus SE provides the same service, except task suspend is optional and timeout is not implemented.

Nucleus RTOS API call for receiving from a mailbox

Service call prototype:

  • STATUS NU_Receive_From_Mailbox(
  • NU_MAILBOX *mailbox,
  • VOID *message,
  • UNSIGNED suspend);

Parameters:

  • mailbox—pointer to the user-supplied mailbox control  block;
  • message—a pointer to storage for the message to be  received, which is the size of four unsigned variables;
  • suspend—specification for task suspend; may be  NUSE_NO_SUSPEND or NUSE_SUSPEND or a timeout value.

Returns:

  • NU_SUCCESS—The call was completed successfully.
  • NU_INVALID_MAILBOX—The mailbox pointer is invalid.
  • NU_INVALID_POINTER—The message pointer is NULL.
  • NU_INVALID_SUSPEND—Suspend was attempted from a  nontask thread.
  • NU_MAILBOX_EMPTY—The mailbox is empty and suspend  was not specified.
  • NU_TIMEOUT—indicates that the mailbox is still empty even  after suspending for the specified timeout value.
  • NU_MAILBOX_DELETED—The mailbox was deleted, while the  task was suspended.
  • NU_MAILBOX_WAS_RESET—the mailbox was reset, while the  task was suspended

Nucleus SE API call for receiving from a mailbox

This API call supports the key functionality of the Nucleus RTOS API.

Service call prototype:

  • STATUS NUSE_Mailbox_Receive(
  • NUSE_MAILBOX mailbox,
  • ADDR *message,
  • U8 suspend);

Parameters:

  • mailbox—the index (ID) of the mailbox to be utilized;
  • message—a pointer to storage for the message to be  received, which is a single variable of type ADDR;
  • suspend—specification for task suspend; may be  NUSE_NO_SUSPEND or NUSE_SUSPEND.

Returns:

  • NUSE_SUCCESS—The call was completed successfully.
  • NUSE_INVALID_MAILBOX—The mailbox index is invalid.
  • NUSE_INVALID_POINTER—The message pointer is NULL.
  • NUSE_INVALID_SUSPEND—Suspend was attempted from a  nontask thread or when blocking API calls were not enabled.
  • NUSE_MAILBOX_EMPTY—The mailbox is empty and suspend  was not specified.
  • NUSE_MAILBOX_WAS_RESET—The mailbox was reset, while  the task was suspended.

Nucleus SE implementation of mailbox receive

The bulk of the code of the NUSE_Mailbox_Receive() API function—after parameter checking—is selected by conditional compilation, dependent on whether support for blocking (task suspend) API calls is enabled. We will look at the two variants separately here.

If blocking is not enabled, the logic for this API call is quite simple and the code requires little explanation:

if (!NUSE_Mailbox_Status[mailbox])   /* mailbox empty */
{
 return_value = NUSE_MAILBOX_EMPTY;
}
else
{             /* mailbox full */

 *message = NUSE_Mailbox_Data[mailbox];

 NUSE_Mailbox_Status[mailbox] = FALSE;
 return_value = NUSE_SUCCESS;

}

The message is extracted from the appropriate element of NUSE_Mailbox_Data[] and the mailbox marked as being empty.

When blocking is enabled, the code becomes more complex:

do
{
 if (NUSE_Mailbox_Status[mailbox])   /* mailbox full */
 {
  *message = NUSE_Mailbox_Data[mailbox];
  NUSE_Mailbox_Status[mailbox] = FALSE;
  if (NUSE_Mailbox_Blocking_Count[mailbox]!= 0)
  {
   U8 index;   /* check whether a task is blocked */
        /* on this mailbox */
   NUSE_Mailbox_Blocking_Count[mailbox]--;
   for (index=0; index<NUSE_TASK_NUMBER; index++)
   {
    if ((LONIB(NUSE_Task_Status[index]) == NUSE_MAILBOX_SUSPEND) &&
     (HINIB(NUSE_Task_Status[index]) == mailbox))
    {
     NUSE_Task_Blocking_Return[index] = NUSE_SUCCESS;
     NUSE_Wake_Task(index);
     break;
    }
   }
   }
  return_value = NUSE_SUCCESS;
  suspend = NUSE_NO_SUSPEND;
 }
 else /* mailbox empty */
 {
  if (suspend == NUSE_NO_SUSPEND)
  {
   return_value = NUSE_MAILBOX_EMPTY;
  }
  else
  {           /* block task */
   NUSE_Mailbox_Blocking_Count[mailbox]++;
   NUSE_Suspend_Task(NUSE_Task_Active, (mailbox << 4) | NUSE_MAILBOX_SUSPEND);
   return_value =     NUSE_Task_Blocking_Return[NUSE_Task_Active];
   if (return_value!= NUSE_SUCCESS)
   {
    suspend = NUSE_NO_SUSPEND;
   }
  }
 }

} while (suspend == NUSE_SUSPEND);

Some explanation may be useful:

  • The code is enclosed in a do...while loop, which continues while the parameter suspend has the value NUSE_SUSPEND.
  • If the mailbox is full, the stored message is returned, and the mailbox status changed to indicate that it is empty. A check is made on whether any tasks are suspended (waiting to send) on the mailbox. If there are any tasks waiting, the first one is woken. The suspend variable is set to NUSE_NO_SUSPEND and the API call exits with NUSE_SUCCESS.
  • If the mailbox is empty and suspend is set to NUSE_NO_SUSPEND, the API call exits with NUSE_MAILBOX_EMPTY. If suspend was set to NUSE_SUSPEND, the task is suspended. On return (i.e., when the task is woken up), if the return value is NUSE_SUCCESS, indicating that the task was woken because a message had been sent (as opposed to a reset of the mailbox) the code loops back to the top.

Mailbox utility services

Nucleus RTOS has four API calls that provide utility functions associated with mailboxes: reset mailbox, return information about a mailbox, return number of mailboxes in the application, and return pointers to all mailboxes in the application. The first three of these are implemented in Nucleus SE.

Resetting a mailbox

This API call restores the mailbox to its initial, unused state. Any message stored in the mailbox is lost. Any tasks that were suspended on the mailbox are resumed and receive a return code of NUSE_MAILBOX_WAS_RESET.

Nucleus RTOS API call for resetting a mailbox

Service call prototype:

  • STATUS NU_Reset_Mailbox(NU_MAILBOX *mailbox);

Parameters:

  • mailbox—pointer to the user-supplied mailbox control  block
    Returns:
  • NU_SUCCESS—The call was completed successfully.
  • NU_INVALID_MAILBOX—The mailbox pointer is not valid.

Nucleus SE API call for resetting a mailbox

This API call supports the key functionality of the Nucleus RTOS API.

Service call prototype:

  • STATUS NUSE_Mailbox_Reset(NUSE_MAILBOX mailbox);

Parameters:

  • mailbox—the index (ID) of the mailbox to be reset
    Returns:
  • NUSE_SUCCESS—The call was completed successfully.
  • NUSE_INVALID_MAILBOX—The mailbox index is not valid.

Nucleus SE implementation of mailbox reset

The bulk of the code of the NUSE_Mailbox_Reset() API function—after parameter checking—is selected by conditional compilation, dependent on whether support for blocking (task suspend) API calls is enabled. We will look at the two variants separately here.

If blocking is not enabled, the API function code is almost trivial. The mailbox is marked as unused by setting its entry in NUSE_Mailbox_Status[] to FALSE.

When blocking is enabled, the code becomes more complex:

 while (NUSE_Mailbox_Blocking_Count[mailbox]!= 0)
 {
  U8 index;   /* check whether any tasks are blocked */
       /* on this mailbox */
  for (index=0; index<NUSE_TASK_NUMBER; index++)
  {
   if ((LONIB(NUSE_Task_Status[index]) == NUSE_MAILBOX_SUSPEND)
    && (HINIB(NUSE_Task_Status[index]) == mailbox))
   {
    NUSE_Task_Blocking_Return[index] = NUSE_MAILBOX_WAS_RESET;
    NUSE_Task_Status[index] = NUSE_READY;
    break;
   }
  }
  NUSE_Mailbox_Blocking_Count[mailbox]--;
}
#if NUSE_SCHEDULER_TYPE == NUSE_PRIORITY_SCHEDULER
 NUSE_Reschedule(NUSE_NO_TASK);

#endif

Initially the mailbox is marked as empty.

Each task suspended on the mailbox is marked as Ready with a suspend return code of NUSE_MAILBOX_WAS_RESET. After this process is complete, if the Priority scheduler is in use, a call is made to NUSE_Reschedule(), as one or more higher priority tasks may have been readied and needs to be allowed to run.

Mailbox information

This service call obtains a selection of information about a mailbox. The Nucleus SE implementation differs from Nucleus RTOS in that it returns less information, as object naming and suspend ordering are not supported and task suspend may not be enabled.

Nucleus RTOS API call for mailbox information

Service call prototype:

  • STATUS NU_Mailbox_Information(
  • NU_MAILBOX *mailbox,
  • CHAR *name,
  • OPTION *suspend_type,
  • DATA_ELEMENT *message_present,
  • UNSIGNED *tasks_waiting,
  • NU_TASK **first_task);

Parameters:

  • mailbox—pointer to the user-supplied mailbox control  block;
  • name—pointer to an 8-character destination area for the mailbox’s name. This includes space for a NULL terminator;
  • suspend_type—pointer to a variable for holding the task suspend type. Valid task suspend types are NU_FIFO and NU_PRIORITY;
  • message_present—a pointer to a variable, which will  receive a value of NU_TRUE or NU_FALSE depending on whether the mailbox is full or not;
  • tasks_waiting—a pointer to a variable, which will receive the number of tasks suspended on this mailbox;
  • first_task—a pointer to a task pointer, which will receive the pointer to the first suspended task.

Returns:

  • NU_SUCCESS—The call was completed successfully.
  • NUSE_INVALID_MAILBOX—The mailbox pointer is not valid.

Nucleus SE API call for mailbox information

This API call supports the key functionality of the Nucleus RTOS API.

Service call prototype:

  • STATUS NUSE_Mailbox_Information(
  • NUSE_MAILBOX mailbox,
  • U8 *message_present,
  • U8 *tasks_waiting,
  • NUSE_TASK *first_task);

Parameters:

  • mailbox—the index of the mailbox about which informationis being requested;
  • message_present—a pointer to a variable, which will receive a value of TRUE or FALSE depending on whether the mailbox is full or not;
  • tasks_waiting—a pointer to a variable, which will receive the number of tasks suspended on this mailbox (nothing returned if task suspend is disabled);
  • first_task—a pointer to a variable of type NUSE_TASK, which will receive the index of the first suspended task (nothing returned if task suspend is disabled).

Returns:

  • NUSE_SUCCESS—The call was completed successfully.
  • NUSE_INVALID_MAILBOX—The mailbox index is not valid.
  • NUSE_INVALID_POINTER—One or more of the pointer parameters is invalid.

Nucleus SE implementation of mailbox information

The implementation of this API call is quite straightforward:

*message_present = NUSE_Mailbox_Status[mailbox];
#if NUSE_BLOCKING_ENABLE

 *tasks_waiting = NUSE_Mailbox_Blocking_Count[mailbox];

 if (NUSE_Mailbox_Blocking_Count[mailbox]!= 0)
 {
  U8 index;

  for (index=0; index<NUSE_TASK_NUMBER; index++)

  {
   if ((LONIB(NUSE_Task_Status[index]) == NUSE_MAILBOX_SUSPEND)
    && (HINIB(NUSE_Task_Status[index]) == mailbox))
   {
    *first_task = index;
    break;
   }

  }

 }
 else
 {
  *first_task = 0;
 }
 #else

  *tasks_waiting = 0;

  *first_task = 0;
 #endif
 return NUSE_SUCCESS;

The function returns the mailbox status. Then, if blocking API calls is enabled, the number of waiting tasks and the index of the first one are returned (otherwise, these two parameters are set to 0).

Obtaining the number of mailboxes

This service call returns the number of mailboxes configured in the application. Whilst in Nucleus RTOS this will vary over time and the returned value will represent the current number of mailboxes, in Nucleus SE the value returned is set at build time and cannot change.

Nucleus RTOS API call for mailbox count

Service call prototype:

UNSIGNED NU_Established_Mailboxes(VOID);

Parameters:

  • None
    Returns:
  • The number of created mailboxes in the application

Nucleus SE API call for mailbox count

This API call supports the key functionality of the Nucleus RTOS API.

Service call prototype:

U8 NUSE_Mailbox_Count(void);

Parameters:

  • None

Returns:

The number of configured mailboxes in the application

Nucleus SE implementation of mailbox count

The implementation of this API call is almost trivially simple: the value of the #define symbol NUSE_MAILBOX_NUMBER is returned.

Data structures

Mailboxes utilize two or three data structures—all in RAM—which, like other Nucleus SE objects, are a series of tables, included and dimensioned according to the number of mailboxes configured and options selected.

I strongly recommend that application code does not access these data structures directly but uses the provided API functions. This avoids incompatibility with future versions of Nucleus SE and unwanted side effects and simplifies porting of an application to Nucleus RTOS. The details of data structures are included here to facilitate easier understanding of the working of the service call code and for debugging.

RAM data

These data structures are:

  • NUSE_Mailbox_Data[]—This is an array of type ADDR, with one entry for each configured mailbox and is where the mailbox data is stored.
  • NUSE_Mailbox_Status[]—This is an array of type U8, with one entry for each configured mailbox, which tracks the usage of the mailboxes. A nonzero value (TRUE) indicates that a mailbox is full.
  • NUSE_Mailbox_Blocking_Count[]—This type U8 array contains the counts of how many tasks are blocked on each mailbox. This array only exists if blocking API call support is enabled.

These data structures are all initialized to zeros by NUSE_Init_Mailbox() when Nucleus SE starts up. This is logical, as it renders every mailbox as being empty (unused). Chapter 17, Nucleus SE Initialization and Start-up, provides a full description of Nucleus SE start-up procedures.

Here are the definitions of these data structures in nuse_init.c file.

 RAM ADDR NUSE_Mailbox_Data[NUSE_MAILBOX_NUMBER];
 RAM U8 NUSE_Mailbox_Status[NUSE_MAILBOX_NUMBER];
 #if NUSE_BLOCKING_ENABLE
 RAM U8 NUSE_Mailbox_Blocking_Count[NUSE_MAILBOX_NUMBER];

 #endif

ROM data

There are no ROM data structures associated with mailboxes.

Mailbox data footprint

Like all kernel objects in Nucleus SE, the amount of data memory required for mailboxes is readily predictable.

The ROM data footprint for all the mailboxes in an application is 0.

The RAM data footprint (in bytes) for all the mailboxes in an application, when blocking API calls is enabled, may be computed thus:

NUSE_MAILBOX_NUMBER * (sizeof(ADDR) + 2)

Otherwise, it is:

NUSE_MAILBOX_NUMBER * (sizeof(ADDR) + 1)

Unimplemented API calls

Four mailbox API calls found in Nucleus RTOS are not implemented in Nucleus SE:

Create mailbox

This API call creates a mailbox. It is not needed with Nucleus SE, as mailboxes are created statically.

Service call prototype:

  • STATUS NU_Create_Mailbox(
  • NU_MAILBOX *mailbox,
  • CHAR *name,
  • OPTION suspend_type);

Parameters:

  • mailbox—Pointer to a user-supplied mailbox control block; this will be used as a “handle” for the mailbox in other API calls.
  • name—Pointers to a 7-character, NULL-terminated name for the mailbox.
  • suspend_type—Specifies how tasks suspend on the mailbox. Valid options for this parameter are NU_FIFO and NU_PRIORITY, which represent First-In-First-Out (FIFO) and priority-order task suspension, respectively.

Returns:

  • NU_SUCCESS—indicates successful completion of the service.
  • NU_INVALID_MAILBOX—indicates the mailbox control block pointer is NULL or already in use.
  • NU_INVALID_SUSPEND—indicates that the suspend_type parameter is invalid.

Delete mailbox

This API call deletes a previously created mailbox. It is not needed with Nucleus SE, as mailboxes are created statically and cannot be deleted.

Service call prototype:

STATUS NU_Delete_Mailbox(NU_MAILBOX *mailbox);

Parameters:

  • mailbox—pointer to mailbox control block
    Returns:
  • NU_SUCCESS—indicates successful completion of the service.
  • NU_INVALID_MAILBOX—indicates the mailbox pointer is invalid.

Mailbox pointers

This API call builds a sequential list of pointers to all mailboxes in the system. It is not needed with Nucleus SE, as mailboxes are identified by a simple index, not a pointer, and it would be redundant.

Service call prototype:

  • UNSIGNED NU_Mailbox_Pointers(
  • NU_MAILBOX **pointer_list,
  • UNSIGNED maximum_pointers);

Parameters:

  • pointer_list—pointer to an array of NU_MAILBOX pointers; this array will be filled with pointers to established mailboxes in the system;
  • maximum_pointers—the maximum number of pointers to place in the array.

Returns:

  • The number of NU_MAILBOX pointers placed into the array

Broadcast to mailbox

This API call broadcasts a message to all tasks waiting for a message from the specified mailbox. It is not implemented with Nucleus SE, as it would have added excessive complexity.

Service call prototype:

  • STATUS NU_Broadcast_To_Mailbox(
  • NU_MAILBOX *mailbox,
  • VOID *message,
  • UNSIGNED suspend);

Parameters:

  • mailbox—pointer to mailbox control block;
  • message—pointer to the broadcast message;
  • suspend—specifies whether or not to suspend the calling task if the mailbox already contains a message; valid options for this parameter are NU_NO_SUSPEND, NU_SUSPEND, or a timeout value.

Returns:

  • NU_SUCCESS—indicates successful completion of the service.
  • NU_INVALID_MAILBOX—indicates the mailbox pointer is invalid.
  • NU_INVALID_POINTER—indicates that the message pointer is NULL.
  • NU_INVALID_SUSPEND—indicates that suspend attempted from a nontask thread.
  • NU_MAILBOX_FULL—indicates the mailbox already contains a message.
  • NU_TIMEOUT—indicates the mailbox is still full after the timeout has expired.
  • NU_MAILBOX_DELETED—mailbox was deleted, while the task was suspended.
  • NU_MAILBOX_RESET—mailbox was reset, while the task was  suspended.

Compatibility with Nucleus RTOS

With all aspects of Nucleus SE, it was my goal to maintain as high a level of applications code compatibility with Nucleus RTOS as possible. Mailboxes are no exception, and, from a user’s perspective, they are implemented in much the same way as in Nucleus RTOS. There are areas of incompatibility, which have come about where I determined that such an incompatibility would be acceptable, given that the resulting code is easier to understand, or, more likely, could be made more memory efficient. Otherwise, Nucleus RTOS API calls may be almost directly mapped onto Nucleus SE calls. Chapter 20, Using Nucleus SE, includes further information on using Nucleus SE for users of Nucleus RTOS.

Object identifiers

In Nucleus RTOS, all objects are described by a data structure—a control block—which has a specific data type. A pointer to this control block serves as an identifier for the mailbox. In Nucleus SE, I decided that a different approach was needed for memory efficiency, and all kernel objects are described by a number of tables in RAM and/or ROM. The size of these tables is determined by the number of each object type that is configured. The identifier for a specific object is simply an index into those tables. So, I have defined NUSE_MAILBOX as being equivalent to U8; a variable—not a pointer—of this type then serves as the mailbox identifier. This is a small incompatibility, which is easily handled if code is ported to or from Nucleus RTOS. Object identifiers are normally just stored and passed around and not operated on in any way.

Nucleus RTOS also supports naming of mailboxes. These names are only used for target-based debug facilities. I omitted them from Nucleus SE to save memory.

Message size and type

In Nucleus RTOS, a mailbox message consists of four 32-bit words. I decided to reduce this to a single variable of type ADDR in Nucleus SE. This change imparts significant increases in memory and execution time efficiency. It also recognizes that a common application for a mailbox is to send a pointer to something from one task to another. This incompatibility will present few challenges when porting application code to Nucleus RTOS. Nucleus SE could be modified quite readily, if a different message format were required.

Unimplemented API calls

Nucleus RTOS supports nine service calls to work with mailboxes. Of these, four are not implemented in Nucleus SE. Details of these and of the decision to omit them may be found in “Unimplemented API calls” section earlier in this chapter.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.117.196.184