Industrial manufacturing
Industrial Internet of Things | Industrial materials | Equipment Maintenance and Repair | Industrial programming |
home  MfgRobots >> Industrial manufacturing >  >> Industrial Internet of Things >> Embedded

Queues in Nucleus SE: Introduction and Core Service Calls

Queues in Nucleus SE: Introduction and Core Service Calls
View the RTOS Revealed series

Queues were introduced in an earlier article. They provide a more flexible means of passing simple messages between tasks than mailboxes.

Using Queues

In Nucleus SE, queues are configured at build time. A maximum of 16 queues may be defined for an application. If no queues are configured, the RTOS omits all queue‑related data structures and API code, keeping the binary lean.

A queue is simply an array of storage slots, each large enough to hold a single ADDR data item. Access is synchronised so that multiple tasks can safely enqueue and dequeue messages. Tasks can write to a queue until all slots are full, and read from a queue in a first‑in, first‑out (FIFO) order. Attempts to send to a full queue or receive from an empty one trigger an error or a task suspension, depending on the API options selected and the Nucleus SE configuration.

Queues vs. Pipes

Nucleus SE also supports pipes, which differ primarily in message size. While a queue transmits a single ADDR (typically a pointer), a pipe carries a variable‑length block of bytes; the block size is fixed at configuration time. Pipes are discussed in depth in a future article.

Configuring Queues

Number of Queues

Queue configuration is controlled by #define statements in nuse_config.h. The key setting is NUSE_QUEUE_NUMBER, which determines how many queues are enabled. The default is 0 (no queues). You may set it to any value from 0 to 16; an out‑of‑range value triggers a compile‑time #error produced by nuse_config_check.h.

Setting NUSE_QUEUE_NUMBER to a non‑zero value activates the queue subsystem, allocating the necessary data structures and enabling the associated API calls.

API Enables

Each queue API function has an enabling #define symbol in nuse_config.h:

NUSE_QUEUE_SEND
NUSE_QUEUE_RECEIVE
NUSE_QUEUE_JAM
NUSE_QUEUE_RESET
NUSE_QUEUE_INFORMATION
NUSE_QUEUE_COUNT

By default all are set to FALSE, disabling the corresponding service calls. To use a particular API, set its symbol to TRUE. Enabling an API while no queues are configured (except NUSE_Queue_Count(), which is always allowed) results in a compile‑time error. If an API is called in code that has not been enabled, a link‑time error occurs because the implementation is omitted.

#define NUSE_QUEUE_NUMBER    0  /* Number of queues in the system – 0‑16 */
/* Service call enablers */
#define NUSE_QUEUE_SEND          FALSE
#define NUSE_QUEUE_RECEIVE        FALSE
#define NUSE_QUEUE_JAM           FALSE
#define NUSE_QUEUE_RESET         FALSE
#define NUSE_QUEUE_INFORMATION   FALSE
#define NUSE_QUEUE_COUNT         FALSE

Queue Service Calls

Nucleus RTOS offers ten queue‑related service calls, of which six are implemented in Nucleus SE. They provide the following functionality:

The implementation of each API is discussed in detail in the following sections.

Writing and Reading Services

The core operations on a queue are writing (sending) and reading (receiving). Writing to the front of a queue is called jamming. Nucleus RTOS and Nucleus SE each expose three basic API calls for these actions.

Writing to a Queue

The RTOS API NU_Send_To_Queue() is highly flexible, allowing indefinite suspension or a timeout if the queue is full. Nucleus SE offers the same function but suspending is optional and timeouts are not supported. RTOS also supports a broadcast operation, which is unavailable in SE.

RTOS API: NU_Send_To_Queue()

Prototype:

STATUS NU_Send_To_Queue(NU_QUEUE *queue, VOID *message,
                        UNSIGNED size, UNSIGNED suspend);

Parameters:

Return codes include NU_SUCCESS, NU_QUEUE_FULL, NU_TIMEOUT, and various error codes for invalid pointers or queue state.

SE API: NUSE_Queue_Send()

Prototype:

STATUS NUSE_Queue_Send(NUSE_QUEUE queue, ADDR *message,
                       U8 suspend);

Parameters:

Return values mirror the RTOS function but reflect SE’s limited blocking behaviour.

Implementation Overview

When blocking is disabled, the routine simply checks for space and either writes the value or returns NUSE_QUEUE_FULL. With blocking enabled, the function loops, suspending the task if the queue is full until space becomes available or a reset occurs. The implementation uses NUSE_Queue_Blocking_Count to track blocked tasks and NUSE_Task_Blocking_Return to resume them once a slot opens.

if (NUSE_Queue_Items[queue] == NUSE_Queue_Size[queue]) {
    return_value = NUSE_QUEUE_FULL;
} else {
    NUSE_Queue_Data[queue][NUSE_Queue_Head[queue]++] = *message;
    if (NUSE_Queue_Head[queue] == NUSE_Queue_Size[queue])
        NUSE_Queue_Head[queue] = 0;
    NUSE_Queue_Items[queue]++;
    return_value = NUSE_SUCCESS;
}
do {
    if (NUSE_Queue_Items[queue] == NUSE_Queue_Size[queue]) {
        if (suspend == NUSE_NO_SUSPEND) {
            return_value = NUSE_QUEUE_FULL;
        } else {
            NUSE_Queue_Blocking_Count[queue]++;
            NUSE_Suspend_Task(NUSE_Task_Active, (queue << 4) | NUSE_QUEUE_SUSPEND);
            return_value = NUSE_Task_Blocking_Return[NUSE_Task_Active];
            if (return_value != NUSE_SUCCESS)
                suspend = NUSE_NO_SUSPEND;
        }
    } else {
        NUSE_Queue_Data[queue][NUSE_Queue_Head[queue]++] = *message;
        if (NUSE_Queue_Head[queue] == NUSE_Queue_Size[queue])
            NUSE_Queue_Head[queue] = 0;
        NUSE_Queue_Items[queue]++;
        if (NUSE_Queue_Blocking_Count[queue] != 0) {
            U8 index;
            NUSE_Queue_Blocking_Count[queue]--;
            for (index = 0; index < NUSE_TASK_NUMBER; index++) {
                if ((LONIB(NUSE_Task_Status[index]) == NUSE_QUEUE_SUSPEND)
                    && (HINIB(NUSE_Task_Status[index]) == queue)) {
                    NUSE_Task_Blocking_Return[index] = NUSE_SUCCESS;
                    NUSE_Wake_Task(index);
                    break;
                }
            }
        }
        return_value = NUSE_SUCCESS;
        suspend = NUSE_NO_SUSPEND;
    }
} while (suspend == NUSE_SUSPEND);

The loop continues until a message is successfully enqueued or the task is unblocked by a reset. The implementation ensures thread‑safe access and efficient wake‑up of blocked consumers.

Embedded

  1. Stainless Steel Explained: Composition, Production, and Global Impact
  2. Diodes and Rectifiers: Fundamentals, Operation, and Key Parameters
  3. Understanding Conductors and Insulators: From Quantum Mechanics to Practical Applications
  4. C# Fundamentals: Input and Output Essentials
  5. Mailboxes in Nucleus SE: A Practical Guide to Configuration and Usage
  6. Semaphores in Nucleus RTOS: Utility Services & Data Structures
  7. Semaphores in Nucleus SE: Overview, Configuration, and API Essentials
  8. Event Flag Groups in Nucleus SE: An Introductory Guide to Configuration and API Usage
  9. Partition Memory in Nucleus RTOS/SE: Utility Services and Data Structures
  10. Partition Memory in Nucleus SE: Configuration, APIs, and Best Practices