Rtos API example

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