Skip to content

TimerEvent tests #5046

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Feb 26, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
219 changes: 219 additions & 0 deletions TESTS/mbed_drivers/timerevent/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
/* mbed Microcontroller Library
* Copyright (c) 2017 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "mbed.h"
#include "greentea-client/test_env.h"
#include "unity.h"
#include "utest.h"
#include "drivers/TimerEvent.h"
#include "hal/ticker_api.h"
#include "rtos.h"

using namespace utest::v1;

#define TEST_DELAY_US 50000ULL

class TestTimerEvent: public TimerEvent {
private:
Semaphore sem;
virtual void handler() {
sem.release();
}

public:
TestTimerEvent() :
TimerEvent(), sem(0, 1) {
}

TestTimerEvent(const ticker_data_t *data) :
TimerEvent(data), sem(0, 1) {
}

virtual ~TestTimerEvent() {
}

// Make these methods publicly accessible
using TimerEvent::insert;
using TimerEvent::insert_absolute;
using TimerEvent::remove;

int32_t sem_wait(uint32_t millisec) {
return sem.wait(millisec);
}
};

class TestTimerEventRelative: public TestTimerEvent {
public:
static const int32_t SEM_SLOTS_AFTER_PAST_TS_INSERTED = 0;
TestTimerEventRelative() :
TestTimerEvent() {
}

TestTimerEventRelative(const ticker_data_t *data) :
TestTimerEvent(data) {
}

// Set relative timestamp of internal event to present_time + ts
void set_future_timestamp(timestamp_t ts) {
insert(::ticker_read(_ticker_data) + ts);
}

void set_past_timestamp(void) {
insert(::ticker_read(_ticker_data) - 1UL);
}
};

class TestTimerEventAbsolute: public TestTimerEvent {
public:
static const int32_t SEM_SLOTS_AFTER_PAST_TS_INSERTED = 1;
TestTimerEventAbsolute() :
TestTimerEvent() {
}

TestTimerEventAbsolute(const ticker_data_t *data) :
TestTimerEvent(data) {
}

// Set absolute timestamp of internal event to present_time + ts
void set_future_timestamp(us_timestamp_t ts) {
insert_absolute(::ticker_read_us(_ticker_data) + ts);
}

void set_past_timestamp(void) {
insert_absolute(::ticker_read_us(_ticker_data) - 1ULL);
}
};

/** Template for tests: insert, insert_absolute
*
* Test insert
* Given an instance of @a TimerEvent subclass
* When a tiestamp is set with @a insert()
* and given time elapses
* Then an event handler is called
*
* Test insert_absolute
* Given an instance of @a TimerEvent subclass
* When a tiestamp is set with @a insert_absolute()
* and given time elapses
* Then an event handler is called
*/
template<typename T>
void test_insert(void) {
T tte;

tte.set_future_timestamp(TEST_DELAY_US);
int32_t sem_slots = tte.sem_wait(0);
TEST_ASSERT_EQUAL(0, sem_slots);

sem_slots = tte.sem_wait(TEST_DELAY_US / 1000 + 1);
TEST_ASSERT_EQUAL(1, sem_slots);

tte.remove();
}

/** Template for tests: remove
*
* Test remove after insert
* Given an instance of @a TimerEvent subclass
* When a tiestamp is set with @a insert()
* and timestamp is removed before being reached
* Then the event handler is never called
*
* Test remove after insert_absolute
* Given an instance of @a TimerEvent subclass
* When a tiestamp is set with @a insert_absolute()
* and timestamp is removed before being reached
* Then the event handler is never called
*/
template<typename T>
void test_remove(void) {
T tte;

tte.set_future_timestamp(TEST_DELAY_US * 2);
int32_t sem_slots = tte.sem_wait(TEST_DELAY_US / 1000);
TEST_ASSERT_EQUAL(0, sem_slots);
tte.remove();

sem_slots = tte.sem_wait(TEST_DELAY_US * 2 / 1000 + 1);
TEST_ASSERT_EQUAL(0, sem_slots);
}

/** Test insert_absolute zero
* Given an instance of @a TimerEvent subclass
* When a timestamp of 0 us is set with @a insert_absolute()
* Then an event handler is called instantly
*/
void test_insert_zero(void) {
TestTimerEvent tte;

tte.insert_absolute(0ULL);
int32_t sem_slots = tte.sem_wait(0);
TEST_ASSERT_EQUAL(1, sem_slots);

tte.remove();
}

