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) 2013-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 "utest/utest.h"
00019 #include "unity/unity.h"
00020 
00021 
00022 using utest::v1::Case;
00023 
00024 #define ONE_MILLI_SEC 1000
00025 #define TICKER_COUNT 16
00026 #define MULTI_TICKER_TIME_MS 100
00027 volatile uint32_t callback_trigger_count = 0;
00028 static const int test_timeout = 240;
00029 static const int total_ticks = 10;
00030 
00031 
00032 /* Tolerance is quite arbitrary due to large number of boards with varying level of accuracy */
00033 #define TOLERANCE_US 1000
00034 
00035 volatile uint32_t ticker_callback_flag;
00036 volatile uint32_t multi_counter;
00037 
00038 DigitalOut led1(LED1);
00039 DigitalOut led2(LED2);
00040 
00041 Ticker *volatile ticker1;
00042 Ticker *volatile ticker2;
00043 Timer gtimer;
00044 
00045 volatile int ticker_count = 0;
00046 volatile bool print_tick = false;
00047 
00048 void ticker_callback_1_switch_to_2(void);
00049 void ticker_callback_2_switch_to_1(void);
00050 
00051 void increment_ticker_counter(void)
00052 {
00053     ++callback_trigger_count;
00054 }
00055 
00056 void switch_led1_state(void)
00057 {
00058     led1 = !led1;
00059 }
00060 
00061 void switch_led2_state(void)
00062 {
00063     led2 = !led2;
00064 }
00065 
00066 void ticker_callback_1_switch_to_2(void)
00067 {
00068     ++callback_trigger_count;
00069     // If ticker is NULL then it is being or has been deleted
00070     if (ticker1) {
00071         ticker1->detach();
00072         ticker1->attach_us(ticker_callback_2_switch_to_1, ONE_MILLI_SEC);
00073     }
00074     switch_led1_state();
00075 }
00076 
00077 void ticker_callback_2_switch_to_1(void)
00078 {
00079     ++callback_trigger_count;
00080     // If ticker is NULL then it is being or has been deleted
00081     if (ticker2) {
00082         ticker2->detach();
00083         ticker2->attach_us(ticker_callback_1_switch_to_2, ONE_MILLI_SEC);
00084     }
00085     switch_led2_state();
00086 }
00087 
00088 
00089 void sem_release(Semaphore *sem)
00090 {
00091     sem->release();
00092 }
00093 
00094 
00095 void stop_gtimer_set_flag(void)
00096 {
00097     gtimer.stop();
00098     core_util_atomic_incr_u32((uint32_t*)&ticker_callback_flag, 1);
00099 }
00100 
00101 void increment_multi_counter(void)
00102 {
00103     core_util_atomic_incr_u32((uint32_t*)&multi_counter, 1);
00104 }
00105 
00106 
00107 /* Tests is to measure the accuracy of Ticker over a period of time
00108  *
00109  * 1) DUT would start to update callback_trigger_count every milli sec, in 2x callback we use 2 tickers
00110  *    to update the count alternatively.
00111  * 2) Host would query what is current count base_time, Device responds by the callback_trigger_count
00112  * 3) Host after waiting for measurement stretch. It will query for device time again final_time.
00113  * 4) Host computes the drift considering base_time, final_time, transport delay and measurement stretch
00114  * 5) Finally host send the results back to device pass/fail based on tolerance.
00115  * 6) More details on tests can be found in timing_drift_auto.py
00116  */
00117 void test_case_1x_ticker()
00118 {
00119     char _key[11] = { };
00120     char _value[128] = { };
00121     int expected_key = 1;
00122 
00123     greentea_send_kv("timing_drift_check_start", 0);
00124     ticker1->attach_us(&increment_ticker_counter, ONE_MILLI_SEC);
00125 
00126     // wait for 1st signal from host
00127     do {
00128         greentea_parse_kv(_key, _value, sizeof(_key), sizeof(_value));
00129         expected_key = strcmp(_key, "base_time");
00130     } while (expected_key);
00131     greentea_send_kv(_key, callback_trigger_count * ONE_MILLI_SEC);
00132 
00133     // wait for 2nd signal from host
00134     greentea_parse_kv(_key, _value, sizeof(_key), sizeof(_value));
00135     greentea_send_kv(_key, callback_trigger_count * ONE_MILLI_SEC);
00136 
00137     //get the results from host
00138     greentea_parse_kv(_key, _value, sizeof(_key), sizeof(_value));
00139 
00140     TEST_ASSERT_EQUAL_STRING_MESSAGE("pass", _key,"Host side script reported a fail...");
00141 }
00142 
00143 void test_case_2x_callbacks()
00144 {
00145     char _key[11] = { };
00146     char _value[128] = { };
00147     int expected_key =  1;
00148 
00149     led1 = 0;
00150     led2 = 0;
00151     callback_trigger_count = 0;
00152 
00153     greentea_send_kv("timing_drift_check_start", 0);
00154     ticker1->attach_us(ticker_callback_1_switch_to_2, ONE_MILLI_SEC);
00155 
00156     // wait for 1st signal from host
00157     do {
00158         greentea_parse_kv(_key, _value, sizeof(_key), sizeof(_value));
00159         expected_key = strcmp(_key, "base_time");
00160     } while (expected_key);
00161     greentea_send_kv(_key, callback_trigger_count * ONE_MILLI_SEC);
00162 
00163     // wait for 2nd signal from host
00164     greentea_parse_kv(_key, _value, sizeof(_key), sizeof(_value));
00165     greentea_send_kv(_key, callback_trigger_count * ONE_MILLI_SEC);
00166 
00167     //get the results from host
00168     greentea_parse_kv(_key, _value, sizeof(_key), sizeof(_value));
00169 
00170     TEST_ASSERT_EQUAL_STRING_MESSAGE("pass", _key,"Host side script reported a fail...");
00171 }
00172 
00173 /** Test many tickers run one after the other
00174 
00175     Given many Tickers
00176     When schedule them one after the other with the same time intervals
00177     Then tickers properly execute callbacks
00178     When schedule them one after the other with the different time intervals
00179     Then tickers properly execute callbacks
00180  */
00181 void test_multi_ticker(void)
00182 {
00183     Ticker ticker[TICKER_COUNT];
00184     const uint32_t extra_wait = 5; // extra 5ms wait time
00185 
00186     multi_counter = 0;
00187     for (int i = 0; i < TICKER_COUNT; i++) {
00188         ticker[i].attach_us(callback(increment_multi_counter), MULTI_TICKER_TIME_MS * 1000);
00189     }
00190 
00191     Thread::wait(MULTI_TICKER_TIME_MS + extra_wait);
00192     for (int i = 0; i < TICKER_COUNT; i++) {
00193             ticker[i].detach();
00194     }
00195     TEST_ASSERT_EQUAL(TICKER_COUNT, multi_counter);
00196 
00197     multi_counter = 0;
00198     for (int i = 0; i < TICKER_COUNT; i++) {
00199         ticker[i].attach_us(callback(increment_multi_counter), (MULTI_TICKER_TIME_MS + i) * 1000);
00200     }
00201 
00202     Thread::wait(MULTI_TICKER_TIME_MS + TICKER_COUNT + extra_wait);
00203     for (int i = 0; i < TICKER_COUNT; i++) {
00204         ticker[i].detach();
00205     }
00206     TEST_ASSERT_EQUAL(TICKER_COUNT, multi_counter);
00207 }
00208 
00209 /** Test multi callback time
00210 
00211     Given a Ticker
00212     When the callback is attached multiple times
00213     Then ticker properly execute callback multiple times
00214  */
00215 void test_multi_call_time(void)
00216 {
00217     Ticker ticker;
00218     int time_diff;
00219     const int attach_count = 10;
00220 
00221     for (int i = 0; i < attach_count; i++) {
00222         ticker_callback_flag = 0;
00223         gtimer.reset();
00224 
00225         gtimer.start();
00226         ticker.attach_us(callback(stop_gtimer_set_flag), MULTI_TICKER_TIME_MS * 1000);
00227         while(!ticker_callback_flag);
00228         time_diff = gtimer.read_us();
00229 
00230         TEST_ASSERT_UINT32_WITHIN(TOLERANCE_US, MULTI_TICKER_TIME_MS * 1000, time_diff);
00231     }
00232 }
00233 
00234 /** Test if detach cancel scheduled callback event
00235 
00236     Given a Ticker with callback attached
00237     When the callback is detached
00238     Then the callback is not being called
00239  */
00240 void test_detach(void)
00241 {
00242     Ticker ticker;
00243     int32_t ret;
00244     const float ticker_time_s = 0.1f;
00245     const uint32_t wait_time_ms = 500;
00246     Semaphore sem(0, 1);
00247 
00248     ticker.attach(callback(sem_release, &sem), ticker_time_s);
00249 
00250     ret = sem.wait();
00251     TEST_ASSERT_TRUE(ret > 0);
00252 
00253     ret = sem.wait();
00254     ticker.detach(); /* cancel */
00255     TEST_ASSERT_TRUE(ret > 0);
00256 
00257     ret = sem.wait(wait_time_ms);
00258     TEST_ASSERT_EQUAL(0, ret);
00259 }
00260 
00261 /** Test single callback time via attach
00262 
00263     Given a Ticker
00264     When callback attached with time interval specified
00265     Then ticker properly executes callback within a specified time interval
00266  */
00267 template<us_timestamp_t DELAY_US>
00268 void test_attach_time(void)
00269 {
00270     Ticker ticker;
00271     ticker_callback_flag = 0;
00272 
00273     gtimer.reset();
00274     gtimer.start();
00275     ticker.attach(callback(stop_gtimer_set_flag), ((float)DELAY_US) / 1000000.0f);
00276     while(!ticker_callback_flag);
00277     ticker.detach();
00278     const int time_diff = gtimer.read_us();
00279 
00280     TEST_ASSERT_UINT64_WITHIN(TOLERANCE_US, DELAY_US, time_diff);
00281 }
00282 
00283 /** Test single callback time via attach_us
00284 
00285     Given a Ticker
00286     When callback attached with time interval specified
00287     Then ticker properly executes callback within a specified time interval
00288  */
00289 template<us_timestamp_t DELAY_US>
00290 void test_attach_us_time(void)
00291 {
00292     Ticker ticker;
00293     ticker_callback_flag = 0;
00294 
00295     gtimer.reset();
00296     gtimer.start();
00297     ticker.attach_us(callback(stop_gtimer_set_flag), DELAY_US);
00298     while(!ticker_callback_flag);
00299     ticker.detach();
00300     const int time_diff = gtimer.read_us();
00301 
00302     TEST_ASSERT_UINT64_WITHIN(TOLERANCE_US, DELAY_US, time_diff);
00303 }
00304 
00305 
00306 utest::v1::status_t one_ticker_case_setup_handler_t(const Case *const source, const size_t index_of_case)
00307 {
00308     ticker1 = new Ticker();
00309     return greentea_case_setup_handler(source, index_of_case);
00310 }
00311 
00312 utest::v1::status_t two_ticker_case_setup_handler_t(const Case *const source, const size_t index_of_case)
00313 {
00314     ticker1 = new Ticker();
00315     ticker2 = new Ticker();
00316     return utest::v1::greentea_case_setup_handler(source, index_of_case);
00317 }
00318 
00319 utest::v1::status_t one_ticker_case_teardown_handler_t(const Case *const source, const size_t passed, const size_t failed, const utest::v1::failure_t reason)
00320 {
00321     Ticker *temp1 = ticker1;
00322     ticker1 = NULL;
00323     delete temp1;
00324     return utest::v1::greentea_case_teardown_handler(source, passed, failed, reason);
00325 }
00326 
00327 utest::v1::status_t two_ticker_case_teardown_handler_t(const Case *const source, const size_t passed, const size_t failed, const utest::v1::failure_t reason)
00328 {
00329     Ticker *temp1 = ticker1;
00330     Ticker *temp2 = ticker2;
00331     ticker1 = NULL;
00332     ticker2 = NULL;
00333     delete temp1;
00334     delete temp2;
00335     return utest::v1::greentea_case_teardown_handler(source, passed, failed, reason);
00336 }
00337 
00338 
00339 // Test cases
00340 Case cases[] = {
00341     Case("Test attach for 0.01s and time measure", test_attach_time<10000>),
00342     Case("Test attach_us for 10ms and time measure", test_attach_us_time<10000>),
00343     Case("Test attach for 0.1s and time measure", test_attach_time<100000>),
00344     Case("Test attach_us for 100ms and time measure", test_attach_us_time<100000>),
00345     Case("Test attach for 0.5s and time measure", test_attach_time<500000>),
00346     Case("Test attach_us for 500ms and time measure", test_attach_us_time<500000>),
00347     Case("Test detach", test_detach),
00348     Case("Test multi call and time measure", test_multi_call_time),
00349     Case("Test multi ticker", test_multi_ticker),
00350     Case("Test timers: 1x ticker", one_ticker_case_setup_handler_t,test_case_1x_ticker, one_ticker_case_teardown_handler_t),
00351     Case("Test timers: 2x callbacks", two_ticker_case_setup_handler_t,test_case_2x_callbacks, two_ticker_case_teardown_handler_t)
00352 };
00353 
00354 utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
00355 {
00356     GREENTEA_SETUP(test_timeout, "timing_drift_auto");
00357     return utest::v1::greentea_test_setup_handler(number_of_cases);
00358 }
00359 
00360 utest::v1::Specification specification(greentea_test_setup, cases, utest::v1::greentea_test_teardown_handler);
00361 
00362 int main()
00363 {
00364     utest::v1::Harness::run(specification);
00365 }