Gleb Klochkov / Mbed OS Climatcontroll_Main

Dependencies:   esp8266-driver

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers timeout_tests.h Source File

timeout_tests.h

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 #ifndef MBED_TIMEOUT_TESTS_H
00017 #define MBED_TIMEOUT_TESTS_H
00018 
00019 #include "mbed.h"
00020 #include "unity/unity.h"
00021 
00022 #define NUM_TIMEOUTS 16
00023 #define DRIFT_TEST_PERIOD_US 10000
00024 
00025 const float TEST_DELAY_S = 0.01;
00026 const uint32_t TEST_DELAY_MS = 1000.0F * TEST_DELAY_S;
00027 const us_timestamp_t TEST_DELAY_US = 1000000.0F * TEST_DELAY_S;
00028 
00029 /* Timeouts are quite arbitrary due to large number of boards with varying level of accuracy */
00030 #define LONG_DELTA_US (100000)
00031 #define SHORT_DELTA_US (2000)
00032 
00033 void sem_callback(Semaphore *sem)
00034 {
00035     sem->release();
00036 }
00037 
00038 void cnt_callback(volatile uint32_t *cnt)
00039 {
00040     (*cnt)++;
00041 }
00042 
00043 template<typename TimeoutType>
00044 class AttachTester: public TimeoutType {
00045 public:
00046     void attach_callback(Callback<void()> func, us_timestamp_t delay_us)
00047     {
00048         TimeoutType::attach(func, (float) delay_us / 1000000.0f);
00049     }
00050 };
00051 
00052 template<typename TimeoutType>
00053 class AttachUSTester: public TimeoutType {
00054 public:
00055     void attach_callback(Callback<void()> func, us_timestamp_t delay_us)
00056     {
00057         TimeoutType::attach_us(func, delay_us);
00058     }
00059 };
00060 
00061 /** Template for tests: callback called once
00062  *
00063  * Test callback called once
00064  * Given a Timeout object with a callback attached with @a attach()
00065  * When given time elapses
00066  * Then the callback is called exactly one time
00067  *
00068  * Test callback called once
00069  * Given a Timeout object with a callback attached with @a attach_us()
00070  * When given time elapses
00071  * Then the callback is called exactly one time
00072  */
00073 template<typename T>
00074 void test_single_call(void)
00075 {
00076     Semaphore sem(0, 1);
00077     T timeout;
00078 
00079     timeout.attach_callback(mbed::callback(sem_callback, &sem), TEST_DELAY_US);
00080 
00081     int32_t sem_slots = sem.wait(0);
00082     TEST_ASSERT_EQUAL(0, sem_slots);
00083 
00084     sem_slots = sem.wait(TEST_DELAY_MS + 1);
00085     TEST_ASSERT_EQUAL(1, sem_slots);
00086 
00087     sem_slots = sem.wait(TEST_DELAY_MS + 1);
00088     TEST_ASSERT_EQUAL(0, sem_slots);
00089 
00090     timeout.detach();
00091 }
00092 
00093 /** Template for tests: callback not called when cancelled
00094  *
00095  * Test callback not called when cancelled
00096  * Given a Timeout object with a callback attached with @a attach()
00097  * When the callback is detached before being called
00098  * Then the callback is never called
00099  *
00100  * Test callback not called when cancelled
00101  * Given a Timeout object with a callback attached with @a attach_us()
00102  * When the callback is detached before being called
00103  * Then the callback is never called
00104  */
00105 template<typename T>
00106 void test_cancel(void)
00107 {
00108     Semaphore sem(0, 1);
00109     T timeout;
00110 
00111     timeout.attach_callback(mbed::callback(sem_callback, &sem), 2.0f * TEST_DELAY_US);
00112 
00113     int32_t sem_slots = sem.wait(TEST_DELAY_MS);
00114     TEST_ASSERT_EQUAL(0, sem_slots);
00115     timeout.detach();
00116 
00117     sem_slots = sem.wait(TEST_DELAY_MS + 1);
00118     TEST_ASSERT_EQUAL(0, sem_slots);
00119 }
00120 
00121 /** Template for tests: callback override
00122  *
00123  * Test callback override
00124  * Given a Timeout object with a callback attached with @a attach()
00125  * When another callback is attached before first one is called
00126  *     and second callback's delay elapses
00127  * Then the second callback is called
00128  *     and the first callback is never called
00129  *
00130  * Test callback override
00131  * Given a Timeout object with a callback attached with @a attach_us()
00132  * When another callback is attached before first one is called
00133  *     and second callback's delay elapses
00134  * Then the second callback is called
00135  *     and the first callback is never called
00136  */
00137 template<typename T>
00138 void test_override(void)
00139 {
00140     Semaphore sem1(0, 1);
00141     Semaphore sem2(0, 1);
00142     T timeout;
00143 
00144     timeout.attach_callback(mbed::callback(sem_callback, &sem1), 2.0f * TEST_DELAY_US);
00145 
00146     int32_t sem_slots = sem1.wait(TEST_DELAY_MS);
00147     TEST_ASSERT_EQUAL(0, sem_slots);
00148     timeout.attach_callback(mbed::callback(sem_callback, &sem2), 2.0f * TEST_DELAY_US);
00149 
00150     sem_slots = sem2.wait(2 * TEST_DELAY_MS + 1);
00151     TEST_ASSERT_EQUAL(1, sem_slots);
00152     sem_slots = sem1.wait(0);
00153     TEST_ASSERT_EQUAL(0, sem_slots);
00154 
00155     timeout.detach();
00156 }
00157 
00158 /** Template for tests: multiple Timeouts
00159  *
00160  * Test multiple Timeouts
00161  * Given multiple separate Timeout objects
00162  * When a callback is attached to all of these Timeout objects with @a attach()
00163  *     and delay for every Timeout elapses
00164  * Then all callbacks are called
00165  *
00166  * Test multiple Timeouts
00167  * Given multiple separate Timeout objects
00168  * When a callback is attached to all of these Timeout objects with @a attach_us()
00169  *     and delay for every Timeout elapses
00170  * Then all callbacks are called
00171  */
00172 template<typename T>
00173 void test_multiple(void)
00174 {
00175     volatile uint32_t callback_count = 0;
00176     T timeouts[NUM_TIMEOUTS];
00177     for (size_t i = 0; i < NUM_TIMEOUTS; i++) {
00178         timeouts[i].attach_callback(mbed::callback(cnt_callback, &callback_count), TEST_DELAY_US);
00179     }
00180     Thread::wait(TEST_DELAY_MS + 1);
00181     TEST_ASSERT_EQUAL(NUM_TIMEOUTS, callback_count);
00182 }
00183 
00184 /** Template for tests: zero delay
00185  *
00186  * Test zero delay
00187  * Given a Timeout object
00188  * When a callback is attached with 0.0 s delay, with @a attach()
00189  * Then the callback is called instantly
00190  *
00191  * Test zero delay
00192  * Given a Timeout object
00193  * When a callback is attached with 0.0 s delay, with @a attach_us()
00194  * Then the callback is called instantly
00195  */
00196 template<typename T>
00197 void test_no_wait(void)
00198 {
00199     Semaphore sem(0, 1);
00200     T timeout;
00201     timeout.attach_callback(mbed::callback(sem_callback, &sem), 0ULL);
00202 
00203     int32_t sem_slots = sem.wait(0);
00204     TEST_ASSERT_EQUAL(1, sem_slots);
00205     timeout.detach();
00206 }
00207 
00208 /** Template for tests: accuracy of timeout delay
00209  *
00210  * Test delay accuracy
00211  * Given a Timeout object with a callback attached with @a attach()
00212  * When the callback is called
00213  * Then elapsed time matches given delay
00214  *
00215  * Test delay accuracy
00216  * Given a Timeout object with a callback attached with @a attach_us()
00217  * When the callback is called
00218  * Then elapsed time matches given delay
00219  */
00220 template<typename T, us_timestamp_t delay_us, us_timestamp_t delta_us>
00221 void test_delay_accuracy(void)
00222 {
00223     Semaphore sem(0, 1);
00224     T timeout;
00225     Timer timer;
00226 
00227     timer.start();
00228     timeout.attach_callback(mbed::callback(sem_callback, &sem), delay_us);
00229 
00230     int32_t sem_slots = sem.wait(osWaitForever);
00231     timer.stop();
00232     TEST_ASSERT_EQUAL(1, sem_slots);
00233     TEST_ASSERT_UINT64_WITHIN(delta_us, delay_us, timer.read_high_resolution_us());
00234 
00235     timeout.detach();
00236 }
00237 
00238 #if DEVICE_SLEEP
00239 /** Template for tests: timeout during sleep
00240  *
00241  * Test timeout during sleep
00242  * Given a Timeout object with a callback attached with @a attach()
00243  *     and the uC in a sleep mode
00244  * When given delay elapses
00245  * Then the callback is called
00246  *     and elapsed time matches given delay
00247  *
00248  * Test timeout during sleep
00249  * Given a Timeout object with a callback attached with @a attach_us()
00250  *     and the uC in a sleep mode
00251  * When given delay elapses
00252  * Then the callback is called
00253  *     and elapsed time matches given delay
00254  */
00255 template<typename T, us_timestamp_t delay_us, us_timestamp_t delta_us>
00256 void test_sleep(void)
00257 {
00258     Semaphore sem(0, 1);
00259     T timeout;
00260     Timer timer;
00261 
00262     sleep_manager_lock_deep_sleep();
00263     timer.start();
00264     timeout.attach_callback(mbed::callback(sem_callback, &sem), delay_us);
00265 
00266     bool deep_sleep_allowed = sleep_manager_can_deep_sleep();
00267     TEST_ASSERT_FALSE_MESSAGE(deep_sleep_allowed, "Deep sleep should be disallowed");
00268     while (sem.wait(0) != 1) {
00269         sleep();
00270     }
00271     timer.stop();
00272 
00273     sleep_manager_unlock_deep_sleep();
00274     TEST_ASSERT_UINT64_WITHIN(delta_us, delay_us, timer.read_high_resolution_us());
00275 
00276     timeout.detach();
00277 }
00278 
00279 #if DEVICE_LOWPOWERTIMER
00280 /** Template for tests: timeout during deepsleep
00281  *
00282  * Test timeout during deepsleep
00283  * Given a LowPowerTimeout object with a callback attached with @a attach()
00284  *     and the uC in a deepsleep mode
00285  * When given delay elapses
00286  * Then the callback is called
00287  *     and elapsed time matches given delay
00288  *
00289  * Test timeout during deepsleep
00290  * Given a LowPowerTimeout object with a callback attached with @a attach_us()
00291  *     and the uC in a deepsleep mode
00292  * When given delay elapses
00293  * Then the callback is called
00294  *     and elapsed time matches given delay
00295  */
00296 template<typename T, us_timestamp_t delay_us, us_timestamp_t delta_us>
00297 void test_deepsleep(void)
00298 {
00299     Semaphore sem(0, 1);
00300     T timeout;
00301     /*
00302      * We use here the low power timer instead of microsecond timer for start and
00303      * end because the microseconds timer might be disabled during deepsleep.
00304      */
00305     LowPowerTimer timer;
00306 
00307     /*
00308      * Since deepsleep() may shut down the UART peripheral, we wait for 10ms
00309      * to allow for hardware serial buffers to completely flush.
00310 
00311      * This should be replaced with a better function that checks if the
00312      * hardware buffers are empty. However, such an API does not exist now,
00313      * so we'll use the wait_ms() function for now.
00314      */
00315     wait_ms(10);
00316 
00317     timer.start();
00318     timeout.attach_callback(mbed::callback(sem_callback, &sem), delay_us);
00319 
00320     bool deep_sleep_allowed = sleep_manager_can_deep_sleep();
00321     TEST_ASSERT_TRUE_MESSAGE(deep_sleep_allowed, "Deep sleep should be allowed");
00322     while (sem.wait(0) != 1) {
00323         sleep();
00324     }
00325     timer.stop();
00326 
00327     TEST_ASSERT_UINT64_WITHIN(delta_us, delay_us, timer.read_high_resolution_us());
00328 
00329     timeout.detach();
00330 }
00331 #endif
00332 #endif
00333 
00334 template<typename TimeoutTesterType>
00335 class TimeoutDriftTester {
00336 public:
00337     TimeoutDriftTester(us_timestamp_t period = 1000) :
00338             _callback_count(0), _period(period), _timeout()
00339     {
00340     }
00341 
00342     void reschedule_callback(void)
00343     {
00344         _timeout.attach_callback(mbed::callback(this, &TimeoutDriftTester::reschedule_callback), _period);
00345         _callback_count++;
00346     }
00347 
00348     void detach_callback(void)
00349     {
00350         _timeout.detach();
00351     }
00352 
00353     uint32_t get_callback_count(void)
00354     {
00355         return _callback_count;
00356     }
00357 
00358 private:
00359     volatile uint32_t _callback_count;
00360     us_timestamp_t _period;
00361     TimeoutTesterType _timeout;
00362 };
00363 
00364 /** Template for tests: accuracy of timeout delay scheduled repeatedly
00365  *
00366  * Test time drift -- device part
00367  * Given a Timeout object with a callback repeatedly attached with @a attach()
00368  * When the testing host computes test duration based on values received from uC
00369  * Then computed time and actual time measured by host are equal within given tolerance
00370  *
00371  * Test time drift -- device part
00372  * Given a Timeout object with a callback repeatedly attached with @a attach_us()
00373  * When the testing host computes test duration based on values received from uC
00374  * Then computed time and actual time measured by host are equal within given tolerance
00375  *
00376  * Original description:
00377  * 1) DUT would start to update callback_trigger_count every milli sec
00378  * 2) Host would query what is current count base_time, Device responds by the callback_trigger_count
00379  * 3) Host after waiting for measurement stretch. It will query for device time again final_time.
00380  * 4) Host computes the drift considering base_time, final_time, transport delay and measurement stretch
00381  * 5) Finally host send the results back to device pass/fail based on tolerance.
00382  * 6) More details on tests can be found in timing_drift_auto.py
00383  */
00384 template<typename T>
00385 void test_drift(void)
00386 {
00387     char _key[11] = { };
00388     char _value[128] = { };
00389     int expected_key = 1;
00390     TimeoutDriftTester<T> timeout(DRIFT_TEST_PERIOD_US);
00391 
00392     greentea_send_kv("timing_drift_check_start", 0);
00393     timeout.reschedule_callback();
00394 
00395     // wait for 1st signal from host
00396     do {
00397         greentea_parse_kv(_key, _value, sizeof(_key), sizeof(_value));
00398         expected_key = strcmp(_key, "base_time");
00399     } while (expected_key);
00400 
00401     greentea_send_kv(_key, timeout.get_callback_count() * DRIFT_TEST_PERIOD_US);
00402 
00403     // wait for 2nd signal from host
00404     greentea_parse_kv(_key, _value, sizeof(_key), sizeof(_value));
00405     greentea_send_kv(_key, timeout.get_callback_count() * DRIFT_TEST_PERIOD_US);
00406 
00407     timeout.detach_callback();
00408 
00409     //get the results from host
00410     greentea_parse_kv(_key, _value, sizeof(_key), sizeof(_value));
00411 
00412     TEST_ASSERT_EQUAL_STRING_MESSAGE("pass", _key, "Host script reported a failure");
00413 }
00414 
00415 #endif