/** Template for tests: insert, insert_absolute past timestamp
*
* Test insert timestamp from the past
* Given an instance of @a TimerEvent subclass
* When a timestamp of X us is set with @a insert()
* and X is less than present_time
* Then an event handler is **not** called instantly
* (the event is scheduled after the ticker's overflow)
*
* Test insert_absolute timestamp from the past
* Given an instance of @a TimerEvent subclass
* When a timestamp of X us is set with @a insert_absolute()
* and X is less than present_time
* Then an event handler is called instantly
*/
template<typename T>
void test_insert_past(void) {
T tte;

tte.set_past_timestamp();
int32_t sem_slots = tte.sem_wait(0);
TEST_ASSERT_EQUAL(tte.SEM_SLOTS_AFTER_PAST_TS_INSERTED, sem_slots);

tte.remove();
}

utest::v1::status_t test_setup(const size_t number_of_cases)
{
GREENTEA_SETUP(5, "default_auto");
return verbose_test_setup_handler(number_of_cases);
}

Case cases[] = {
Case("Test insert", test_insert<TestTimerEventRelative>),
Case("Test insert_absolute", test_insert<TestTimerEventAbsolute>),

Case("Test remove after insert", test_remove<TestTimerEventRelative>),
Case("Test remove after insert_absolute", test_remove<TestTimerEventAbsolute>),

Case("Test insert_absolute zero", test_insert_zero),

Case("Test insert timestamp from the past", test_insert_past<TestTimerEventRelative>),
Case("Test insert_absolute timestamp from the past", test_insert_past<TestTimerEventAbsolute>),
};

Specification specification(test_setup, cases);

