Denislam Valeev
/
Nucleo_rtos_basic
1
mbed-os/TESTS/mbedmicro-rtos-mbed/mail/main.cpp
- Committer:
- valeyev
- Date:
- 2018-03-13
- Revision:
- 0:e056ac8fecf8
File content as of revision 0:e056ac8fecf8:
/* mbed Microcontroller Library * Copyright (c) 2017 ARM Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mbed.h" #include "greentea-client/test_env.h" #include "unity.h" #include "utest.h" #include "rtos.h" #if defined(MBED_RTOS_SINGLE_THREAD) #error [NOT_SUPPORTED] test not supported #endif using namespace utest::v1; #define THREAD_STACK_SIZE 320 /* larger stack cause out of heap memory on some 16kB RAM boards in multi thread test*/ #define QUEUE_SIZE 16 #define THREAD_1_ID 1 #define THREAD_2_ID 2 #define THREAD_3_ID 3 #define QUEUE_PUT_DELAY_1 5 #define QUEUE_PUT_DELAY_2 50 #define QUEUE_PUT_DELAY_3 100 #define DATA_BASE 100 typedef struct { uint16_t data; uint8_t thread_id; } mail_t; template<uint8_t thread_id, uint32_t wait_ms, uint32_t send_count> void send_thread(Mail<mail_t, QUEUE_SIZE> *m) { uint32_t data = thread_id * DATA_BASE; for (uint32_t i = 0; i < send_count; i++) { mail_t *mail = m->alloc(); mail->thread_id = thread_id; mail->data = data++; m->put(mail); Thread::wait(wait_ms); } } template<uint8_t thread_id, uint32_t queue_size, uint32_t wait_ms> void receive_thread(Mail<mail_t, queue_size> *m) { int result_counter = 0; uint32_t data = thread_id * DATA_BASE; Thread::wait(wait_ms); for (uint32_t i = 0; i < queue_size; i++) { osEvent evt = m->get(); if (evt.status == osEventMail) { mail_t *mail = (mail_t*)evt.value.p; const uint8_t id = mail->thread_id; // verify thread id TEST_ASSERT_TRUE(id == thread_id); // verify sent data TEST_ASSERT_TRUE(mail->data == data++); m->free(mail); result_counter++; } } TEST_ASSERT_EQUAL(queue_size, result_counter); } /** Test single thread Mail usage and order Given mailbox and one additional thread When messages are put in to the Mail box by this thread Then messages are received in main thread in the same order as was sent and the data sent is valid */ void test_single_thread_order(void) { uint16_t data = DATA_BASE; int result_counter = 0; Mail<mail_t, QUEUE_SIZE> mail_box; // mail send thread creation Thread thread(osPriorityNormal, THREAD_STACK_SIZE); thread.start(callback(send_thread<THREAD_1_ID, QUEUE_PUT_DELAY_1, QUEUE_SIZE>, &mail_box)); // wait for some mail to be collected Thread::wait(10); for (uint32_t i = 0; i < QUEUE_SIZE; i++) { // mail receive (main thread) osEvent evt = mail_box.get(); if (evt.status == osEventMail) { mail_t *mail = (mail_t*)evt.value.p; const uint8_t id = mail->thread_id; // verify thread id TEST_ASSERT_TRUE(id == THREAD_1_ID); // verify sent data TEST_ASSERT_TRUE(mail->data == data++); mail_box.free(mail); result_counter++; } } TEST_ASSERT_EQUAL(QUEUE_SIZE, result_counter); } /** Test multi thread Mail usage and order Given mailbox and three additional threads When messages are put in to the Mail box by these threads Then messages are received in main thread in the same per thread order as was sent and the data sent is valid */ void test_multi_thread_order(void) { uint16_t data[4] = { 0, DATA_BASE, DATA_BASE * 2, DATA_BASE * 3 }; int result_counter = 0; Mail<mail_t, QUEUE_SIZE> mail_box; // mail send threads creation Thread thread1(osPriorityNormal, THREAD_STACK_SIZE); Thread thread2(osPriorityNormal, THREAD_STACK_SIZE); Thread thread3(osPriorityNormal, THREAD_STACK_SIZE); thread1.start(callback(send_thread<THREAD_1_ID, QUEUE_PUT_DELAY_1, 7>, &mail_box)); thread2.start(callback(send_thread<THREAD_2_ID, QUEUE_PUT_DELAY_2, 5>, &mail_box)); thread3.start(callback(send_thread<THREAD_3_ID, QUEUE_PUT_DELAY_3, 4>, &mail_box)); // wait for some mail to be collected Thread::wait(10); for (uint32_t i = 0; i < QUEUE_SIZE; i++) { // mail receive (main thread) osEvent evt = mail_box.get(); if (evt.status == osEventMail) { mail_t *mail = (mail_t*)evt.value.p; const uint8_t id = mail->thread_id; // verify thread id TEST_ASSERT_TRUE((id == THREAD_1_ID) || (id == THREAD_2_ID) || (id == THREAD_3_ID)); // verify sent data TEST_ASSERT_TRUE(mail->data == data[id]++); mail_box.free(mail); result_counter++; } } TEST_ASSERT_EQUAL(QUEUE_SIZE, result_counter); } /** Test multi thread multi Mail usage and order Given 3 mailbox and three additional threads When messages are put in to the mail boxes by main thread Then messages are received by threads in the same per mail box order as was sent and the data sent is valid */ void test_multi_thread_multi_mail_order(void) { Mail<mail_t, 4> mail_box[4]; /* mail_box[0] not used */ uint16_t data[4] = { 0, DATA_BASE, DATA_BASE * 2, DATA_BASE * 3 }; mail_t *mail; uint8_t id; // mail receive threads creation Thread thread1(osPriorityNormal, THREAD_STACK_SIZE); Thread thread2(osPriorityNormal, THREAD_STACK_SIZE); Thread thread3(osPriorityNormal, THREAD_STACK_SIZE); thread1.start(callback(receive_thread<THREAD_1_ID, 4, 0>, mail_box + 1)); thread2.start(callback(receive_thread<THREAD_2_ID, 4, 10>, mail_box + 2)); thread3.start(callback(receive_thread<THREAD_3_ID, 4, 100>, mail_box + 3)); for (uint32_t i = 0; i < 4; i++) { id = THREAD_1_ID; mail = mail_box[id].alloc(); mail->thread_id = id; mail->data = data[id]++; mail_box[id].put(mail); id = THREAD_2_ID; mail = mail_box[id].alloc(); mail->thread_id = id; mail->data = data[id]++; mail_box[id].put(mail); id = THREAD_3_ID; mail = mail_box[id].alloc(); mail->thread_id = id; mail->data = data[id]++; mail_box[id].put(mail); Thread::wait(i * 10); } thread1.join(); thread2.join(); thread3.join(); } /** Test message memory deallocation with block out of the scope Given an empty mailbox When try to free out of the scope memory block Then it return appropriate error code */ void test_free_wrong() { osStatus status; Mail<uint32_t, 4> mail_box; uint32_t *mail, data; mail = &data; status = mail_box.free(mail); TEST_ASSERT_EQUAL(osErrorParameter, status); mail = mail_box.alloc(); TEST_ASSERT_NOT_EQUAL(NULL, mail); mail = &data; status = mail_box.free(mail); TEST_ASSERT_EQUAL(osErrorParameter, status); } /** Test message memory deallocation with null block Given an empty mailbox When try to free null ptr Then it return appropriate error code */ void test_free_null() { osStatus status; Mail<uint32_t, 4> mail_box; uint32_t *mail; mail = NULL; status = mail_box.free(mail); TEST_ASSERT_EQUAL(osErrorParameter, status); mail = mail_box.alloc(); TEST_ASSERT_NOT_EQUAL(NULL, mail); mail = NULL; status = mail_box.free(mail); TEST_ASSERT_EQUAL(osErrorParameter, status); } /** Test same message memory deallocation twice Given an empty mailbox Then allocate message memory When try to free it second time Then it return appropriate error code */ void test_free_twice() { osStatus status; Mail<uint32_t, 4> mail_box; uint32_t *mail = mail_box.alloc(); TEST_ASSERT_NOT_EQUAL(NULL, mail); status = mail_box.free(mail); TEST_ASSERT_EQUAL(osOK, status); status = mail_box.free(mail); TEST_ASSERT_EQUAL(osErrorResource, status); } /** Test get from empty mailbox with timeout set Given an empty mailbox When @a get is called on the mailbox with timeout of 50 Then mailbox returns status of osOK, but no data after specified amount of time */ void test_get_empty_timeout() { Mail<uint32_t, 4> mail_box; Timer timer; timer.start(); osEvent evt = mail_box.get(50); TEST_ASSERT_UINT32_WITHIN(5000, 50000, timer.read_us()); TEST_ASSERT_EQUAL(osEventTimeout, evt.status); } /** Test get from empty mailbox with 0 timeout Given an empty mailbox When @a get is called on the mailbox with timeout of 0 Then mailbox returns status of osOK, but no data */ void test_get_empty_no_timeout() { Mail<uint32_t, 4> mail_box; osEvent evt = mail_box.get(0); TEST_ASSERT_EQUAL(osOK, evt.status); } /** Test mail order Given an mailbox for uint32_t values Then allocate two mails and put them in to mailbox When call @a get it returns previously put mails Then mails should be in the same order as put */ void test_order(void) { osStatus status; osEvent evt; Mail<int32_t, 4> mail_box; const int32_t TEST_VAL1 = 123; const int32_t TEST_VAL2 = 456; int32_t *mail1 = mail_box.alloc(); TEST_ASSERT_NOT_EQUAL(NULL, mail1); *mail1 = TEST_VAL1; status = mail_box.put(mail1); TEST_ASSERT_EQUAL(osOK, status); int32_t *mail2 = mail_box.alloc(); TEST_ASSERT_NOT_EQUAL(NULL, mail2); *mail2 = TEST_VAL2; status = mail_box.put(mail2); TEST_ASSERT_EQUAL(osOK, status); evt = mail_box.get(); TEST_ASSERT_EQUAL(evt.status, osEventMail); mail1 = (int32_t*)evt.value.p; TEST_ASSERT_EQUAL(TEST_VAL1, *mail1); evt = mail_box.get(); TEST_ASSERT_EQUAL(evt.status, osEventMail); mail2 = (int32_t*)evt.value.p; TEST_ASSERT_EQUAL(TEST_VAL2, *mail2); status = mail_box.free(mail1); TEST_ASSERT_EQUAL(osOK, status); status = mail_box.free(mail2); TEST_ASSERT_EQUAL(osOK, status); } /** Test Mail box max size limit Given an Mail box with max size of 4 elements When call @a alloc four times it returns memory blocks Then the memory blocks should be valid When call @a alloc one more time it returns memory blocks Then the memory blocks should be not valid (NULL - no memory available) */ void test_max_size() { osStatus status; Mail<uint32_t, 4> mail_box; const uint32_t TEST_VAL = 123; // 1 OK uint32_t *mail1 = mail_box.alloc(); TEST_ASSERT_NOT_EQUAL(NULL, mail1); // 2 OK uint32_t *mail2 = mail_box.alloc(); TEST_ASSERT_NOT_EQUAL(NULL, mail2); // 3 OK uint32_t *mail3 = mail_box.alloc(); TEST_ASSERT_NOT_EQUAL(NULL, mail3); // 4 OK uint32_t *mail4 = mail_box.alloc(); TEST_ASSERT_NOT_EQUAL(NULL, mail4); // 5 KO uint32_t *mail5 = mail_box.alloc(); TEST_ASSERT_EQUAL(NULL, mail5); status = mail_box.free(mail1); TEST_ASSERT_EQUAL(osOK, status); status = mail_box.free(mail2); TEST_ASSERT_EQUAL(osOK, status); status = mail_box.free(mail3); TEST_ASSERT_EQUAL(osOK, status); status = mail_box.free(mail4); TEST_ASSERT_EQUAL(osOK, status); } /** Test mailbox of T type data Given an mailbox with T memory block type When allocate/put/get/free memory block Then all operations should succeed */ template<typename T> void test_data_type(void) { osStatus status; Mail<T, 4> mail_box; const T TEST_VAL = 123; T *mail = mail_box.alloc(); TEST_ASSERT_NOT_EQUAL(NULL, mail); *mail = TEST_VAL; status = mail_box.put(mail); TEST_ASSERT_EQUAL(osOK, status); osEvent evt = mail_box.get(); TEST_ASSERT_EQUAL(evt.status, osEventMail); mail = (T*)evt.value.p; TEST_ASSERT_EQUAL(TEST_VAL, *mail); status = mail_box.free(mail); TEST_ASSERT_EQUAL(osOK, status); } /** Test calloc - memory block allocation with resetting Given an empty Mail box When call @a calloc it returns allocated memory block Then the memory block should be valid and filled with zeros */ void test_calloc() { Mail<uint32_t, 1> mail_box; uint32_t *mail = mail_box.calloc(); TEST_ASSERT_NOT_EQUAL(NULL, mail); TEST_ASSERT_EQUAL(0, *mail); } /** Test mail empty Given a mail of uint32_t data before data is inserted the mail should be empty after data is inserted the mail shouldn't be empty */ void test_mail_empty() { Mail<mail_t, 1> m; mail_t *mail = m.alloc(); TEST_ASSERT_EQUAL(true, m.empty()); m.put(mail); TEST_ASSERT_EQUAL(false, m.empty()); } /** Test mail empty Given a mail of uint32_t data with size of 1 before data is inserted the mail shouldn't be full after data is inserted the mail should be full */ void test_mail_full() { Mail<mail_t, 1> m; mail_t *mail = m.alloc(); TEST_ASSERT_EQUAL(false, m.full()); m.put(mail); TEST_ASSERT_EQUAL(true, m.full()); } utest::v1::status_t test_setup(const size_t number_of_cases) { GREENTEA_SETUP(10, "default_auto"); return verbose_test_setup_handler(number_of_cases); } Case cases[] = { Case("Test calloc", test_calloc), Case("Test message type uint8", test_data_type<uint8_t>), Case("Test message type uint16", test_data_type<uint16_t>), Case("Test message type uint32", test_data_type<uint32_t>), Case("Test mailbox max size", test_max_size), Case("Test message send order", test_order), Case("Test get with timeout on empty mailbox", test_get_empty_timeout), Case("Test get without timeout on empty mailbox", test_get_empty_no_timeout), Case("Test message free twice", test_free_twice), Case("Test null message free", test_free_null), Case("Test invalid message free", test_free_wrong), Case("Test message send/receive single thread and order", test_single_thread_order), Case("Test message send/receive multi-thread and per thread order", test_multi_thread_order), Case("Test message send/receive multi-thread, multi-Mail and per thread order", test_multi_thread_multi_mail_order), Case("Test mail empty", test_mail_empty), Case("Test mail full", test_mail_full) }; Specification specification(test_setup, cases); int main() { return !Harness::run(specification); }