Skip to content

Commit c18d355

Browse files
committed
Added Example demonstrating use of queues
1 parent ad2968c commit c18d355

File tree

1 file changed

+127
-0
lines changed
  • libraries/MultiThreading/examples/Queues

1 file changed

+127
-0
lines changed
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
/*
2+
This example demonstrates basic usage of FreeRTOS Queues which enable tasks to pass data between each other in a secure asynchronous way.
3+
Please refer to other examples in this folder to better understand usage of tasks.
4+
It is also advised to read documentation on FreeRTOS web pages:
5+
https://www.freertos.org/a00106.html
6+
7+
This example read data received on serial port (sent by user) pass it vie queue to another task which will send it back on Serial Output.
8+
9+
Theory:
10+
A queue is a simple to use data structure (in the most basic way) controlled by `xQueueSend` and `xQueueReceive` functions.
11+
Usually one task writes into the queue and the other task reads from it.
12+
Usage of queues enables the reading task to yield the CPU until there are data in the queue and therefore not waste precious computation time.
13+
*/
14+
15+
#define MAX_LINE_LENGTH (64)
16+
17+
// Define two tasks for reading and writing from and to the serial port.
18+
void TaskWriteToSerial(void *pvParameters);
19+
void TaskReadFromSerial(void *pvParameters);
20+
21+
// Define Queue handle
22+
QueueHandle_t QueueHandle;
23+
const int QueueElementSize = 10;
24+
typedef struct{
25+
char line[MAX_LINE_LENGTH];
26+
uint8_t line_length;
27+
} message_t;
28+
29+
// The setup function runs once when you press reset or power on the board.
30+
void setup() {
31+
// Initialize serial communication at 115200 bits per second:
32+
Serial.begin(115200);
33+
while(!Serial){delay(10);}
34+
35+
// Create the queue which will have <QueueElementSize> number of elements, each of size `message_t` and pass the address to <QueueHandle>.
36+
QueueHandle = xQueueCreate(QueueElementSize, sizeof(message_t));
37+
38+
// Check if the queue was successfully created
39+
if(QueueHandle == NULL){
40+
Serial.println("Queue could not be created. Halt.");
41+
while(1) delay(1000); // Halt at this point as is not possible to continue
42+
}
43+
44+
// Set up two tasks to run independently.
45+
xTaskCreate(
46+
TaskWriteToSerial
47+
, "Task Write To Serial" // A name just for humans
48+
, 2048 // The stack size can be checked by calling `uxHighWaterMark = uxTaskGetStackHighWaterMark(NULL);`
49+
, NULL // No parameter is used
50+
, 2 // Priority, with 3 (configMAX_PRIORITIES - 1) being the highest, and 0 being the lowest.
51+
, NULL // Task handle is not used here
52+
);
53+
54+
xTaskCreate(
55+
TaskReadFromSerial
56+
, "Task Read From Serial"
57+
, 2048 // Stack size
58+
, NULL // No parameter is used
59+
, 1 // Priority
60+
, NULL // Task handle is not used here
61+
);
62+
63+
// Now the task scheduler, which takes over control of scheduling individual tasks, is automatically started.
64+
Serial.printf("\nAnything you write will return as echo.\nMaximum line length is %d characters (+ terminating '0').\nAnything longer will sent as separate line.\n\n", MAX_LINE_LENGTH-1);
65+
}
66+
67+
void loop(){
68+
// Loop is free to do any other work
69+
70+
delay(1000); // While not being used yield the CPU to other tasks
71+
}
72+
73+
/*--------------------------------------------------*/
74+
/*---------------------- Tasks ---------------------*/
75+
/*--------------------------------------------------*/
76+
77+
void TaskWriteToSerial(void *pvParameters){ // This is a task.
78+
message_t message;
79+
for (;;){ // A Task shall never return or exit.
80+
// One approach would be to poll the function (uxQueueMessagesWaiting(QueueHandle) and call delay if nothing is waiting.
81+
// The other approach is to use infinite time to wait defined by constant `portMAX_DELAY`:
82+
if(QueueHandle != NULL){ // Sanity check just to make sure the queue actually exists
83+
int ret = xQueueReceive(QueueHandle, &message, portMAX_DELAY);
84+
if(ret == pdPASS){
85+
// The message was successfully received - send it back to Serial port and "Echo: "
86+
//Serial.printf("Echo: \"%s\"\n", line);
87+
Serial.printf("Echo line of size %d: \"%s\"\n", message.line_length, message.line);
88+
// The item is queued by copy, not by reference, so lets free the buffer after use.
89+
}else if(ret == pdFALSE){
90+
Serial.println("The `TaskWriteToSerial` was unable to receive data from the Queue");
91+
}
92+
} // Sanity check
93+
} // Infinite loop
94+
}
95+
96+
void TaskReadFromSerial(void *pvParameters){ // This is a task.
97+
message_t message;
98+
for (;;){
99+
// Check if any data are waiting in the Serial buffer
100+
message.line_length = Serial.available();
101+
if(message.line_length > 0){
102+
// Check if the queue exists AND if there is any free space in the queue
103+
if(QueueHandle != NULL && uxQueueSpacesAvailable(QueueHandle) > 0){
104+
int max_length = message.line_length < MAX_LINE_LENGTH ? message.line_length : MAX_LINE_LENGTH-1;
105+
for(int i = 0; i < max_length; ++i){
106+
message.line[i] = Serial.read();
107+
}
108+
message.line_length = max_length;
109+
message.line[message.line_length] = 0; // Add the terminating nul char
110+
111+
// The line needs to be passed as pointer to void.
112+
// The last parameter states how many milliseconds should wait (keep trying to send) if is not possible to send right away.
113+
// When the wait parameter is 0 it will not wait and if the send is not possible the function will return errQUEUE_FULL
114+
int ret = xQueueSend(QueueHandle, (void*) &message, 0);
115+
if(ret == pdTRUE){
116+
// The message was successfully sent.
117+
}else if(ret == errQUEUE_FULL){
118+
// Since we are checking uxQueueSpacesAvailable this should not occur, however if more than one task should
119+
// write into the same queue it can fill-up between the test and actual send attempt
120+
Serial.println("The `TaskReadFromSerial` was unable to send data into the Queue");
121+
} // Queue send check
122+
} // Queue sanity check
123+
}else{
124+
delay(100); // Allow other tasks to run when there is nothing to read
125+
} // Serial buffer check
126+
} // Infinite loop
127+
}

0 commit comments

Comments
 (0)