Skip to content

Commit cbb8a1f

Browse files
authored
Merge pull request #4947 from fkjagodzinski/rtostimer_tests
Rtostimer tests
2 parents 0c679a8 + 311d38b commit cbb8a1f

File tree

2 files changed

+379
-4
lines changed

2 files changed

+379
-4
lines changed
Lines changed: 367 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,367 @@
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+
#include "mbed.h"
17+
#include "greentea-client/test_env.h"
18+
#include "unity.h"
19+
#include "utest.h"
20+
#include "rtos.h"
21+
22+
using namespace utest::v1;
23+
24+
#define TEST_DELAY_MS 50
25+
#define TEST_DELAY2_MS 30
26+
#define TEST_DELAY_MS_DELTA 1
27+
#define TEST_RESTART_DELAY_MS 10
28+
29+
#if TEST_RESTART_DELAY_MS >= TEST_DELAY_MS
30+
#error invalid TEST_RESTART_DELAY_MS value
31+
#endif
32+
33+
void timer_callback(void const *arg)
34+
{
35+
Semaphore *sem = (Semaphore *) arg;
36+
sem->release();
37+
}
38+
39+
/* In order to successfully run this test suite when compiled with --profile=debug
40+
* error() has to be redefined as noop.
41+
*
42+
* RtosTimer calls RTX API which uses Event Recorder functionality. When compiled
43+
* with MBED_TRAP_ERRORS_ENABLED=1 (set in debug profile) EvrRtxTimerError() calls error()
44+
* which aborts test program.
45+
*/
46+
#if defined(MBED_TRAP_ERRORS_ENABLED) && MBED_TRAP_ERRORS_ENABLED
47+
void error(const char* format, ...) {
48+
(void) format;
49+
}
50+
#endif
51+
52+
/** Test one-shot not restarted when elapsed
53+
*
54+
* Given a one-shot timer
55+
* When the timer is started
56+
* and given time elapses
57+
* Then timer stops
58+
* and elapsed time matches given delay
59+
* and timer stays stopped
60+
*/
61+
void test_oneshot_not_restarted()
62+
{
63+
Semaphore sem(1);
64+
RtosTimer timer(mbed::callback(timer_callback, (void const *) &sem), osTimerOnce);
65+
osStatus stat = timer.stop();
66+
TEST_ASSERT_EQUAL(osErrorResource, stat);
67+
68+
Timer t;
69+
sem.wait(0);
70+
stat = timer.start(TEST_DELAY_MS);
71+
t.start();
72+
TEST_ASSERT_EQUAL(osOK, stat);
73+
74+
int32_t slots = sem.wait(TEST_DELAY_MS + 1);
75+
t.stop();
76+
TEST_ASSERT_EQUAL(1, slots);
77+
TEST_ASSERT_INT_WITHIN(TEST_DELAY_MS_DELTA * 1000, TEST_DELAY_MS * 1000, t.read_us());
78+
79+
slots = sem.wait(TEST_DELAY_MS + 1);
80+
TEST_ASSERT_EQUAL(0, slots);
81+
82+
stat = timer.stop();
83+
TEST_ASSERT_EQUAL(osErrorResource, stat);
84+
}
85+
86+
/** Test periodic repeats continuously
87+
*
88+
* Given a periodic timer
89+
* When timer is started
90+
* and given time elapses
91+
* Then timer repeats its operation
92+
* When timer is stopped
93+
* Then timer stops operation
94+
*/
95+
void test_periodic_repeats()
96+
{
97+
Semaphore sem(1);
98+
RtosTimer timer(mbed::callback(timer_callback, (void const *) &sem), osTimerPeriodic);
99+
osStatus stat = timer.stop();
100+
TEST_ASSERT_EQUAL(osErrorResource, stat);
101+
102+
Timer t;
103+
sem.wait(0);
104+
stat = timer.start(TEST_DELAY_MS);
105+
t.start();
106+
TEST_ASSERT_EQUAL(osOK, stat);
107+
108+
int32_t slots = sem.wait(TEST_DELAY_MS + 1);
109+
int t1 = t.read_us();
110+
TEST_ASSERT_EQUAL(1, slots);
111+
TEST_ASSERT_INT_WITHIN(TEST_DELAY_MS_DELTA * 1000, TEST_DELAY_MS * 1000, t1);
112+
113+
slots = sem.wait(TEST_DELAY_MS + 1);
114+
t.stop();
115+
TEST_ASSERT_EQUAL(1, slots);
116+
TEST_ASSERT_INT_WITHIN(TEST_DELAY_MS_DELTA * 1000, TEST_DELAY_MS * 1000, t.read_us() - t1);
117+
118+
stat = timer.stop();
119+
TEST_ASSERT_EQUAL(osOK, stat);
120+
121+
slots = sem.wait(TEST_DELAY_MS + 1);
122+
TEST_ASSERT_EQUAL(0, slots);
123+
124+
stat = timer.stop();
125+
TEST_ASSERT_EQUAL(osErrorResource, stat);
126+
}
127+
128+
/** Test timer can be restarted
129+
*
130+
* Given a one-shot timer
131+
* When the timer is started
132+
* and @a start is called again before given time elapses
133+
* and given time elapses
134+
* Then timer stops
135+
* and elapsed time is greater than original delay
136+
*/
137+
void test_restart()
138+
{
139+
Semaphore sem(1);
140+
RtosTimer timer(mbed::callback(timer_callback, (void const *) &sem), osTimerOnce);
141+
osStatus stat = timer.stop();
142+
TEST_ASSERT_EQUAL(osErrorResource, stat);
143+
144+
Timer t;
145+
sem.wait(0);
146+
stat = timer.start(TEST_DELAY_MS);
147+
t.start();
148+
TEST_ASSERT_EQUAL(osOK, stat);
149+
150+
int32_t slots = sem.wait(TEST_RESTART_DELAY_MS);
151+
TEST_ASSERT_EQUAL(0, slots);
152+
153+
stat = timer.start(TEST_DELAY_MS);
154+
TEST_ASSERT_EQUAL(osOK, stat);
155+
156+
slots = sem.wait(TEST_DELAY_MS + 1);
157+
t.stop();
158+
TEST_ASSERT_EQUAL(1, slots);
159+
TEST_ASSERT_INT_WITHIN(TEST_DELAY_MS_DELTA * 1000, (TEST_DELAY_MS + TEST_RESTART_DELAY_MS) * 1000, t.read_us());
160+
161+
stat = timer.stop();
162+
TEST_ASSERT_EQUAL(osErrorResource, stat);
163+
}
164+
165+
/** Test timer can be started again
166+
*
167+
* Given a one-shot timer
168+
* When the timer is started
169+
* and given time elapses
170+
* Then timer stops
171+
* When the timer is started again
172+
* and given time elapses
173+
* Then timer stops again
174+
*/
175+
void test_start_again()
176+
{
177+
Semaphore sem(1);
178+
RtosTimer timer(mbed::callback(timer_callback, (void const *) &sem), osTimerOnce);
179+
osStatus stat = timer.stop();
180+
TEST_ASSERT_EQUAL(osErrorResource, stat);
181+
182+
sem.wait(0);
183+
stat = timer.start(TEST_DELAY_MS);
184+
TEST_ASSERT_EQUAL(osOK, stat);
185+
186+
int32_t slots = sem.wait(TEST_DELAY_MS + 1);
187+
TEST_ASSERT_EQUAL(1, slots);
188+
189+
stat = timer.stop();
190+
TEST_ASSERT_EQUAL(osErrorResource, stat);
191+
192+
stat = timer.start(TEST_DELAY_MS);
193+
TEST_ASSERT_EQUAL(osOK, stat);
194+
195+
slots = sem.wait(TEST_DELAY_MS + 1);
196+
TEST_ASSERT_EQUAL(1, slots);
197+
198+
stat = timer.stop();
199+
TEST_ASSERT_EQUAL(osErrorResource, stat);
200+
}
201+
202+
/** Test timer restart updates delay
203+
*
204+
* Given a one-shot timer
205+
* When the timer is started
206+
* and @a start is called again with a different delay before given time elapses
207+
* and updated delay elapses
208+
* Then timer stops
209+
* and time elapsed since the second @a start call matches updated delay
210+
*/
211+
void test_restart_updates_delay()
212+
{
213+
Semaphore sem(1);
214+
RtosTimer timer(mbed::callback(timer_callback, (void const *) &sem), osTimerOnce);
215+
osStatus stat = timer.stop();
216+
TEST_ASSERT_EQUAL(osErrorResource, stat);
217+
218+
sem.wait(0);
219+
stat = timer.start(TEST_DELAY_MS);
220+
TEST_ASSERT_EQUAL(osOK, stat);
221+
222+
int32_t slots = sem.wait(TEST_RESTART_DELAY_MS);
223+
TEST_ASSERT_EQUAL(0, slots);
224+
225+
Timer t;
226+
stat = timer.start(TEST_DELAY2_MS);
227+
t.start();
228+
TEST_ASSERT_EQUAL(osOK, stat);
229+
230+
slots = sem.wait(TEST_DELAY2_MS + 1);
231+
t.stop();
232+
TEST_ASSERT_EQUAL(1, slots);
233+
TEST_ASSERT_INT_WITHIN(TEST_DELAY_MS_DELTA * 1000, TEST_DELAY2_MS * 1000, t.read_us());
234+
235+
stat = timer.stop();
236+
TEST_ASSERT_EQUAL(osErrorResource, stat);
237+
}
238+
239+
/** Test timer is created in stopped state
240+
*
241+
* Given a one-shot timer
242+
* When the timer has not been started
243+
* Then the timer is stopped
244+
*/
245+
void test_created_stopped()
246+
{
247+
RtosTimer timer(mbed::callback(timer_callback, (void const *) NULL), osTimerOnce);
248+
osStatus stat = timer.stop();
249+
TEST_ASSERT_EQUAL(osErrorResource, stat);
250+
}
251+
252+
/** Test one-shot can be stopped
253+
*
254+
* Given a one-shot timer
255+
* When the timer is started
256+
* and timer is stopped while still running
257+
* Then timer stops operation
258+
*/
259+
void test_stop()
260+
{
261+
Semaphore sem(1);
262+
RtosTimer timer(mbed::callback(timer_callback, (void const *) &sem), osTimerOnce);
263+
osStatus stat = timer.stop();
264+
TEST_ASSERT_EQUAL(osErrorResource, stat);
265+
266+
sem.wait(0);
267+
stat = timer.start(TEST_DELAY_MS);
268+
TEST_ASSERT_EQUAL(osOK, stat);
269+
270+
int32_t slots = sem.wait(TEST_RESTART_DELAY_MS);
271+
TEST_ASSERT_EQUAL(0, slots);
272+
273+
stat = timer.stop();
274+
TEST_ASSERT_EQUAL(osOK, stat);
275+
276+
slots = sem.wait(TEST_DELAY_MS + 1);
277+
TEST_ASSERT_EQUAL(0, slots);
278+
279+
stat = timer.stop();
280+
TEST_ASSERT_EQUAL(osErrorResource, stat);
281+
}
282+
283+
/** Test timer started with infinite delay
284+
*
285+
* Given a one-shot timer
286+
* When the timer is started with @a osWaitForever delay
287+
* Then @a start return status is @a osOK
288+
*/
289+
void test_wait_forever()
290+
{
291+
RtosTimer timer(mbed::callback(timer_callback, (void const *) NULL), osTimerOnce);
292+
293+
osStatus stat = timer.start(osWaitForever);
294+
TEST_ASSERT_EQUAL(osOK, stat);
295+
296+
stat = timer.stop();
297+
TEST_ASSERT_EQUAL(osOK, stat);
298+
}
299+
300+
/** Test timer started with zero delay
301+
*
302+
* Given a one-shot timer
303+
* When the timer is started with 0 delay
304+
* Then @a start return status is @a osErrorParameter
305+
*/
306+
void test_no_wait()
307+
{
308+
RtosTimer timer(mbed::callback(timer_callback, (void const *) NULL), osTimerOnce);
309+
310+
osStatus stat = timer.start(0);
311+
TEST_ASSERT_EQUAL(osErrorParameter, stat);
312+
313+
stat = timer.stop();
314+
TEST_ASSERT_EQUAL(osErrorResource, stat);
315+
}
316+
317+
void timer_isr_call(void const *arg)
318+
{
319+
RtosTimer *timer = (RtosTimer *) arg;
320+
osStatus stat = timer->start(TEST_DELAY_MS);
321+
TEST_ASSERT_EQUAL(osErrorISR, stat);
322+
323+
stat = timer->stop();
324+
TEST_ASSERT_EQUAL(osErrorISR, stat);
325+
}
326+
327+
/** Test timer method calls from an ISR fail
328+
*
329+
* Given a one-shot timer
330+
* When a timer method is called from an ISR
331+
* Then method return status is @a osErrorISR
332+
*/
333+
void test_isr_calls_fail()
334+
{
335+
RtosTimer timer(mbed::callback(timer_callback, (void const *) NULL), osTimerOnce);
336+
337+
Ticker ticker;
338+
ticker.attach(mbed::callback(timer_isr_call, (void const *) &timer), (float) TEST_DELAY_MS / 1000.0);
339+
340+
wait_ms(TEST_DELAY_MS + 1);
341+
}
342+
343+
utest::v1::status_t test_setup(const size_t number_of_cases)
344+
{
345+
GREENTEA_SETUP(5, "default_auto");
346+
return verbose_test_setup_handler(number_of_cases);
347+
}
348+
349+
Case cases[] = {
350+
Case("Test one-shot not restarted when elapsed", test_oneshot_not_restarted),
351+
Case("Test periodic repeats continuously", test_periodic_repeats),
352+
Case("Test timer can be restarted while running", test_restart),
353+
Case("Test stopped timer can be started again", test_start_again),
354+
Case("Test restart changes timeout", test_restart_updates_delay),
355+
Case("Test can be stopped", test_stop),
356+
Case("Test timer is created in stopped state", test_created_stopped),
357+
Case("Test timer started with infinite delay", test_wait_forever),
358+
Case("Test timer started with zero delay", test_no_wait),
359+
Case("Test calls from ISR fail", test_isr_calls_fail)
360+
};
361+
362+
Specification specification(test_setup, cases);
363+
364+
int main()
365+
{
366+
return !Harness::run(specification);
367+
}

rtos/RtosTimer.h

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -131,13 +131,21 @@ class RtosTimer : private mbed::NonCopyable<RtosTimer> {
131131
}
132132

133133
/** Stop the timer.
134-
@return status code that indicates the execution status of the function.
134+
@return status code that indicates the execution status of the function:
135+
@a osOK the timer has been stopped.
136+
@a osErrorISR @a stop cannot be called from interrupt service routines.
137+
@a osErrorParameter internal error.
138+
@a osErrorResource the timer is not running.
135139
*/
136140
osStatus stop(void);
137141

138-
/** Start the timer.
139-
@param millisec time delay value of the timer.
140-
@return status code that indicates the execution status of the function.
142+
/** Start or restart the timer.
143+
@param millisec non-zero value of the timer.
144+
@return status code that indicates the execution status of the function:
145+
@a osOK the timer has been started or restarted.
146+
@a osErrorISR @a start cannot be called from interrupt service routines.
147+
@a osErrorParameter internal error or incorrect parameter value.
148+
@a osErrorResource internal error (the timer is in an invalid timer state).
141149
*/
142150
osStatus start(uint32_t millisec);
143151

0 commit comments

Comments
 (0)