Skip to content

Commit a81783e

Browse files
Merge pull request #4752 from bulislaw/queue_tests
RTOS: Queue tests & docs rework
2 parents 294d7e7 + fccfa7e commit a81783e

File tree

2 files changed

+292
-62
lines changed

2 files changed

+292
-62
lines changed
Lines changed: 280 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,70 +1,291 @@
11
#include "mbed.h"
22
#include "greentea-client/test_env.h"
3+
#include "unity.h"
4+
#include "utest.h"
35
#include "rtos.h"
46

57
#if defined(MBED_RTOS_SINGLE_THREAD)
68
#error [NOT_SUPPORTED] test not supported
79
#endif
810

9-
typedef struct {
10-
float voltage; /* AD result of measured voltage */
11-
float current; /* AD result of measured current */
12-
uint32_t counter; /* A counter value */
13-
} message_t;
14-
15-
#define CREATE_VOLTAGE(COUNTER) (COUNTER * 0.1) * 33
16-
#define CREATE_CURRENT(COUNTER) (COUNTER * 0.1) * 11
17-
#define QUEUE_SIZE 16
18-
#define QUEUE_PUT_DELAY 100
19-
20-
#define TEST_STACK_SIZE 512
21-
22-
MemoryPool<message_t, QUEUE_SIZE> mpool;
23-
Queue<message_t, QUEUE_SIZE> queue;
24-
25-
/* Send Thread */
26-
void send_thread () {
27-
static uint32_t i = 10;
28-
while (true) {
29-
i++; // Fake data update
30-
message_t *message = mpool.alloc();
31-
message->voltage = CREATE_VOLTAGE(i);
32-
message->current = CREATE_CURRENT(i);
33-
message->counter = i;
34-
queue.put(message);
35-
Thread::wait(QUEUE_PUT_DELAY);
36-
}
11+
using namespace utest::v1;
12+
13+
#define THREAD_STACK_SIZE 512
14+
#define TEST_UINT_MSG 0xDEADBEEF
15+
#define TEST_UINT_MSG2 0xE1EE7
16+
#define TEST_TIMEOUT 50
17+
18+
template <uint32_t ms>
19+
void thread_put_uint_msg(Queue<uint32_t, 1> *q)
20+
{
21+
Thread::wait(ms);
22+
osStatus stat = q->put((uint32_t*) TEST_UINT_MSG);
23+
TEST_ASSERT_EQUAL(osOK, stat);
24+
}
25+
26+
template <uint32_t ms, uint32_t val>
27+
void thread_get_uint_msg(Queue<uint32_t, 1> *q)
28+
{
29+
Thread::wait(ms);
30+
osEvent evt = q->get();
31+
TEST_ASSERT_EQUAL(osEventMessage, evt.status);
32+
TEST_ASSERT_EQUAL(val, evt.value.v);
33+
}
34+
35+
/** Test pass uint msg
36+
37+
Given a queue for uint32_t messages with one slot
38+
When a uin32_t value is inserted into the queue
39+
and a message is extracted from the queue
40+
Then the extracted message is the same as previously inserted message
41+
*/
42+
void test_pass_uint()
43+
{
44+
Queue<uint32_t, 1> q;
45+
osStatus stat = q.put((uint32_t*)TEST_UINT_MSG);
46+
TEST_ASSERT_EQUAL(osOK, stat);
47+
48+
osEvent evt = q.get();
49+
TEST_ASSERT_EQUAL(osEventMessage, evt.status);
50+
TEST_ASSERT_EQUAL(TEST_UINT_MSG, evt.value.v);
51+
}
52+
53+
/** Test pass uint msg twice
54+
55+
Given a queue for uint32_t messages with one slot
56+
When a uin32_t value is inserted into the queue
57+
and a message is extracted from the queue
58+
and the procedure is repeated with different message
59+
Then the extracted message is the same as previously inserted message for both iterations
60+
61+
*/
62+
void test_pass_uint_twice()
63+
{
64+
Queue<uint32_t, 1> q;
65+
osStatus stat = q.put((uint32_t*)TEST_UINT_MSG);
66+
TEST_ASSERT_EQUAL(osOK, stat);
67+
68+
osEvent evt = q.get();
69+
TEST_ASSERT_EQUAL(osEventMessage, evt.status);
70+
TEST_ASSERT_EQUAL(TEST_UINT_MSG, evt.value.v);
71+
72+
stat = q.put((uint32_t*)TEST_UINT_MSG2);
73+
TEST_ASSERT_EQUAL(osOK, stat);
74+
75+
evt = q.get();
76+
TEST_ASSERT_EQUAL(osEventMessage, evt.status);
77+
TEST_ASSERT_EQUAL(TEST_UINT_MSG2, evt.value.v);
78+
}
79+
80+
/** Test pass ptr msg
81+
82+
Given a queue for pointers to uint32_t messages with one slot
83+
When a pointer to an uint32_t is inserted into the queue
84+
and a message is extracted from the queue
85+
Then the extracted message is the same as previously inserted message
86+
*/
87+
void test_pass_ptr()
88+
{
89+
Queue<uint32_t, 1> q;
90+
uint32_t msg = TEST_UINT_MSG;
91+
92+
osStatus stat = q.put(&msg);
93+
TEST_ASSERT_EQUAL(osOK, stat);
94+
95+
osEvent evt = q.get();
96+
TEST_ASSERT_EQUAL(osEventMessage, evt.status);
97+
TEST_ASSERT_EQUAL(&msg, evt.value.p);
98+
}
99+
100+
/** Test get from empty queue
101+
102+
Given an empty queue for uint32_t values
103+
When @a get is called on the queue with timeout of 0
104+
Then queue returns status of osOK, but no data
105+
*/
106+
void test_get_empty_no_timeout()
107+
{
108+
Queue<uint32_t, 1> q;
109+
110+
osEvent evt = q.get(0);
111+
TEST_ASSERT_EQUAL(osOK, evt.status);
112+
}
113+
114+
/** Test get from empty queue with timeout
115+
116+
Given an empty queue for uint32_t values
117+
When @a get is called on the queue with timeout of 50ms
118+
Then queue returns status of osEventTimeout after about 50ms wait
119+
*/
120+
void test_get_empty_timeout()
121+
{
122+
Queue<uint32_t, 1> q;
123+
uint32_t start = us_ticker_read();
124+
125+
osEvent evt = q.get(50);
126+
TEST_ASSERT_EQUAL(osEventTimeout, evt.status);
127+
TEST_ASSERT_UINT32_WITHIN(5000, 50000, us_ticker_read() - start);
128+
}
129+
130+
/** Test get empty wait forever
131+
132+
Given a two threads A & B and a queue for uint32_t values
133+
When thread A calls @a get on an empty queue with osWaitForever
134+
Then the thread A waits for a message to appear in the queue
135+
When thread B puts a message in the queue
136+
Then thread A wakes up and receives it
137+
*/
138+
void test_get_empty_wait_forever()
139+
{
140+
Thread t(osPriorityNormal, THREAD_STACK_SIZE);
141+
Queue<uint32_t, 1> q;
142+
143+
t.start(callback(thread_put_uint_msg<TEST_TIMEOUT>, &q));
144+
145+
uint32_t start = us_ticker_read();
146+
147+
osEvent evt = q.get();
148+
TEST_ASSERT_EQUAL(osEventMessage, evt.status);
149+
TEST_ASSERT_EQUAL(TEST_UINT_MSG, evt.value.v);
150+
TEST_ASSERT_UINT32_WITHIN(TEST_TIMEOUT * 100, TEST_TIMEOUT * 1000, us_ticker_read() - start);
37151
}
38152

39-
int main (void) {
40-
GREENTEA_SETUP(20, "default_auto");
41-
42-
Thread thread(osPriorityNormal, TEST_STACK_SIZE);
43-
thread.start(send_thread);
44-
bool result = true;
45-
int result_counter = 0;
46-
47-
while (true) {
48-
osEvent evt = queue.get();
49-
if (evt.status == osEventMessage) {
50-
message_t *message = (message_t*)evt.value.p;
51-
const float expected_voltage = CREATE_VOLTAGE(message->counter);
52-
const float expected_current = CREATE_CURRENT(message->counter);
53-
// Check using macros if received values correspond to values sent via queue
54-
bool expected_values = (expected_voltage == message->voltage) &&
55-
(expected_current == message->current);
56-
result = result && expected_values;
57-
const char *result_msg = expected_values ? "OK" : "FAIL";
58-
printf("%3d %.2fV %.2fA ... [%s]\r\n", message->counter,
59-
message->voltage,
60-
message->current,
61-
result_msg);
62-
mpool.free(message);
63-
if (result == false || ++result_counter == QUEUE_SIZE) {
64-
break;
65-
}
66-
}
67-
}
68-
GREENTEA_TESTSUITE_RESULT(result);
69-
return 0;
153+
/** Test put full no timeout
154+
*
155+
* Given a queue with one slot for uint32_t data
156+
* When a thread tries to insert two messages
157+
* Then first operation succeeds and second fails with @a osErrorResource
158+
*/
159+
void test_put_full_no_timeout()
160+
{
161+
Queue<uint32_t, 1> q;
162+
163+
osStatus stat = q.put((uint32_t*) TEST_UINT_MSG);
164+
TEST_ASSERT_EQUAL(osOK, stat);
165+
166+
stat = q.put((uint32_t*) TEST_UINT_MSG);
167+
TEST_ASSERT_EQUAL(osErrorResource, stat);
168+
}
169+
170+
/** Test put full timeout
171+
*
172+
* Given a queue with one slot for uint32_t data
173+
* When a thread tries to insert two messages with @ TEST_TIMEOUT timeout
174+
* Then first operation succeeds and second fails with @a osErrorTimeout
175+
*/
176+
void test_put_full_timeout()
177+
{
178+
Queue<uint32_t, 1> q;
179+
180+
osStatus stat = q.put((uint32_t*) TEST_UINT_MSG, TEST_TIMEOUT);
181+
TEST_ASSERT_EQUAL(osOK, stat);
182+
183+
uint32_t start = us_ticker_read();
184+
185+
stat = q.put((uint32_t*) TEST_UINT_MSG, TEST_TIMEOUT);
186+
TEST_ASSERT_EQUAL(osErrorTimeout, stat);
187+
TEST_ASSERT_UINT32_WITHIN(TEST_TIMEOUT * 100, TEST_TIMEOUT * 1000, us_ticker_read() - start);
188+
}
189+
190+
/** Test put full wait forever
191+
*
192+
* Given two threads A & B and a queue with one slot for uint32_t data
193+
* When thread A puts a message to the queue and tries to put second one with @a osWaitForever timeout
194+
* Then thread waits for a slot to become empty in the queue
195+
* When thread B takes one message out of the queue
196+
* Then thread A successfully inserts message into the queue
197+
*/
198+
void test_put_full_waitforever()
199+
{
200+
Thread t(osPriorityNormal, THREAD_STACK_SIZE);
201+
Queue<uint32_t, 1> q;
202+
203+
t.start(callback(thread_get_uint_msg<TEST_TIMEOUT, TEST_UINT_MSG>, &q));
204+
205+
osStatus stat = q.put((uint32_t*) TEST_UINT_MSG);
206+
TEST_ASSERT_EQUAL(osOK, stat);
207+
208+
uint32_t start = us_ticker_read();
209+
stat = q.put((uint32_t*) TEST_UINT_MSG, osWaitForever);
210+
TEST_ASSERT_EQUAL(osOK, stat);
211+
TEST_ASSERT_UINT32_WITHIN(TEST_TIMEOUT * 100, TEST_TIMEOUT * 1000, us_ticker_read() - start);
212+
213+
t.join();
214+
}
215+
216+
/** Test message ordering
217+
218+
Given a queue of uint32_t data
219+
When two messages are inserted with equal priority
220+
Then messages should be returned in the exact order they were inserted
221+
*/
222+
void test_msg_order()
223+
{
224+
Queue<uint32_t, 2> q;
225+
226+
osStatus stat = q.put((uint32_t*) TEST_UINT_MSG, TEST_TIMEOUT);
227+
TEST_ASSERT_EQUAL(osOK, stat);
228+
229+
stat = q.put((uint32_t*) TEST_UINT_MSG2, TEST_TIMEOUT);
230+
TEST_ASSERT_EQUAL(osOK, stat);
231+
232+
osEvent evt = q.get();
233+
TEST_ASSERT_EQUAL(osEventMessage, evt.status);
234+
TEST_ASSERT_EQUAL(TEST_UINT_MSG, evt.value.v);
235+
236+
evt = q.get();
237+
TEST_ASSERT_EQUAL(osEventMessage, evt.status);
238+
TEST_ASSERT_EQUAL(TEST_UINT_MSG2, evt.value.v);
239+
}
240+
241+
/** Test message priority
242+
243+
Given a queue of uint32_t data
244+
When two messages are inserted with ascending priority
245+
Then messages should be returned in descending priority order
246+
*/
247+
void test_msg_prio()
248+
{
249+
Queue<uint32_t, 2> q;
250+
251+
osStatus stat = q.put((uint32_t*) TEST_UINT_MSG, TEST_TIMEOUT, 0);
252+
TEST_ASSERT_EQUAL(osOK, stat);
253+
254+
stat = q.put((uint32_t*) TEST_UINT_MSG2, TEST_TIMEOUT, 1);
255+
TEST_ASSERT_EQUAL(osOK, stat);
256+
257+
osEvent evt = q.get();
258+
TEST_ASSERT_EQUAL(osEventMessage, evt.status);
259+
TEST_ASSERT_EQUAL(TEST_UINT_MSG2, evt.value.v);
260+
261+
evt = q.get();
262+
TEST_ASSERT_EQUAL(osEventMessage, evt.status);
263+
TEST_ASSERT_EQUAL(TEST_UINT_MSG, evt.value.v);
264+
}
265+
266+
utest::v1::status_t test_setup(const size_t number_of_cases)
267+
{
268+
GREENTEA_SETUP(5, "default_auto");
269+
return verbose_test_setup_handler(number_of_cases);
270+
}
271+
272+
Case cases[] = {
273+
Case("Test pass uint msg", test_pass_uint),
274+
Case("Test pass uint msg twice", test_pass_uint_twice),
275+
Case("Test pass ptr msg", test_pass_ptr),
276+
Case("Test get from empty queue no timeout", test_get_empty_no_timeout),
277+
Case("Test get from empty queue timeout", test_get_empty_timeout),
278+
Case("Test get empty wait forever", test_get_empty_wait_forever),
279+
Case("Test put full no timeout", test_put_full_no_timeout),
280+
Case("Test put full timeout", test_put_full_timeout),
281+
Case("Test put full wait forever", test_put_full_waitforever),
282+
Case("Test message ordering", test_msg_order),
283+
Case("Test message priority", test_msg_prio)
284+
};
285+
286+
Specification specification(test_setup, cases);
287+
288+
int main()
289+
{
290+
return !Harness::run(specification);
70291
}

rtos/Queue.h

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,15 +68,24 @@ class Queue : private mbed::NonCopyable<Queue<T, queue_sz> > {
6868
@param data message pointer.
6969
@param millisec timeout value or 0 in case of no time-out. (default: 0)
7070
@param prio priority value or 0 in case of default. (default: 0)
71-
@return status code that indicates the execution status of the function.
71+
@return status code that indicates the execution status of the function:
72+
@a osOK the message has been put into the queue.
73+
@a osErrorTimeout the message could not be put into the queue in the given time.
74+
@a osErrorResource not enough space in the queue.
75+
@a osErrorParameter internal error or non-zero timeout specified in an ISR.
7276
*/
7377
osStatus put(T* data, uint32_t millisec=0, uint8_t prio=0) {
7478
return osMessageQueuePut(_id, &data, prio, millisec);
7579
}
7680

77-
/** Get a message or Wait for a message from a Queue.
81+
/** Get a message or Wait for a message from a Queue. Messages are retrieved in a descending priority order or
82+
first in first out when the priorities are the same.
7883
@param millisec timeout value or 0 in case of no time-out. (default: osWaitForever).
79-
@return event information that includes the message and the status code.
84+
@return event information that includes the message in event.value and the status code in event.status:
85+
@a osEventMessage message received.
86+
@a osOK no message is available in the queue and no timeout was specified.
87+
@a osEventTimeout no message has arrived during the given timeout period.
88+
@a osErrorParameter a parameter is invalid or outside of a permitted range.
8089
*/
8190
osEvent get(uint32_t millisec=osWaitForever) {
8291
osEvent event;

0 commit comments

Comments
 (0)