Skip to content

Commit acad33a

Browse files
authored
Merge pull request #5548 from fkjagodzinski/test-systimer
Tests for SysTimer (the idle loop timer for tickless mode)
2 parents 3d1174a + d83ed63 commit acad33a

File tree

4 files changed

+522
-100
lines changed

4 files changed

+522
-100
lines changed
Lines changed: 274 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,274 @@
1+
/* mbed Microcontroller Library
2+
* Copyright (c) 2017 ARM Limited
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
#if !MBED_TICKLESS
17+
#error [NOT_SUPPORTED] Tickless mode not supported for this target.
18+
#endif
19+
20+
#if !DEVICE_LOWPOWERTIMER
21+
#error [NOT_SUPPORTED] Current SysTimer implementation requires lp ticker support.
22+
#endif
23+
24+
#include "mbed.h"
25+
#include "greentea-client/test_env.h"
26+
#include "unity.h"
27+
#include "utest.h"
28+
29+
extern "C" {
30+
#include "rtx_lib.h"
31+
}
32+
#include "rtos/TARGET_CORTEX/SysTimer.h"
33+
34+
#define TEST_TICKS 42UL
35+
#define DELAY_DELTA_US 2500ULL
36+
37+
using namespace utest::v1;
38+
39+
const us_timestamp_t DELAY_US = 1000000ULL * TEST_TICKS / OS_TICK_FREQ;
40+
41+
// Override the handler() -- the SysTick interrupt must not be set as pending by the test code.
42+
class SysTimerTest: public rtos::internal::SysTimer {
43+
private:
44+
Semaphore _sem;
45+
virtual void handler()
46+
{
47+
increment_tick();
48+
_sem.release();
49+
}
50+
51+
public:
52+
SysTimerTest() :
53+
SysTimer(), _sem(0, 1)
54+
{
55+
}
56+
57+
virtual ~SysTimerTest()
58+
{
59+
}
60+
61+
int32_t sem_wait(uint32_t millisec)
62+
{
63+
return _sem.wait(millisec);
64+
}
65+
};
66+
67+
/** Test tick count is zero upon creation
68+
*
69+
* Given a SysTimer
70+
* When the timer is created
71+
* Then tick count is zero
72+
*/
73+
void test_created_with_zero_tick_count(void)
74+
{
75+
SysTimerTest st;
76+
TEST_ASSERT_EQUAL_UINT32(0, st.get_tick());
77+
}
78+
79+
/** Test tick count is updated correctly
80+
*
81+
* Given a SysTimer
82+
* When @a update_tick method is called immediately after creation
83+
* Then the tick count is not updated
84+
* When @a update_tick is called again after a delay
85+
* Then the tick count is updated
86+
* and the number of ticks incremented is equal TEST_TICKS - 1
87+
* When @a update_tick is called again without a delay
88+
* Then the tick count is not updated
89+
*/
90+
void test_update_tick(void)
91+
{
92+
SysTimerTest st;
93+
TEST_ASSERT_EQUAL_UINT32(0, st.update_tick());
94+
TEST_ASSERT_EQUAL_UINT32(0, st.get_tick());
95+
us_timestamp_t test_ticks_elapsed_ts = st.get_time() + DELAY_US;
96+
97+
while (st.get_time() <= test_ticks_elapsed_ts) {}
98+
TEST_ASSERT_EQUAL_UINT32(TEST_TICKS - 1, st.update_tick());
99+
TEST_ASSERT_EQUAL_UINT32(TEST_TICKS - 1, st.get_tick());
100+
101+
TEST_ASSERT_EQUAL_UINT32(0, st.update_tick());
102+
TEST_ASSERT_EQUAL_UINT32(TEST_TICKS - 1, st.get_tick());
103+
}
104+
105+
/** Test get_time returns correct time
106+
*
107+
* Given a SysTimer
108+
* When @a get_time method is called before and after a delay
109+
* Then time difference is equal the delay
110+
*/
111+
void test_get_time(void)
112+
{
113+
SysTimerTest st;
114+
us_timestamp_t t1 = st.get_time();
115+
116+
wait_us(DELAY_US);
117+
us_timestamp_t t2 = st.get_time();
118+
TEST_ASSERT_UINT64_WITHIN(DELAY_DELTA_US, DELAY_US, t2 - t1);
119+
}
120+
121+
/** Test cancel_tick
122+
*
123+
* Given a SysTimer with a scheduled tick
124+
* When @a cancel_tick is called before the given number of ticks elapse
125+
* Then the handler is never called
126+
* and the tick count is not incremented
127+
*/
128+
void test_cancel_tick(void)
129+
{
130+
SysTimerTest st;
131+
st.cancel_tick();
132+
st.schedule_tick(TEST_TICKS);
133+
134+
st.cancel_tick();
135+
int32_t sem_slots = st.sem_wait((DELAY_US + DELAY_DELTA_US) / 1000ULL);
136+
TEST_ASSERT_EQUAL_INT32(0, sem_slots);
137+
TEST_ASSERT_EQUAL_UINT32(0, st.get_tick());
138+
}
139+
140+
/** Test schedule zero
141+
*
142+
* Given a SysTimer
143+
* When a tick is scheduled with delta = 0 ticks
144+
* Then the handler is called instantly
145+
*/
146+
void test_schedule_zero(void)
147+
{
148+
SysTimerTest st;
149+
150+
st.schedule_tick(0UL);
151+
int32_t sem_slots = st.sem_wait(0UL);
152+
TEST_ASSERT_EQUAL_INT32(1, sem_slots);
153+
}
154+
155+
/** Test handler called once
156+
*
157+
* Given a SysTimer with a tick scheduled with delta = TEST_TICKS
158+
* When the handler is called
159+
* Then the tick count is incremented by 1
160+
* and elapsed time is equal 1000000ULL * TEST_TICKS / OS_TICK_FREQ;
161+
* When more time elapses
162+
* Then the handler is not called again
163+
*/
164+
void test_handler_called_once(void)
165+
{
166+
SysTimerTest st;
167+
st.schedule_tick(TEST_TICKS);
168+
us_timestamp_t t1 = st.get_time();
169+
int32_t sem_slots = st.sem_wait(0);
170+
TEST_ASSERT_EQUAL_INT32(0, sem_slots);
171+
172+
sem_slots = st.sem_wait(osWaitForever);
173+
us_timestamp_t t2 = st.get_time();
174+
TEST_ASSERT_EQUAL_INT32(1, sem_slots);
175+
TEST_ASSERT_EQUAL_UINT32(1, st.get_tick());
176+
TEST_ASSERT_UINT64_WITHIN(DELAY_DELTA_US, DELAY_US, t2 - t1);
177+
178+
sem_slots = st.sem_wait((DELAY_US + DELAY_DELTA_US) / 1000ULL);
179+
TEST_ASSERT_EQUAL_INT32(0, sem_slots);
180+
TEST_ASSERT_EQUAL_UINT32(1, st.get_tick());
181+
}
182+
183+
/** Test wake up from sleep
184+
*
185+
* Given a SysTimer with a tick scheduled in the future
186+
* and a core in sleep mode
187+
* When given time elapses
188+
* Then the uC is woken up from sleep
189+
* and the tick handler is called
190+
* and measured time matches requested delay
191+
*/
192+
void test_sleep(void)
193+
{
194+
Timer timer;
195+
SysTimerTest st;
196+
197+
sleep_manager_lock_deep_sleep();
198+
timer.start();
199+
st.schedule_tick(TEST_TICKS);
200+
201+
TEST_ASSERT_FALSE_MESSAGE(sleep_manager_can_deep_sleep(), "Deep sleep should be disallowed");
202+
while (st.sem_wait(0) != 1) {
203+
sleep();
204+
}
205+
timer.stop();
206+
sleep_manager_unlock_deep_sleep();
207+
208+
TEST_ASSERT_UINT64_WITHIN(DELAY_DELTA_US, DELAY_US, timer.read_high_resolution_us());
209+
}
210+
211+
#if DEVICE_LOWPOWERTIMER
212+
/** Test wake up from deepsleep
213+
*
214+
* Given a SysTimer with a tick scheduled in the future
215+
* and a core in deepsleep mode
216+
* When given time elapses
217+
* Then the uC is woken up from deepsleep
218+
* and the tick handler is called
219+
* and measured time matches requested delay
220+
*/
221+
void test_deepsleep(void)
222+
{
223+
/*
224+
* Since deepsleep() may shut down the UART peripheral, we wait for 10ms
225+
* to allow for hardware serial buffers to completely flush.
226+
227+
* This should be replaced with a better function that checks if the
228+
* hardware buffers are empty. However, such an API does not exist now,
229+
* so we'll use the wait_ms() function for now.
230+
*/
231+
wait_ms(10);
232+
233+
// Regular Timer might be disabled during deepsleep.
234+
LowPowerTimer lptimer;
235+
SysTimerTest st;
236+
237+
lptimer.start();
238+
st.schedule_tick(TEST_TICKS);
239+
TEST_ASSERT_TRUE_MESSAGE(sleep_manager_can_deep_sleep(), "Deep sleep should be allowed");
240+
while (st.sem_wait(0) != 1) {
241+
sleep();
242+
}
243+
lptimer.stop();
244+
245+
TEST_ASSERT_UINT64_WITHIN(DELAY_DELTA_US, DELAY_US, lptimer.read_high_resolution_us());
246+
}
247+
#endif
248+
249+
utest::v1::status_t test_setup(const size_t number_of_cases)
250+
{
251+
GREENTEA_SETUP(5, "default_auto");
252+
return verbose_test_setup_handler(number_of_cases);
253+
}
254+
255+
Case cases[] = {
256+
Case("Tick count is zero upon creation", test_created_with_zero_tick_count),
257+
Case("Tick count is updated correctly", test_update_tick),
258+
Case("Time is updated correctly", test_get_time),
259+
Case("Tick can be cancelled", test_cancel_tick),
260+
Case("Schedule zero ticks", test_schedule_zero),
261+
Case("Handler called once", test_handler_called_once),
262+
Case("Wake up from sleep", test_sleep),
263+
#if DEVICE_LOWPOWERTIMER
264+
Case("Wake up from deep sleep", test_deepsleep),
265+
#endif
266+
267+
};
268+
269+
Specification specification(test_setup, cases);
270+
271+
int main()
272+
{
273+
return !Harness::run(specification);
274+
}

0 commit comments

Comments
 (0)