mirror of https://github.com/ARMmbed/mbed-os.git
commit
a81783e177
|
@ -1,70 +1,291 @@
|
||||||
#include "mbed.h"
|
#include "mbed.h"
|
||||||
#include "greentea-client/test_env.h"
|
#include "greentea-client/test_env.h"
|
||||||
|
#include "unity.h"
|
||||||
|
#include "utest.h"
|
||||||
#include "rtos.h"
|
#include "rtos.h"
|
||||||
|
|
||||||
#if defined(MBED_RTOS_SINGLE_THREAD)
|
#if defined(MBED_RTOS_SINGLE_THREAD)
|
||||||
#error [NOT_SUPPORTED] test not supported
|
#error [NOT_SUPPORTED] test not supported
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct {
|
using namespace utest::v1;
|
||||||
float voltage; /* AD result of measured voltage */
|
|
||||||
float current; /* AD result of measured current */
|
|
||||||
uint32_t counter; /* A counter value */
|
|
||||||
} message_t;
|
|
||||||
|
|
||||||
#define CREATE_VOLTAGE(COUNTER) (COUNTER * 0.1) * 33
|
#define THREAD_STACK_SIZE 512
|
||||||
#define CREATE_CURRENT(COUNTER) (COUNTER * 0.1) * 11
|
#define TEST_UINT_MSG 0xDEADBEEF
|
||||||
#define QUEUE_SIZE 16
|
#define TEST_UINT_MSG2 0xE1EE7
|
||||||
#define QUEUE_PUT_DELAY 100
|
#define TEST_TIMEOUT 50
|
||||||
|
|
||||||
#define TEST_STACK_SIZE 512
|
template <uint32_t ms>
|
||||||
|
void thread_put_uint_msg(Queue<uint32_t, 1> *q)
|
||||||
MemoryPool<message_t, QUEUE_SIZE> mpool;
|
{
|
||||||
Queue<message_t, QUEUE_SIZE> queue;
|
Thread::wait(ms);
|
||||||
|
osStatus stat = q->put((uint32_t*) TEST_UINT_MSG);
|
||||||
/* Send Thread */
|
TEST_ASSERT_EQUAL(osOK, stat);
|
||||||
void send_thread () {
|
|
||||||
static uint32_t i = 10;
|
|
||||||
while (true) {
|
|
||||||
i++; // Fake data update
|
|
||||||
message_t *message = mpool.alloc();
|
|
||||||
message->voltage = CREATE_VOLTAGE(i);
|
|
||||||
message->current = CREATE_CURRENT(i);
|
|
||||||
message->counter = i;
|
|
||||||
queue.put(message);
|
|
||||||
Thread::wait(QUEUE_PUT_DELAY);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main (void) {
|
template <uint32_t ms, uint32_t val>
|
||||||
GREENTEA_SETUP(20, "default_auto");
|
void thread_get_uint_msg(Queue<uint32_t, 1> *q)
|
||||||
|
{
|
||||||
Thread thread(osPriorityNormal, TEST_STACK_SIZE);
|
Thread::wait(ms);
|
||||||
thread.start(send_thread);
|
osEvent evt = q->get();
|
||||||
bool result = true;
|
TEST_ASSERT_EQUAL(osEventMessage, evt.status);
|
||||||
int result_counter = 0;
|
TEST_ASSERT_EQUAL(val, evt.value.v);
|
||||||
|
}
|
||||||
while (true) {
|
|
||||||
osEvent evt = queue.get();
|
/** Test pass uint msg
|
||||||
if (evt.status == osEventMessage) {
|
|
||||||
message_t *message = (message_t*)evt.value.p;
|
Given a queue for uint32_t messages with one slot
|
||||||
const float expected_voltage = CREATE_VOLTAGE(message->counter);
|
When a uin32_t value is inserted into the queue
|
||||||
const float expected_current = CREATE_CURRENT(message->counter);
|
and a message is extracted from the queue
|
||||||
// Check using macros if received values correspond to values sent via queue
|
Then the extracted message is the same as previously inserted message
|
||||||
bool expected_values = (expected_voltage == message->voltage) &&
|
*/
|
||||||
(expected_current == message->current);
|
void test_pass_uint()
|
||||||
result = result && expected_values;
|
{
|
||||||
const char *result_msg = expected_values ? "OK" : "FAIL";
|
Queue<uint32_t, 1> q;
|
||||||
printf("%3d %.2fV %.2fA ... [%s]\r\n", message->counter,
|
osStatus stat = q.put((uint32_t*)TEST_UINT_MSG);
|
||||||
message->voltage,
|
TEST_ASSERT_EQUAL(osOK, stat);
|
||||||
message->current,
|
|
||||||
result_msg);
|
osEvent evt = q.get();
|
||||||
mpool.free(message);
|
TEST_ASSERT_EQUAL(osEventMessage, evt.status);
|
||||||
if (result == false || ++result_counter == QUEUE_SIZE) {
|
TEST_ASSERT_EQUAL(TEST_UINT_MSG, evt.value.v);
|
||||||
break;
|
}
|
||||||
}
|
|
||||||
}
|
/** Test pass uint msg twice
|
||||||
}
|
|
||||||
GREENTEA_TESTSUITE_RESULT(result);
|
Given a queue for uint32_t messages with one slot
|
||||||
return 0;
|
When a uin32_t value is inserted into the queue
|
||||||
|
and a message is extracted from the queue
|
||||||
|
and the procedure is repeated with different message
|
||||||
|
Then the extracted message is the same as previously inserted message for both iterations
|
||||||
|
|
||||||
|
*/
|
||||||
|
void test_pass_uint_twice()
|
||||||
|
{
|
||||||
|
Queue<uint32_t, 1> q;
|
||||||
|
osStatus stat = q.put((uint32_t*)TEST_UINT_MSG);
|
||||||
|
TEST_ASSERT_EQUAL(osOK, stat);
|
||||||
|
|
||||||
|
osEvent evt = q.get();
|
||||||
|
TEST_ASSERT_EQUAL(osEventMessage, evt.status);
|
||||||
|
TEST_ASSERT_EQUAL(TEST_UINT_MSG, evt.value.v);
|
||||||
|
|
||||||
|
stat = q.put((uint32_t*)TEST_UINT_MSG2);
|
||||||
|
TEST_ASSERT_EQUAL(osOK, stat);
|
||||||
|
|
||||||
|
evt = q.get();
|
||||||
|
TEST_ASSERT_EQUAL(osEventMessage, evt.status);
|
||||||
|
TEST_ASSERT_EQUAL(TEST_UINT_MSG2, evt.value.v);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Test pass ptr msg
|
||||||
|
|
||||||
|
Given a queue for pointers to uint32_t messages with one slot
|
||||||
|
When a pointer to an uint32_t is inserted into the queue
|
||||||
|
and a message is extracted from the queue
|
||||||
|
Then the extracted message is the same as previously inserted message
|
||||||
|
*/
|
||||||
|
void test_pass_ptr()
|
||||||
|
{
|
||||||
|
Queue<uint32_t, 1> q;
|
||||||
|
uint32_t msg = TEST_UINT_MSG;
|
||||||
|
|
||||||
|
osStatus stat = q.put(&msg);
|
||||||
|
TEST_ASSERT_EQUAL(osOK, stat);
|
||||||
|
|
||||||
|
osEvent evt = q.get();
|
||||||
|
TEST_ASSERT_EQUAL(osEventMessage, evt.status);
|
||||||
|
TEST_ASSERT_EQUAL(&msg, evt.value.p);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Test get from empty queue
|
||||||
|
|
||||||
|
Given an empty queue for uint32_t values
|
||||||
|
When @a get is called on the queue with timeout of 0
|
||||||
|
Then queue returns status of osOK, but no data
|
||||||
|
*/
|
||||||
|
void test_get_empty_no_timeout()
|
||||||
|
{
|
||||||
|
Queue<uint32_t, 1> q;
|
||||||
|
|
||||||
|
osEvent evt = q.get(0);
|
||||||
|
TEST_ASSERT_EQUAL(osOK, evt.status);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Test get from empty queue with timeout
|
||||||
|
|
||||||
|
Given an empty queue for uint32_t values
|
||||||
|
When @a get is called on the queue with timeout of 50ms
|
||||||
|
Then queue returns status of osEventTimeout after about 50ms wait
|
||||||
|
*/
|
||||||
|
void test_get_empty_timeout()
|
||||||
|
{
|
||||||
|
Queue<uint32_t, 1> q;
|
||||||
|
uint32_t start = us_ticker_read();
|
||||||
|
|
||||||
|
osEvent evt = q.get(50);
|
||||||
|
TEST_ASSERT_EQUAL(osEventTimeout, evt.status);
|
||||||
|
TEST_ASSERT_UINT32_WITHIN(5000, 50000, us_ticker_read() - start);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Test get empty wait forever
|
||||||
|
|
||||||
|
Given a two threads A & B and a queue for uint32_t values
|
||||||
|
When thread A calls @a get on an empty queue with osWaitForever
|
||||||
|
Then the thread A waits for a message to appear in the queue
|
||||||
|
When thread B puts a message in the queue
|
||||||
|
Then thread A wakes up and receives it
|
||||||
|
*/
|
||||||
|
void test_get_empty_wait_forever()
|
||||||
|
{
|
||||||
|
Thread t(osPriorityNormal, THREAD_STACK_SIZE);
|
||||||
|
Queue<uint32_t, 1> q;
|
||||||
|
|
||||||
|
t.start(callback(thread_put_uint_msg<TEST_TIMEOUT>, &q));
|
||||||
|
|
||||||
|
uint32_t start = us_ticker_read();
|
||||||
|
|
||||||
|
osEvent evt = q.get();
|
||||||
|
TEST_ASSERT_EQUAL(osEventMessage, evt.status);
|
||||||
|
TEST_ASSERT_EQUAL(TEST_UINT_MSG, evt.value.v);
|
||||||
|
TEST_ASSERT_UINT32_WITHIN(TEST_TIMEOUT * 100, TEST_TIMEOUT * 1000, us_ticker_read() - start);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Test put full no timeout
|
||||||
|
*
|
||||||
|
* Given a queue with one slot for uint32_t data
|
||||||
|
* When a thread tries to insert two messages
|
||||||
|
* Then first operation succeeds and second fails with @a osErrorResource
|
||||||
|
*/
|
||||||
|
void test_put_full_no_timeout()
|
||||||
|
{
|
||||||
|
Queue<uint32_t, 1> q;
|
||||||
|
|
||||||
|
osStatus stat = q.put((uint32_t*) TEST_UINT_MSG);
|
||||||
|
TEST_ASSERT_EQUAL(osOK, stat);
|
||||||
|
|
||||||
|
stat = q.put((uint32_t*) TEST_UINT_MSG);
|
||||||
|
TEST_ASSERT_EQUAL(osErrorResource, stat);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Test put full timeout
|
||||||
|
*
|
||||||
|
* Given a queue with one slot for uint32_t data
|
||||||
|
* When a thread tries to insert two messages with @ TEST_TIMEOUT timeout
|
||||||
|
* Then first operation succeeds and second fails with @a osErrorTimeout
|
||||||
|
*/
|
||||||
|
void test_put_full_timeout()
|
||||||
|
{
|
||||||
|
Queue<uint32_t, 1> q;
|
||||||
|
|
||||||
|
osStatus stat = q.put((uint32_t*) TEST_UINT_MSG, TEST_TIMEOUT);
|
||||||
|
TEST_ASSERT_EQUAL(osOK, stat);
|
||||||
|
|
||||||
|
uint32_t start = us_ticker_read();
|
||||||
|
|
||||||
|
stat = q.put((uint32_t*) TEST_UINT_MSG, TEST_TIMEOUT);
|
||||||
|
TEST_ASSERT_EQUAL(osErrorTimeout, stat);
|
||||||
|
TEST_ASSERT_UINT32_WITHIN(TEST_TIMEOUT * 100, TEST_TIMEOUT * 1000, us_ticker_read() - start);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Test put full wait forever
|
||||||
|
*
|
||||||
|
* Given two threads A & B and a queue with one slot for uint32_t data
|
||||||
|
* When thread A puts a message to the queue and tries to put second one with @a osWaitForever timeout
|
||||||
|
* Then thread waits for a slot to become empty in the queue
|
||||||
|
* When thread B takes one message out of the queue
|
||||||
|
* Then thread A successfully inserts message into the queue
|
||||||
|
*/
|
||||||
|
void test_put_full_waitforever()
|
||||||
|
{
|
||||||
|
Thread t(osPriorityNormal, THREAD_STACK_SIZE);
|
||||||
|
Queue<uint32_t, 1> q;
|
||||||
|
|
||||||
|
t.start(callback(thread_get_uint_msg<TEST_TIMEOUT, TEST_UINT_MSG>, &q));
|
||||||
|
|
||||||
|
osStatus stat = q.put((uint32_t*) TEST_UINT_MSG);
|
||||||
|
TEST_ASSERT_EQUAL(osOK, stat);
|
||||||
|
|
||||||
|
uint32_t start = us_ticker_read();
|
||||||
|
stat = q.put((uint32_t*) TEST_UINT_MSG, osWaitForever);
|
||||||
|
TEST_ASSERT_EQUAL(osOK, stat);
|
||||||
|
TEST_ASSERT_UINT32_WITHIN(TEST_TIMEOUT * 100, TEST_TIMEOUT * 1000, us_ticker_read() - start);
|
||||||
|
|
||||||
|
t.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Test message ordering
|
||||||
|
|
||||||
|
Given a queue of uint32_t data
|
||||||
|
When two messages are inserted with equal priority
|
||||||
|
Then messages should be returned in the exact order they were inserted
|
||||||
|
*/
|
||||||
|
void test_msg_order()
|
||||||
|
{
|
||||||
|
Queue<uint32_t, 2> q;
|
||||||
|
|
||||||
|
osStatus stat = q.put((uint32_t*) TEST_UINT_MSG, TEST_TIMEOUT);
|
||||||
|
TEST_ASSERT_EQUAL(osOK, stat);
|
||||||
|
|
||||||
|
stat = q.put((uint32_t*) TEST_UINT_MSG2, TEST_TIMEOUT);
|
||||||
|
TEST_ASSERT_EQUAL(osOK, stat);
|
||||||
|
|
||||||
|
osEvent evt = q.get();
|
||||||
|
TEST_ASSERT_EQUAL(osEventMessage, evt.status);
|
||||||
|
TEST_ASSERT_EQUAL(TEST_UINT_MSG, evt.value.v);
|
||||||
|
|
||||||
|
evt = q.get();
|
||||||
|
TEST_ASSERT_EQUAL(osEventMessage, evt.status);
|
||||||
|
TEST_ASSERT_EQUAL(TEST_UINT_MSG2, evt.value.v);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Test message priority
|
||||||
|
|
||||||
|
Given a queue of uint32_t data
|
||||||
|
When two messages are inserted with ascending priority
|
||||||
|
Then messages should be returned in descending priority order
|
||||||
|
*/
|
||||||
|
void test_msg_prio()
|
||||||
|
{
|
||||||
|
Queue<uint32_t, 2> q;
|
||||||
|
|
||||||
|
osStatus stat = q.put((uint32_t*) TEST_UINT_MSG, TEST_TIMEOUT, 0);
|
||||||
|
TEST_ASSERT_EQUAL(osOK, stat);
|
||||||
|
|
||||||
|
stat = q.put((uint32_t*) TEST_UINT_MSG2, TEST_TIMEOUT, 1);
|
||||||
|
TEST_ASSERT_EQUAL(osOK, stat);
|
||||||
|
|
||||||
|
osEvent evt = q.get();
|
||||||
|
TEST_ASSERT_EQUAL(osEventMessage, evt.status);
|
||||||
|
TEST_ASSERT_EQUAL(TEST_UINT_MSG2, evt.value.v);
|
||||||
|
|
||||||
|
evt = q.get();
|
||||||
|
TEST_ASSERT_EQUAL(osEventMessage, evt.status);
|
||||||
|
TEST_ASSERT_EQUAL(TEST_UINT_MSG, evt.value.v);
|
||||||
|
}
|
||||||
|
|
||||||
|
utest::v1::status_t test_setup(const size_t number_of_cases)
|
||||||
|
{
|
||||||
|
GREENTEA_SETUP(5, "default_auto");
|
||||||
|
return verbose_test_setup_handler(number_of_cases);
|
||||||
|
}
|
||||||
|
|
||||||
|
Case cases[] = {
|
||||||
|
Case("Test pass uint msg", test_pass_uint),
|
||||||
|
Case("Test pass uint msg twice", test_pass_uint_twice),
|
||||||
|
Case("Test pass ptr msg", test_pass_ptr),
|
||||||
|
Case("Test get from empty queue no timeout", test_get_empty_no_timeout),
|
||||||
|
Case("Test get from empty queue timeout", test_get_empty_timeout),
|
||||||
|
Case("Test get empty wait forever", test_get_empty_wait_forever),
|
||||||
|
Case("Test put full no timeout", test_put_full_no_timeout),
|
||||||
|
Case("Test put full timeout", test_put_full_timeout),
|
||||||
|
Case("Test put full wait forever", test_put_full_waitforever),
|
||||||
|
Case("Test message ordering", test_msg_order),
|
||||||
|
Case("Test message priority", test_msg_prio)
|
||||||
|
};
|
||||||
|
|
||||||
|
Specification specification(test_setup, cases);
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
return !Harness::run(specification);
|
||||||
}
|
}
|
||||||
|
|
15
rtos/Queue.h
15
rtos/Queue.h
|
@ -68,15 +68,24 @@ public:
|
||||||
@param data message pointer.
|
@param data message pointer.
|
||||||
@param millisec timeout value or 0 in case of no time-out. (default: 0)
|
@param millisec timeout value or 0 in case of no time-out. (default: 0)
|
||||||
@param prio priority value or 0 in case of default. (default: 0)
|
@param prio priority value or 0 in case of default. (default: 0)
|
||||||
@return status code that indicates the execution status of the function.
|
@return status code that indicates the execution status of the function:
|
||||||
|
@a osOK the message has been put into the queue.
|
||||||
|
@a osErrorTimeout the message could not be put into the queue in the given time.
|
||||||
|
@a osErrorResource not enough space in the queue.
|
||||||
|
@a osErrorParameter internal error or non-zero timeout specified in an ISR.
|
||||||
*/
|
*/
|
||||||
osStatus put(T* data, uint32_t millisec=0, uint8_t prio=0) {
|
osStatus put(T* data, uint32_t millisec=0, uint8_t prio=0) {
|
||||||
return osMessageQueuePut(_id, &data, prio, millisec);
|
return osMessageQueuePut(_id, &data, prio, millisec);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get a message or Wait for a message from a Queue.
|
/** Get a message or Wait for a message from a Queue. Messages are retrieved in a descending priority order or
|
||||||
|
first in first out when the priorities are the same.
|
||||||
@param millisec timeout value or 0 in case of no time-out. (default: osWaitForever).
|
@param millisec timeout value or 0 in case of no time-out. (default: osWaitForever).
|
||||||
@return event information that includes the message and the status code.
|
@return event information that includes the message in event.value and the status code in event.status:
|
||||||
|
@a osEventMessage message received.
|
||||||
|
@a osOK no message is available in the queue and no timeout was specified.
|
||||||
|
@a osEventTimeout no message has arrived during the given timeout period.
|
||||||
|
@a osErrorParameter a parameter is invalid or outside of a permitted range.
|
||||||
*/
|
*/
|
||||||
osEvent get(uint32_t millisec=osWaitForever) {
|
osEvent get(uint32_t millisec=osWaitForever) {
|
||||||
osEvent event;
|
osEvent event;
|
||||||
|
|
Loading…
Reference in New Issue