From 96ec8ee80a18502c2159497e821df3fcd0dc7411 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Fri, 22 Aug 2014 17:09:36 +0200 Subject: rtems: Add more clock tick functions Add rtems_clock_tick_later(), rtems_clock_tick_later_usec() and rtems_clock_tick_before(). --- cpukit/rtems/include/rtems/rtems/clock.h | 71 +++++++++++++++++++++ doc/user/clock.t | 104 +++++++++++++++++++++++++++++++ testsuites/sptests/sp37/init.c | 55 ++++++++++++++++ testsuites/sptests/sp37/sp37.doc | 5 ++ testsuites/sptests/sp37/system.h | 4 ++ 5 files changed, 239 insertions(+) diff --git a/cpukit/rtems/include/rtems/rtems/clock.h b/cpukit/rtems/include/rtems/rtems/clock.h index ff71665132..7595f5e8c4 100644 --- a/cpukit/rtems/include/rtems/rtems/clock.h +++ b/cpukit/rtems/include/rtems/rtems/clock.h @@ -34,6 +34,7 @@ #include #include #include +#include #include /* struct timeval */ @@ -159,6 +160,76 @@ RTEMS_INLINE_ROUTINE rtems_interval rtems_clock_get_ticks_since_boot(void) return _Watchdog_Ticks_since_boot; } +/** + * @brief Returns the ticks counter value delta ticks in the future. + * + * @param[in] delta The ticks delta value. + * + * @return The tick counter value delta ticks in the future. + */ +RTEMS_INLINE_ROUTINE rtems_interval rtems_clock_tick_later( + rtems_interval delta +) +{ + return _Watchdog_Ticks_since_boot + delta; +} + +/** + * @brief Returns the ticks counter value at least delta microseconds in the + * future. + * + * @param[in] delta_in_usec The delta value in microseconds. + * + * @return The tick counter value at least delta microseconds in the future. + */ +RTEMS_INLINE_ROUTINE rtems_interval rtems_clock_tick_later_usec( + rtems_interval delta_in_usec +) +{ + rtems_interval us_per_tick = rtems_configuration_get_microseconds_per_tick(); + + /* + * Add one additional tick, since we don't know the time to the clock next + * tick. + */ + return _Watchdog_Ticks_since_boot + + (delta_in_usec + us_per_tick - 1) / us_per_tick + 1; +} + +/** + * @brief Returns true if the current ticks counter value indicates a time + * before the time specified by the tick value and false otherwise. + * + * @param[in] tick The tick value. + * + * This can be used to write busy loops with a timeout. + * + * @code + * status busy( void ) + * { + * rtems_interval timeout = rtems_clock_tick_later_usec( 10000 ); + * + * do { + * if ( ok() ) { + * return success; + * } + * } while ( rtems_clock_tick_before( timeout ) ); + * + * return timeout; + * } + * @endcode + * + * @retval true The current ticks counter value indicates a time before the + * time specified by the tick value. + * @retval false Otherwise. + */ +RTEMS_INLINE_ROUTINE bool rtems_clock_tick_before( + rtems_interval tick +) +{ + return (int32_t) ( tick - _Watchdog_Ticks_since_boot ) > 0; +} + /** * @brief Obtain Ticks Per Seconds * diff --git a/doc/user/clock.t b/doc/user/clock.t index 921d1cbbe8..1e821adca2 100644 --- a/doc/user/clock.t +++ b/doc/user/clock.t @@ -21,6 +21,9 @@ the clock manager are: @item @code{@value{DIRPREFIX}clock_get_seconds_since_epoch} - Get seconds since epoch @item @code{@value{DIRPREFIX}clock_get_ticks_per_second} - Get ticks per second @item @code{@value{DIRPREFIX}clock_get_ticks_since_boot} - Get current ticks counter value +@item @code{@value{DIRPREFIX}clock_tick_later} - Get tick value in the future +@item @code{@value{DIRPREFIX}clock_tick_later_usec} - Get tick value in the future in microseconds +@item @code{@value{DIRPREFIX}clock_tick_before} - Is tick value is before a point in time @item @code{@value{DIRPREFIX}clock_get_uptime} - Get time since boot @item @code{@value{DIRPREFIX}clock_get_uptime_timeval} - Get time since boot in timeval format @item @code{@value{DIRPREFIX}clock_get_uptime_seconds} - Get seconds since boot @@ -613,6 +616,107 @@ This directive is callable from an ISR. This directive will not cause the running task to be preempted. +@c +@c +@c +@page +@subsection CLOCK_TICK_LATER - Get tick value in the future + +@subheading CALLING SEQUENCE: + +@ifset is-C +@findex rtems_clock_tick_later +@example +rtems_interval rtems_clock_tick_later( + rtems_interval delta +); +@end example +@end ifset + +@subheading DESCRIPTION: + +Returns the ticks counter value delta ticks in the future. + +@subheading NOTES: + +This directive is callable from an ISR. + +This directive will not cause the running task to be preempted. + +@c +@c +@c +@page +@subsection CLOCK_TICK_LATER_USEC - Get tick value in the future in microseconds + +@subheading CALLING SEQUENCE: + +@ifset is-C +@findex rtems_clock_tick_later_usec +@example +rtems_interval rtems_clock_tick_later_usec( + rtems_interval delta_in_usec +); +@end example +@end ifset + +@subheading DESCRIPTION: + +Returns the ticks counter value at least delta microseconds in the future. + +@subheading NOTES: + +This directive is callable from an ISR. + +This directive will not cause the running task to be preempted. + +@c +@c +@c +@page +@subsection CLOCK_TICK_BEFORE - Is tick value is before a point in time + +@subheading CALLING SEQUENCE: + +@ifset is-C +@findex rtems_clock_tick_before +@example +rtems_interval rtems_clock_tick_before( + rtems_interval tick +); +@end example +@end ifset + +@subheading DESCRIPTION: + +Returns true if the current ticks counter value indicates a time before the +time specified by the tick value and false otherwise. + +@subheading NOTES: + +This directive is callable from an ISR. + +This directive will not cause the running task to be preempted. + +@subheading EXAMPLE: + +@example +@group +status busy( void ) +@{ + rtems_interval timeout = rtems_clock_tick_later_usec( 10000 ); + + do @{ + if ( ok() ) @{ + return success; + @} + @} while ( rtems_clock_tick_before( timeout ) ); + + return timeout; +@} +@end group +@end example + @c @c @c diff --git a/testsuites/sptests/sp37/init.c b/testsuites/sptests/sp37/init.c index be0bd3225e..60ae01bf01 100644 --- a/testsuites/sptests/sp37/init.c +++ b/testsuites/sptests/sp37/init.c @@ -230,6 +230,59 @@ static void test_interrupt_locks( void ) rtems_interrupt_lock_destroy( &initialized ); } +static void test_clock_tick_functions( void ) +{ + rtems_interrupt_level level; + Watchdog_Interval saved_ticks; + + _Thread_Disable_dispatch(); + rtems_interrupt_disable( level ); + + saved_ticks = _Watchdog_Ticks_since_boot; + + _Watchdog_Ticks_since_boot = 0xdeadbeef; + rtems_test_assert( rtems_clock_get_ticks_since_boot() == 0xdeadbeef ); + + rtems_test_assert( rtems_clock_tick_later( 0 ) == 0xdeadbeef ); + rtems_test_assert( rtems_clock_tick_later( 0x8160311e ) == 0x600df00d ); + + _Watchdog_Ticks_since_boot = 0; + rtems_test_assert( rtems_clock_tick_later_usec( 0 ) == 1 ); + rtems_test_assert( rtems_clock_tick_later_usec( 1 ) == 2 ); + rtems_test_assert( rtems_clock_tick_later_usec( US_PER_TICK ) == 2 ); + rtems_test_assert( rtems_clock_tick_later_usec( US_PER_TICK + 1 ) == 3 ); + + _Watchdog_Ticks_since_boot = 0; + rtems_test_assert( !rtems_clock_tick_before( 0xffffffff ) ); + rtems_test_assert( !rtems_clock_tick_before( 0 ) ); + rtems_test_assert( rtems_clock_tick_before( 1 ) ); + + _Watchdog_Ticks_since_boot = 1; + rtems_test_assert( !rtems_clock_tick_before( 0 ) ); + rtems_test_assert( !rtems_clock_tick_before( 1 ) ); + rtems_test_assert( rtems_clock_tick_before( 2 ) ); + + _Watchdog_Ticks_since_boot = 0x7fffffff; + rtems_test_assert( !rtems_clock_tick_before( 0x7ffffffe ) ); + rtems_test_assert( !rtems_clock_tick_before( 0x7fffffff ) ); + rtems_test_assert( rtems_clock_tick_before( 0x80000000 ) ); + + _Watchdog_Ticks_since_boot = 0x80000000; + rtems_test_assert( !rtems_clock_tick_before( 0x7fffffff ) ); + rtems_test_assert( !rtems_clock_tick_before( 0x80000000 ) ); + rtems_test_assert( rtems_clock_tick_before( 0x80000001 ) ); + + _Watchdog_Ticks_since_boot = 0xffffffff; + rtems_test_assert( !rtems_clock_tick_before( 0xfffffffe ) ); + rtems_test_assert( !rtems_clock_tick_before( 0xffffffff ) ); + rtems_test_assert( rtems_clock_tick_before( 0 ) ); + + _Watchdog_Ticks_since_boot = saved_ticks; + + rtems_interrupt_enable( level ); + _Thread_Enable_dispatch(); +} + void test_interrupt_inline(void) { rtems_interrupt_level level; @@ -413,6 +466,8 @@ rtems_task Init( directive_failed( status, "rtems_clock_tick" ); puts( "clock_tick from task level" ); + test_clock_tick_functions(); + /* * Now do a dispatch directly out of a clock tick that is * called from a task. We need to create a task that will diff --git a/testsuites/sptests/sp37/sp37.doc b/testsuites/sptests/sp37/sp37.doc index 9e814f2752..b98faa1caa 100644 --- a/testsuites/sptests/sp37/sp37.doc +++ b/testsuites/sptests/sp37/sp37.doc @@ -13,6 +13,9 @@ test set name: sp37 directives: rtems_clock_tick + rtems_clock_tick_later() + rtems_clock_tick_later_usec() + rtems_clock_tick_before() rtems_interrupt_disable (inline/body) rtems_interrupt_enable (inline/body) rtems_interrupt_flash (inline/body) @@ -24,6 +27,8 @@ concepts: + Ensure that rtems_clock_tick operates properly when invoked from a task rather than an ISR. ++ Ensure that clock tick counter functions work properly. + + Ensure that the interrupt disable, enable, and flash directives operate as expected. diff --git a/testsuites/sptests/sp37/system.h b/testsuites/sptests/sp37/system.h index 43bef8129e..6bb47ec11f 100644 --- a/testsuites/sptests/sp37/system.h +++ b/testsuites/sptests/sp37/system.h @@ -15,6 +15,8 @@ #include +#define US_PER_TICK 10000 + /* functions */ rtems_task Init( @@ -28,6 +30,8 @@ rtems_task Init( #define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION +#define CONFIGURE_MICROSECONDS_PER_TICK US_PER_TICK + #define CONFIGURE_RTEMS_INIT_TASKS_TABLE #define CONFIGURE_INIT_TASK_PRIORITY 2 #define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_PREEMPT -- cgit v1.2.3