Knight KE / Mbed OS Game_Master
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 /* mbed Microcontroller Library
00002  * Copyright (c) 2017 ARM Limited
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 #include "mbed.h"
00017 #include "greentea-client/test_env.h"
00018 #include "unity.h"
00019 #include "utest.h"
00020 #include "rtos.h"
00021 
00022 #if defined(MBED_RTOS_SINGLE_THREAD)
00023   #error [NOT_SUPPORTED] test not supported
00024 #endif
00025 
00026 #if !DEVICE_USTICKER
00027   #error [NOT_SUPPORTED] test not supported
00028 #endif
00029 
00030 using namespace utest::v1;
00031 
00032 #define THREAD_STACK_SIZE   320 /* larger stack cause out of heap memory on some 16kB RAM boards in multi thread test*/
00033 #define QUEUE_SIZE          16
00034 #define THREAD_1_ID         1
00035 #define THREAD_2_ID         2
00036 #define THREAD_3_ID         3
00037 #define QUEUE_PUT_DELAY_1   5
00038 #define QUEUE_PUT_DELAY_2   50
00039 #define QUEUE_PUT_DELAY_3   100
00040 #define DATA_BASE           100
00041 
00042 
00043 typedef struct {
00044     uint16_t data;
00045     uint8_t thread_id;
00046 } mail_t;
00047 
00048 
00049 template<uint8_t thread_id, uint32_t wait_ms, uint32_t send_count>
00050 void send_thread(Mail<mail_t, QUEUE_SIZE> *m)
00051 {
00052     uint32_t data = thread_id * DATA_BASE;
00053 
00054     for (uint32_t i = 0; i < send_count; i++) {
00055         mail_t *mail = m->alloc();
00056         mail->thread_id = thread_id;
00057         mail->data = data++;
00058         m->put(mail);
00059         Thread::wait(wait_ms);
00060     }
00061 }
00062 
00063 template<uint8_t thread_id, uint32_t queue_size, uint32_t wait_ms>
00064 void receive_thread(Mail<mail_t, queue_size> *m)
00065 {
00066     int result_counter = 0;
00067     uint32_t data = thread_id * DATA_BASE;
00068 
00069     Thread::wait(wait_ms);
00070     for (uint32_t i = 0; i < queue_size; i++) {
00071         osEvent evt = m->get();
00072         if (evt.status == osEventMail) {
00073             mail_t *mail = (mail_t*)evt.value.p;
00074             const uint8_t id = mail->thread_id;
00075 
00076             // verify thread id
00077             TEST_ASSERT_TRUE(id == thread_id);
00078             // verify sent data
00079             TEST_ASSERT_TRUE(mail->data == data++);
00080 
00081             m->free(mail);
00082             result_counter++;
00083         }
00084     }
00085     TEST_ASSERT_EQUAL(queue_size, result_counter);
00086 }
00087 
00088 /** Test single thread Mail usage and order
00089 
00090     Given mailbox and one additional thread
00091     When messages are put in to the Mail box by this thread
00092     Then messages are received in main thread in the same order as was sent and the data sent is valid
00093  */
00094 void test_single_thread_order(void)
00095 {
00096     uint16_t data = DATA_BASE;
00097     int result_counter = 0;
00098     Mail<mail_t, QUEUE_SIZE> mail_box;
00099 
00100     // mail send thread creation
00101     Thread thread(osPriorityNormal, THREAD_STACK_SIZE);
00102     thread.start(callback(send_thread<THREAD_1_ID, QUEUE_PUT_DELAY_1, QUEUE_SIZE>, &mail_box));
00103 
00104     // wait for some mail to be collected
00105     Thread::wait(10);
00106 
00107     for (uint32_t i = 0; i < QUEUE_SIZE; i++) {
00108         // mail receive (main thread)
00109         osEvent evt = mail_box.get();
00110         if (evt.status == osEventMail) {
00111             mail_t *mail = (mail_t*)evt.value.p;
00112             const uint8_t id = mail->thread_id;
00113 
00114             // verify thread id
00115             TEST_ASSERT_TRUE(id == THREAD_1_ID);
00116             // verify sent data
00117             TEST_ASSERT_TRUE(mail->data == data++);
00118             mail_box.free(mail);
00119 
00120             result_counter++;
00121         }
00122     }
00123     TEST_ASSERT_EQUAL(QUEUE_SIZE, result_counter);
00124 }
00125 
00126 /** Test multi thread Mail usage and order
00127 
00128     Given mailbox and three additional threads
00129     When messages are put in to the Mail box by these threads
00130     Then messages are received in main thread in the same per thread order as was sent and the data sent is valid
00131  */
00132 void test_multi_thread_order(void)
00133 {
00134     uint16_t data[4] = { 0, DATA_BASE, DATA_BASE * 2, DATA_BASE * 3 };
00135     int result_counter = 0;
00136     Mail<mail_t, QUEUE_SIZE> mail_box;
00137 
00138     // mail send threads creation
00139     Thread thread1(osPriorityNormal, THREAD_STACK_SIZE);
00140     Thread thread2(osPriorityNormal, THREAD_STACK_SIZE);
00141     Thread thread3(osPriorityNormal, THREAD_STACK_SIZE);
00142     thread1.start(callback(send_thread<THREAD_1_ID, QUEUE_PUT_DELAY_1, 7>, &mail_box));
00143     thread2.start(callback(send_thread<THREAD_2_ID, QUEUE_PUT_DELAY_2, 5>, &mail_box));
00144     thread3.start(callback(send_thread<THREAD_3_ID, QUEUE_PUT_DELAY_3, 4>, &mail_box));
00145 
00146     // wait for some mail to be collected
00147     Thread::wait(10);
00148 
00149     for (uint32_t i = 0; i < QUEUE_SIZE; i++) {
00150         // mail receive (main thread)
00151         osEvent evt = mail_box.get();
00152         if (evt.status == osEventMail) {
00153             mail_t *mail = (mail_t*)evt.value.p;
00154             const uint8_t id = mail->thread_id;
00155 
00156             // verify thread id
00157             TEST_ASSERT_TRUE((id == THREAD_1_ID) || (id == THREAD_2_ID) || (id == THREAD_3_ID));
00158             // verify sent data
00159             TEST_ASSERT_TRUE(mail->data == data[id]++);
00160             mail_box.free(mail);
00161 
00162             result_counter++;
00163         }
00164     }
00165     TEST_ASSERT_EQUAL(QUEUE_SIZE, result_counter);
00166 }
00167 
00168 /** Test multi thread multi Mail usage and order
00169 
00170     Given 3 mailbox and three additional threads
00171     When messages are put in to the mail boxes by main thread
00172     Then messages are received by threads in the same per mail box order as was sent and the data sent is valid
00173  */
00174 void test_multi_thread_multi_mail_order(void)
00175 {
00176     Mail<mail_t, 4> mail_box[4]; /* mail_box[0] not used */
00177     uint16_t data[4] = { 0, DATA_BASE, DATA_BASE * 2, DATA_BASE * 3 };
00178     mail_t *mail;
00179     uint8_t id;
00180 
00181     // mail receive threads creation
00182     Thread thread1(osPriorityNormal, THREAD_STACK_SIZE);
00183     Thread thread2(osPriorityNormal, THREAD_STACK_SIZE);
00184     Thread thread3(osPriorityNormal, THREAD_STACK_SIZE);
00185     thread1.start(callback(receive_thread<THREAD_1_ID, 4, 0>, mail_box + 1));
00186     thread2.start(callback(receive_thread<THREAD_2_ID, 4, 10>, mail_box + 2));
00187     thread3.start(callback(receive_thread<THREAD_3_ID, 4, 100>, mail_box + 3));
00188 
00189     for (uint32_t i = 0; i < 4; i++) {
00190         id = THREAD_1_ID;
00191         mail = mail_box[id].alloc();
00192         mail->thread_id = id;
00193         mail->data = data[id]++;
00194         mail_box[id].put(mail);
00195 
00196         id = THREAD_2_ID;
00197         mail = mail_box[id].alloc();
00198         mail->thread_id = id;
00199         mail->data = data[id]++;
00200         mail_box[id].put(mail);
00201 
00202         id = THREAD_3_ID;
00203         mail = mail_box[id].alloc();
00204         mail->thread_id = id;
00205         mail->data = data[id]++;
00206         mail_box[id].put(mail);
00207 
00208         Thread::wait(i * 10);
00209     }
00210 
00211     thread1.join();
00212     thread2.join();
00213     thread3.join();
00214 }
00215 
00216 /** Test message memory deallocation with block out of the scope
00217 
00218     Given an empty mailbox
00219     When try to free out of the scope memory block
00220     Then it return appropriate error code
00221  */
00222 void test_free_wrong()
00223 {
00224     osStatus status;
00225     Mail<uint32_t, 4> mail_box;
00226     uint32_t *mail, data;
00227 
00228     mail = &data;
00229     status = mail_box.free(mail);
00230     TEST_ASSERT_EQUAL(osErrorParameter, status);
00231 
00232     mail = mail_box.alloc();
00233     TEST_ASSERT_NOT_EQUAL(NULL, mail);
00234 
00235     mail = &data;
00236     status = mail_box.free(mail);
00237     TEST_ASSERT_EQUAL(osErrorParameter, status);
00238 }
00239 
00240 /** Test message memory deallocation with null block
00241 
00242     Given an empty mailbox
00243     When try to free null ptr
00244     Then it return appropriate error code
00245  */
00246 void test_free_null()
00247 {
00248     osStatus status;
00249     Mail<uint32_t, 4> mail_box;
00250     uint32_t *mail;
00251 
00252     mail = NULL;
00253     status = mail_box.free(mail);
00254     TEST_ASSERT_EQUAL(osErrorParameter, status);
00255 
00256     mail = mail_box.alloc();
00257     TEST_ASSERT_NOT_EQUAL(NULL, mail);
00258 
00259     mail = NULL;
00260     status = mail_box.free(mail);
00261     TEST_ASSERT_EQUAL(osErrorParameter, status);
00262 }
00263 
00264 /** Test same message memory deallocation twice
00265 
00266     Given an empty mailbox
00267     Then allocate message memory
00268     When try to free it second time
00269     Then it return appropriate error code
00270  */
00271 void test_free_twice()
00272 {
00273     osStatus status;
00274     Mail<uint32_t, 4> mail_box;
00275 
00276     uint32_t *mail = mail_box.alloc();
00277     TEST_ASSERT_NOT_EQUAL(NULL, mail);
00278 
00279     status = mail_box.free(mail);
00280     TEST_ASSERT_EQUAL(osOK, status);
00281 
00282     status = mail_box.free(mail);
00283     TEST_ASSERT_EQUAL(osErrorResource, status);
00284 }
00285 
00286 /** Test get from empty mailbox with timeout set
00287 
00288     Given an empty mailbox
00289     When @a get is called on the mailbox with timeout of 50
00290     Then mailbox returns status of osOK, but no data after specified amount of time
00291  */
00292 void test_get_empty_timeout()
00293 {
00294     Mail<uint32_t, 4> mail_box;
00295     Timer timer;
00296 
00297     timer.start();
00298     osEvent evt = mail_box.get(50);
00299     TEST_ASSERT_UINT32_WITHIN(5000, 50000, timer.read_us());
00300     TEST_ASSERT_EQUAL(osEventTimeout, evt.status);
00301 }
00302 
00303 /** Test get from empty mailbox with 0 timeout
00304 
00305     Given an empty mailbox
00306     When @a get is called on the mailbox with timeout of 0
00307     Then mailbox returns status of osOK, but no data
00308  */
00309 void test_get_empty_no_timeout()
00310 {
00311     Mail<uint32_t, 4> mail_box;
00312 
00313     osEvent evt = mail_box.get(0);
00314     TEST_ASSERT_EQUAL(osOK, evt.status);
00315 }
00316 
00317 /** Test mail order
00318 
00319     Given an mailbox for uint32_t values
00320     Then allocate two mails and put them in to mailbox
00321     When call @a get it returns previously put mails
00322     Then mails should be in the same order as put
00323  */
00324 void test_order(void)
00325 {
00326     osStatus status;
00327     osEvent evt;
00328     Mail<int32_t, 4> mail_box;
00329     const int32_t TEST_VAL1 = 123;
00330     const int32_t TEST_VAL2 = 456;
00331 
00332     int32_t *mail1 = mail_box.alloc();
00333     TEST_ASSERT_NOT_EQUAL(NULL, mail1);
00334 
00335     *mail1 = TEST_VAL1;
00336     status = mail_box.put(mail1);
00337     TEST_ASSERT_EQUAL(osOK, status);
00338 
00339     int32_t *mail2 = mail_box.alloc();
00340     TEST_ASSERT_NOT_EQUAL(NULL, mail2);
00341 
00342     *mail2 = TEST_VAL2;
00343     status = mail_box.put(mail2);
00344     TEST_ASSERT_EQUAL(osOK, status);
00345 
00346 
00347     evt = mail_box.get();
00348     TEST_ASSERT_EQUAL(evt.status, osEventMail);
00349 
00350     mail1 = (int32_t*)evt.value.p;
00351     TEST_ASSERT_EQUAL(TEST_VAL1, *mail1);
00352 
00353     evt = mail_box.get();
00354     TEST_ASSERT_EQUAL(evt.status, osEventMail);
00355 
00356     mail2 = (int32_t*)evt.value.p;
00357     TEST_ASSERT_EQUAL(TEST_VAL2, *mail2);
00358 
00359 
00360     status = mail_box.free(mail1);
00361     TEST_ASSERT_EQUAL(osOK, status);
00362 
00363     status = mail_box.free(mail2);
00364     TEST_ASSERT_EQUAL(osOK, status);
00365 }
00366 
00367 /** Test Mail box max size limit
00368 
00369     Given an Mail box with max size of 4 elements
00370     When call @a alloc four times it returns memory blocks
00371     Then the memory blocks should be valid
00372     When call @a alloc one more time it returns memory blocks
00373     Then the memory blocks should be not valid (NULL - no memory available)
00374  */
00375 void test_max_size()
00376 {
00377     osStatus status;
00378     Mail<uint32_t, 4> mail_box;
00379     const uint32_t TEST_VAL = 123;
00380 
00381     // 1 OK
00382     uint32_t *mail1 = mail_box.alloc();
00383     TEST_ASSERT_NOT_EQUAL(NULL, mail1);
00384 
00385     // 2 OK
00386     uint32_t *mail2 = mail_box.alloc();
00387     TEST_ASSERT_NOT_EQUAL(NULL, mail2);
00388 
00389     // 3 OK
00390     uint32_t *mail3 = mail_box.alloc();
00391     TEST_ASSERT_NOT_EQUAL(NULL, mail3);
00392 
00393     // 4 OK
00394     uint32_t *mail4 = mail_box.alloc();
00395     TEST_ASSERT_NOT_EQUAL(NULL, mail4);
00396 
00397     // 5 KO
00398     uint32_t *mail5 = mail_box.alloc();
00399     TEST_ASSERT_EQUAL(NULL, mail5);
00400 
00401 
00402     status = mail_box.free(mail1);
00403     TEST_ASSERT_EQUAL(osOK, status);
00404 
00405     status = mail_box.free(mail2);
00406     TEST_ASSERT_EQUAL(osOK, status);
00407 
00408     status = mail_box.free(mail3);
00409     TEST_ASSERT_EQUAL(osOK, status);
00410 
00411     status = mail_box.free(mail4);
00412     TEST_ASSERT_EQUAL(osOK, status);
00413 }
00414 
00415 /** Test mailbox of T type data
00416 
00417     Given an mailbox with T memory block type
00418     When allocate/put/get/free memory block
00419     Then all operations should succeed
00420  */
00421 template<typename T>
00422 void test_data_type(void)
00423 {
00424     osStatus status;
00425     Mail<T, 4> mail_box;
00426     const T TEST_VAL = 123;
00427 
00428     T *mail = mail_box.alloc();
00429     TEST_ASSERT_NOT_EQUAL(NULL, mail);
00430 
00431     *mail = TEST_VAL;
00432     status = mail_box.put(mail);
00433     TEST_ASSERT_EQUAL(osOK, status);
00434 
00435     osEvent evt = mail_box.get();
00436     TEST_ASSERT_EQUAL(evt.status, osEventMail);
00437 
00438     mail = (T*)evt.value.p;
00439     TEST_ASSERT_EQUAL(TEST_VAL, *mail);
00440 
00441 
00442     status = mail_box.free(mail);
00443     TEST_ASSERT_EQUAL(osOK, status);
00444 }
00445 
00446 /** Test calloc - memory block allocation with resetting
00447 
00448     Given an empty Mail box
00449     When call @a calloc it returns allocated memory block
00450     Then the memory block should be valid and filled with zeros
00451  */
00452 void test_calloc()
00453 {
00454     Mail<uint32_t, 1> mail_box;
00455 
00456     uint32_t *mail = mail_box.calloc();
00457     TEST_ASSERT_NOT_EQUAL(NULL, mail);
00458     TEST_ASSERT_EQUAL(0, *mail);
00459 }
00460 
00461 /** Test mail empty
00462 
00463     Given a mail of uint32_t data
00464     before data is inserted the mail should be empty
00465     after data is inserted the mail shouldn't be empty
00466  */
00467 void test_mail_empty()
00468 {
00469     Mail<mail_t, 1> m;
00470 
00471     mail_t *mail = m.alloc();
00472 
00473     TEST_ASSERT_EQUAL(true,  m.empty());
00474 
00475     m.put(mail);
00476 
00477     TEST_ASSERT_EQUAL(false, m.empty());
00478 }
00479 
00480 /** Test mail empty
00481 
00482     Given a mail of uint32_t data with size of 1
00483     before data is inserted the mail shouldn't be full
00484     after data is inserted the mail should be full
00485  */
00486 void test_mail_full()
00487 {
00488     Mail<mail_t, 1> m;
00489 
00490     mail_t *mail = m.alloc();
00491 
00492     TEST_ASSERT_EQUAL(false,  m.full());
00493 
00494     m.put(mail);
00495 
00496     TEST_ASSERT_EQUAL(true, m.full());
00497 }
00498 
00499 utest::v1::status_t test_setup(const size_t number_of_cases)
00500 {
00501     GREENTEA_SETUP(10, "default_auto");
00502     return verbose_test_setup_handler(number_of_cases);
00503 }
00504 
00505 Case cases[] = {
00506     Case("Test calloc", test_calloc),
00507     Case("Test message type uint8", test_data_type<uint8_t>),
00508     Case("Test message type uint16", test_data_type<uint16_t>),
00509     Case("Test message type uint32", test_data_type<uint32_t>),
00510     Case("Test mailbox max size", test_max_size),
00511     Case("Test message send order", test_order),
00512     Case("Test get with timeout on empty mailbox", test_get_empty_timeout),
00513     Case("Test get without timeout on empty mailbox", test_get_empty_no_timeout),
00514     Case("Test message free twice", test_free_twice),
00515     Case("Test null message free", test_free_null),
00516     Case("Test invalid message free", test_free_wrong),
00517     Case("Test message send/receive single thread and order", test_single_thread_order),
00518     Case("Test message send/receive multi-thread and per thread order", test_multi_thread_order),
00519     Case("Test message send/receive multi-thread, multi-Mail and per thread order", test_multi_thread_multi_mail_order),
00520     Case("Test mail empty", test_mail_empty),
00521     Case("Test mail full", test_mail_full)
00522 };
00523 
00524 Specification specification(test_setup, cases);
00525 
00526 int main()
00527 {
00528     return !Harness::run(specification);
00529 }