int main()
{
return !Harness::run(specification);
}
24 changes: 21 additions & 3 deletions drivers/TimerEvent.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,31 @@ class TimerEvent : private NonCopyable<TimerEvent> {
// The handler called to service the timer event of the derived class
virtual void handler() = 0;

// insert relative timestamp in to linked list
/** Set relative timestamp of the internal event.
* @param timestamp event's us timestamp
*
* @warning
* Do not insert more than one timestamp.
* The same @a event object is used for every @a insert/insert_absolute call.
*
* @warning
* Ticker's present timestamp is used for reference. For timestamps
* from the past the event is scheduled after ticker's overflow.
* For reference @see convert_timestamp
*/
void insert(timestamp_t timestamp);

// insert absolute timestamp into linked list
/** Set absolute timestamp of the internal event.
* @param timestamp event's us timestamp
*
* @warning
* Do not insert more than one timestamp.
* The same @a event object is used for every @a insert/insert_absolute call.
*/
void insert_absolute(us_timestamp_t timestamp);

// remove from linked list, if in it
/** Remove timestamp.
*/
void remove();

ticker_event_t event;
Expand Down
2 changes: 1 addition & 1 deletion targets/TARGET_ARM_SSG/TARGET_BEETLE/us_ticker.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ void us_ticker_set_interrupt(timestamp_t timestamp) {

void us_ticker_fire_interrupt(void)
{
uint32_t us_ticker_irqn1 = Timer_GetIRQn(TIMER1);
uint32_t us_ticker_irqn1 = Timer_GetIRQn(TIMER0);
NVIC_SetPendingIRQ((IRQn_Type)us_ticker_irqn1);
}

Expand Down
3 changes: 3 additions & 0 deletions targets/TARGET_Freescale/TARGET_KLXX/us_ticker.c
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,9 @@ void us_ticker_set_interrupt(timestamp_t timestamp) {

void us_ticker_fire_interrupt(void)
{
us_ticker_int_counter = 0;
us_ticker_int_remainder = 0;

#if defined(TARGET_KL43Z)
NVIC_SetPendingIRQ(LPTMR0_IRQn);
#else
Expand Down
4 changes: 3 additions & 1 deletion targets/TARGET_Maxim/TARGET_MAX32600/us_ticker.c
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,9 @@ void us_ticker_set_interrupt(timestamp_t timestamp)

void us_ticker_fire_interrupt(void)
{
NVIC_SetPendingIRQ(US_TIMER_IRQn);
US_TIMER->ctrl &= ~MXC_F_TMR_CTRL_ENABLE0; // disable timer
US_TIMER->term_cnt32 = 1;
US_TIMER->ctrl |= MXC_F_TMR_CTRL_ENABLE0; // enable timer
}

//******************************************************************************
Expand Down
4 changes: 3 additions & 1 deletion targets/TARGET_Maxim/TARGET_MAX32610/us_ticker.c
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,9 @@ void us_ticker_set_interrupt(timestamp_t timestamp)

void us_ticker_fire_interrupt(void)
{
NVIC_SetPendingIRQ(US_TIMER_IRQn);
US_TIMER->ctrl &= ~MXC_F_TMR_CTRL_ENABLE0; // disable timer
US_TIMER->term_cnt32 = 1;
US_TIMER->ctrl |= MXC_F_TMR_CTRL_ENABLE0; // enable timer
}

//******************************************************************************
Expand Down
4 changes: 3 additions & 1 deletion targets/TARGET_Maxim/TARGET_MAX32620/us_ticker.c
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,9 @@ void us_ticker_set_interrupt(timestamp_t timestamp)

void us_ticker_fire_interrupt(void)
{
NVIC_SetPendingIRQ(US_TIMER_IRQn);
US_TIMER->ctrl &= ~MXC_F_TMR_CTRL_ENABLE0; // disable timer
US_TIMER->term_cnt32 = 1;
US_TIMER->ctrl |= MXC_F_TMR_CTRL_ENABLE0; // enable timer
}

//******************************************************************************
Expand Down
2 changes: 1 addition & 1 deletion targets/TARGET_Maxim/TARGET_MAX32625/us_ticker.c
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ void us_ticker_set_interrupt(timestamp_t timestamp)

void us_ticker_fire_interrupt(void)
{
NVIC_SetPendingIRQ(US_TIMER_IRQn);
TMR32_SetCompare(US_TIMER, 1);
}

//******************************************************************************
Expand Down
2 changes: 1 addition & 1 deletion targets/TARGET_Maxim/TARGET_MAX32630/us_ticker.c
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ void us_ticker_set_interrupt(timestamp_t timestamp)

void us_ticker_fire_interrupt(void)
{
NVIC_SetPendingIRQ(US_TIMER_IRQn);
TMR32_SetCompare(US_TIMER, 1);
}

//******************************************************************************
Expand Down
14 changes: 14 additions & 0 deletions targets/TARGET_NORDIC/TARGET_MCU_NRF51822/us_ticker.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "PeripheralNames.h"
#include "nrf_delay.h"
#include "mbed_toolchain.h"
#include "mbed_critical.h"

/*
* Note: The micro-second timer API on the nRF51 platform is implemented using
Expand Down Expand Up @@ -52,6 +53,8 @@
#define RTC_UNITS_TO_MICROSECONDS(RTC_UNITS) (((RTC_UNITS) * (uint64_t)1000000) / RTC_CLOCK_FREQ)
#define MICROSECONDS_TO_RTC_UNITS(MICROS) ((((uint64_t)(MICROS) * RTC_CLOCK_FREQ) + 999999) / 1000000)

#define US_TICKER_SW_IRQ_MASK 0x1

static bool us_ticker_inited = false;
static volatile uint32_t overflowCount; /**< The number of times the 24-bit RTC counter has overflowed. */
static volatile bool us_ticker_callbackPending = false;
Expand All @@ -62,6 +65,9 @@ static bool os_tick_started = false; /**< flag indicating i
*/
static uint32_t previous_tick_cc_value = 0;

// us ticker fire interrupt flag for IRQ handler
volatile uint8_t m_common_sw_irq_flag = 0;

/*
RTX provide the following definitions which are used by the tick code:
* os_trv: The number (minus 1) of clock cycle between two tick.
Expand Down Expand Up @@ -181,6 +187,11 @@ static inline uint32_t rtc1_getCounter(void)
*/
void us_ticker_handler(void)
{
if (m_common_sw_irq_flag & US_TICKER_SW_IRQ_MASK) {
m_common_sw_irq_flag &= ~US_TICKER_SW_IRQ_MASK;
us_ticker_irq_handler();
}

if (NRF_RTC1->EVENTS_OVRFLW) {
overflowCount++;
NRF_RTC1->EVENTS_OVRFLW = 0;
Expand Down Expand Up @@ -287,7 +298,10 @@ void us_ticker_set_interrupt(timestamp_t timestamp)

void us_ticker_fire_interrupt(void)
{
core_util_critical_section_enter();
m_common_sw_irq_flag |= US_TICKER_SW_IRQ_MASK;
NVIC_SetPendingIRQ(RTC1_IRQn);
core_util_critical_section_exit();
}

void us_ticker_disable_interrupt(void)
Expand Down
4 changes: 4 additions & 0 deletions targets/TARGET_NORDIC/TARGET_NRF5/common_rtc.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@
#define OS_TICK_CC_CHANNEL 1
#define LP_TICKER_CC_CHANNEL 2

#define US_TICKER_SW_IRQ_MASK 0x1
#define LP_TICKER_SW_IRQ_MASK 0x2

#define COMMON_RTC_EVENT_COMPARE(channel) \
CONCAT_2(NRF_RTC_EVENT_COMPARE_, channel)
#define COMMON_RTC_INT_COMPARE_MASK(channel) \
Expand All @@ -47,6 +50,7 @@

extern bool m_common_rtc_enabled;
extern uint32_t volatile m_common_rtc_overflows;
extern uint8_t volatile m_common_sw_irq_flag;

void common_rtc_init(void);
uint32_t common_rtc_32bit_ticks_get(void);
Expand Down
Loading