Rtos API example

Revision:
0:9fca2b23d0ba
diff -r 000000000000 -r 9fca2b23d0ba mbed-os/TESTS/mbed_hal/ticker/main.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-os/TESTS/mbed_hal/ticker/main.cpp	Sat Feb 23 12:13:36 2019 +0000
@@ -0,0 +1,2378 @@
+/* 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.
+ */
+
+#define __STDC_LIMIT_MACROS
+#include <stdint.h>
+#include <algorithm>
+
+#include "utest/utest.h"
+#include "unity/unity.h"
+#include "greentea-client/test_env.h"
+
+#include "mbed.h"
+#include "ticker_api.h"
+
+using namespace utest::v1;
+
+#define MBED_ARRAY_SIZE(array) (sizeof(array)/sizeof(array[0]))
+
+#define TIMESTAMP_MAX_DELTA_BITS(bits)  ((uint64_t)(0x7 << ((bits) - 4)))
+#define TIMESTAMP_MAX_DELTA TIMESTAMP_MAX_DELTA_BITS(32)
+
+struct ticker_interface_stub_t { 
+    ticker_interface_t interface;
+    bool initialized; 
+    bool interrupt_flag;
+    timestamp_t timestamp ;
+    timestamp_t interrupt_timestamp; 
+    unsigned int init_call;
+    unsigned int read_call;
+    unsigned int disable_interrupt_call;
+    unsigned int clear_interrupt_call;
+    unsigned int set_interrupt_call;
+    unsigned int fire_interrupt_call;
+    unsigned int get_info_call;
+};
+
+static ticker_interface_stub_t interface_stub = { 0 };
+static ticker_info_t interface_info_stub = { 0 };
+
+static void ticker_interface_stub_init()
+{
+    ++interface_stub.init_call;
+    interface_stub.initialized = true;
+}
+
+static uint32_t ticker_interface_stub_read()
+{
+    ++interface_stub.read_call;
+    return interface_stub.timestamp;
+} 
+
+static void ticker_interface_stub_disable_interrupt()
+{ 
+    ++interface_stub.disable_interrupt_call;
+}
+
+static void ticker_interface_stub_clear_interrupt()
+{
+    ++interface_stub.clear_interrupt_call;
+    interface_stub.interrupt_flag = false;
+}
+
+static void ticker_interface_stub_set_interrupt(timestamp_t timestamp)
+{
+    ++interface_stub.set_interrupt_call;
+    interface_stub.interrupt_timestamp = timestamp; 
+}
+
+static void ticker_interface_stub_fire_interrupt()
+{
+    ++interface_stub.fire_interrupt_call;
+}
+
+static const ticker_info_t *ticker_interface_stub_get_info()
+{
+    ++interface_stub.get_info_call;
+    return &interface_info_stub;
+}
+
+static void reset_ticker_interface_stub()
+{
+    interface_stub.interface.init = ticker_interface_stub_init;
+    interface_stub.interface.read = ticker_interface_stub_read;
+    interface_stub.interface.disable_interrupt = 
+        ticker_interface_stub_disable_interrupt;
+    interface_stub.interface.clear_interrupt = 
+        ticker_interface_stub_clear_interrupt;
+    interface_stub.interface.set_interrupt =ticker_interface_stub_set_interrupt;
+    interface_stub.interface.fire_interrupt = ticker_interface_stub_fire_interrupt;
+    interface_stub.interface.get_info = ticker_interface_stub_get_info;
+    interface_stub.initialized = false;
+    interface_stub.interrupt_flag = false;
+    interface_stub.timestamp = 0;
+    interface_stub.interrupt_timestamp = 0;
+    interface_stub.init_call = 0;
+    interface_stub.read_call = 0;
+    interface_stub.disable_interrupt_call = 0;
+    interface_stub.clear_interrupt_call = 0;
+    interface_stub.set_interrupt_call = 0;
+    interface_stub.fire_interrupt_call = 0;
+
+    interface_info_stub.frequency = 1000000;
+    interface_info_stub.bits = 32;
+}
+
+// stub of the event queue 
+static ticker_event_queue_t queue_stub = {
+    /* event handler */ NULL,
+    /* head */ NULL,
+    /* timestamp */ 0,
+    /* initialized */ false
+};
+
+static void reset_queue_stub()
+{
+    queue_stub.event_handler = NULL;
+    queue_stub.head = NULL,
+    queue_stub.tick_last_read = 0;
+    queue_stub.tick_remainder = 0;
+    queue_stub.frequency = 0;
+    queue_stub.bitmask = 0;
+    queue_stub.max_delta = 0;
+    queue_stub.max_delta_us = 0;
+    queue_stub.present_time = 0;
+    queue_stub.initialized = false;
+}
+
+// stub of the ticker
+static ticker_data_t ticker_stub = {
+    /* interface */ &interface_stub.interface,
+    /* queue */ &queue_stub
+};
+
+static void reset_ticker_stub()
+{
+    reset_queue_stub();
+    reset_ticker_interface_stub();
+}
+
+const uint32_t test_frequencies[] = {
+    1,
+    32768,      // 2^15
+    1000000,
+    0xFFFFFFFF  // 2^32 - 1
+};
+
+const uint32_t test_bitwidths[] = {
+    32,
+    31,
+    16,
+    8
+};
+
+template < void (F)(uint32_t a, uint32_t b)>
+static void test_over_frequency_and_width(void)
+{
+    for (unsigned int i = 0; i < MBED_ARRAY_SIZE(test_frequencies); i++) {
+        for (unsigned int j = 0; j < MBED_ARRAY_SIZE(test_bitwidths); j++) {
+            reset_ticker_stub();
+            interface_info_stub.frequency = test_frequencies[i];
+            interface_info_stub.bits = test_bitwidths[j];
+
+            F(test_frequencies[i], test_bitwidths[j]);
+        }
+    }
+}
+
+static utest::v1::status_t case_setup_handler(
+    const Case *const source, const size_t index_of_case
+) { 
+    utest::v1::status_t status = greentea_case_setup_handler(source, index_of_case);
+    reset_ticker_stub();
+    return status;
+}
+
+static utest::v1::status_t case_teardown_handler(
+    const Case *const source, const size_t passed, const size_t failed, const failure_t reason
+) { 
+    reset_ticker_stub();
+    utest::v1::status_t status = greentea_case_teardown_handler(
+        source, passed, failed, reason
+    );
+    return status;
+}
+
+static utest::v1::status_t greentea_failure_handler(
+    const Case *const source, const failure_t reason
+) {
+    utest::v1::status_t status = greentea_case_failure_abort_handler(
+        source, reason
+    );
+    return status;
+}
+
+#define MAKE_TEST_CASE(description, handler) \
+    { \
+        description, \
+        handler, \
+        NULL, \
+        NULL, \
+        case_setup_handler, \
+        case_teardown_handler, \
+        greentea_failure_handler \
+    }
+
+/**
+ * Given an unitialized ticker_data instance. 
+ * When the ticker is initialized 
+ * Then: 
+ *   - The ticker interface should be initialized 
+ *   - The queue handler should be set to the handler provided in parameter
+ *   - The internal ticker timestamp should be zero
+ *   - interrupt should be scheduled in current timestamp + 
+ *     TIMESTAMP_MAX_DELTA
+ *   - The queue should not contains any event
+ */
+static void test_ticker_initialization()
+{
+    ticker_event_handler dummy_handler = (ticker_event_handler)0xDEADBEEF;
+
+    // setup of the stub 
+    interface_stub.timestamp = 0xFEEDBABE;
+
+    ticker_set_handler(&ticker_stub, dummy_handler);
+
+    TEST_ASSERT_TRUE(interface_stub.initialized);
+    TEST_ASSERT_EQUAL_PTR(dummy_handler, queue_stub.event_handler);
+    TEST_ASSERT_EQUAL_UINT64(0, queue_stub.present_time);
+    TEST_ASSERT_EQUAL(1, interface_stub.set_interrupt_call);
+    TEST_ASSERT_EQUAL_UINT32(
+        interface_stub.timestamp + TIMESTAMP_MAX_DELTA,
+        interface_stub.interrupt_timestamp
+    );
+    TEST_ASSERT_EQUAL_PTR(NULL, queue_stub.head);
+    TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call);
+}
+
+/**
+ * Given an initialized ticker_data instance. 
+ * When the ticker handler is set to a new value    
+ * Then: 
+ *   - The ticker interface initialization function should not be called.
+ *   - The queue handler should be set to the new handler.
+ *   - The events in the queue should remains the same.
+ */
+static void test_ticker_re_initialization()
+{
+    ticker_event_handler dummy_handler = (ticker_event_handler) 0xDEADBEEF;
+    ticker_event_handler expected_handler = (ticker_event_handler) 0xFEEDDEAF;
+    
+    ticker_event_t first_event = { 0 }; 
+    ticker_event_t second_event  = { 0 }; 
+    ticker_event_t third_event  = { 0 }; 
+
+    first_event.next = &second_event;
+    second_event.next = &third_event;
+
+    // initialize the ticker and put few events in the queue.
+    ticker_set_handler(&ticker_stub, dummy_handler);
+    // simulate insertion, it shouldn't affect the queue behaviour for this test
+    queue_stub.head = &first_event;
+    interface_stub.init_call = 0;
+
+    ticker_set_handler(&ticker_stub, expected_handler);
+
+    TEST_ASSERT_TRUE(interface_stub.initialized);
+    TEST_ASSERT_EQUAL(0, interface_stub.init_call);
+    TEST_ASSERT_EQUAL(expected_handler, queue_stub.event_handler);
+    TEST_ASSERT_EQUAL(&first_event, queue_stub.head);
+    TEST_ASSERT_EQUAL(&second_event, queue_stub.head->next);
+    TEST_ASSERT_EQUAL(&third_event, queue_stub.head->next->next);
+    TEST_ASSERT_EQUAL(NULL, queue_stub.head->next->next->next);
+    TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call);
+}
+
+/**
+ * Given an initialized ticker_data instance. 
+ * When the ticker is read 
+ * Then it should return the value present in the ticker interface
+ */
+static void test_ticker_read()
+{
+    ticker_set_handler(&ticker_stub, NULL);
+
+    timestamp_t timestamps[] = { 
+        0xA,
+        0xAA,
+        0xAAA,
+        0xAAAA,
+        0xAAAAA,
+        0xAAAAAA,
+        0xAAAAAAA,
+        0xAAAAAAAA
+    };
+
+    for (size_t i = 0; i < MBED_ARRAY_SIZE(timestamps); ++i) {
+        interface_stub.timestamp = timestamps[i];
+        TEST_ASSERT_EQUAL_UINT32(timestamps[i], ticker_read(&ticker_stub));
+        TEST_ASSERT_EQUAL_UINT64(timestamps[i], ticker_read_us(&ticker_stub));
+    }
+
+    TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call);
+}
+
+/**
+ * Given an initialized ticker_data instance. 
+ * When the ticker is read and the value read is less than the previous 
+ * value read.
+ * Then:
+ *   - ticker_read should return the value read in the ticker interface 
+ *   - ticker_read_us should return a value where: 
+ *     + lower 8 bytes should be equal to the value in the ticker interface
+ *     + upper 8 bytes should be equal to the previous value of upper 8 bytes
+ *       plus one.
+ */
+static void test_ticker_read_overflow()
+{
+    const timestamp_t timestamps[] = { 
+        0xAAAAAAAA,
+        0xAAAAAAA,
+        0xAAAAAA,
+        0xAAAAA,
+        0xAAAA,
+        0xAAA,
+        0xAA,
+        0xA
+    };
+
+    ticker_set_handler(&ticker_stub, NULL);
+
+    uint32_t upper_bytes_begin = ticker_read_us(&ticker_stub) >> 32;
+
+    for (size_t i = 0; i < MBED_ARRAY_SIZE(timestamps); ++i) {
+        interface_stub.timestamp = timestamps[i];
+        TEST_ASSERT_EQUAL_UINT32(timestamps[i], ticker_read(&ticker_stub));
+        TEST_ASSERT_EQUAL_UINT32(timestamps[i], ticker_read_us(&ticker_stub));
+        TEST_ASSERT_EQUAL_UINT64(
+            upper_bytes_begin + i, ticker_read_us(&ticker_stub) >> 32
+        );
+    }
+
+    TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call);
+}
+
+/**
+ * Given an initialized ticker without user registered events.  
+ * When an event is inserted with ticker_insert_event and the timestamp passed 
+ * in parameter is in range [ticker_timestamp : ticker_timestamp + 
+ * TIMESTAMP_MAX_DELTA[.
+ * Then 
+ *   - The event should be in the queue
+ *   - The interrupt timestamp should be equal to the timestamp of the event 
+ *   - The timestamp of the event should reflect the timestamp requested. 
+ *   - The id of the event should be equal to the id passed in parameter. 
+ */
+static void test_legacy_insert_event_outside_overflow_range()
+{
+    ticker_set_handler(&ticker_stub, NULL);
+    interface_stub.set_interrupt_call = 0;
+
+    // test the end of the range
+    ticker_event_t last_event = { 0 };
+    const timestamp_t timestamp_last_event = 
+        interface_stub.timestamp + TIMESTAMP_MAX_DELTA; 
+    const uint32_t id_last_event = 0xDEADDEAF;
+
+    ticker_insert_event(
+        &ticker_stub, 
+        &last_event, timestamp_last_event, id_last_event
+    );
+
+    TEST_ASSERT_EQUAL_PTR(&last_event, queue_stub.head);
+    TEST_ASSERT_EQUAL(1, interface_stub.set_interrupt_call);    
+    TEST_ASSERT_EQUAL_UINT32(
+        timestamp_last_event, interface_stub.interrupt_timestamp
+    );
+    TEST_ASSERT_EQUAL_PTR(NULL, queue_stub.head->next);
+    TEST_ASSERT_EQUAL_UINT32(timestamp_last_event, last_event.timestamp);
+    TEST_ASSERT_EQUAL_UINT32(id_last_event, last_event.id);
+
+    // test the beginning of the range
+    ticker_event_t first_event = { 0 };
+    const timestamp_t timestamp_first_event = interface_stub.timestamp + 1;
+    const uint32_t id_first_event = 0xAAAAAAAA;
+
+    ticker_insert_event(
+        &ticker_stub, 
+        &first_event, timestamp_first_event, id_first_event
+    );
+
+    TEST_ASSERT_EQUAL_PTR(&first_event, queue_stub.head);
+    TEST_ASSERT_EQUAL(2, interface_stub.set_interrupt_call);    
+    TEST_ASSERT_EQUAL_UINT32(
+        timestamp_first_event, interface_stub.interrupt_timestamp
+    );
+    TEST_ASSERT_EQUAL_PTR(&last_event, queue_stub.head->next);
+    TEST_ASSERT_EQUAL_UINT32(
+        timestamp_first_event, first_event.timestamp
+    );
+    TEST_ASSERT_EQUAL_UINT32(id_first_event, first_event.id);
+
+    TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call);
+}  
+
+/**
+ * Given an initialized ticker without user registered events.  
+ * When an event is inserted with ticker_insert_event and a timestamp in the 
+ * range [ticker_timestamp + TIMESTAMP_MAX_DELTA + 1 : 
+ * ticker_timestamp + UINT32MAX [
+ * Then 
+ *   - The event should be in the queue
+ *   - The interrupt timestamp should be equal to 
+ *     TIMESTAMP_MAX_DELTA 
+ *   - The timestamp of the event should reflect the timestamp requested. 
+ *   - The id of the event should be equal to the id passed in parameter. 
+ */
+static void test_legacy_insert_event_in_overflow_range()
+{
+    ticker_set_handler(&ticker_stub, NULL);
+    interface_stub.set_interrupt_call = 0;
+
+    // test the end of the range
+    ticker_event_t last_event = { 0 };
+    const timestamp_t timestamp_last_event = 
+        interface_stub.timestamp + UINT32_MAX; 
+    const uint32_t id_last_event = 0xDEADDEAF;
+
+    ticker_insert_event(
+        &ticker_stub, 
+        &last_event, timestamp_last_event, id_last_event
+    );
+
+    TEST_ASSERT_EQUAL_PTR(&last_event, queue_stub.head);
+    TEST_ASSERT_EQUAL(1, interface_stub.set_interrupt_call);    
+    TEST_ASSERT_EQUAL_UINT32(
+        interface_stub.timestamp + TIMESTAMP_MAX_DELTA, 
+        interface_stub.interrupt_timestamp
+    );
+    TEST_ASSERT_EQUAL_PTR(NULL, queue_stub.head->next);
+    TEST_ASSERT_EQUAL_UINT32(timestamp_last_event, last_event.timestamp);
+    TEST_ASSERT_EQUAL_UINT32(id_last_event, last_event.id);
+
+    // test the beginning of the range
+    ++interface_stub.timestamp;
+
+    ticker_event_t first_event = { 0 };
+    const timestamp_t timestamp_first_event = 
+        interface_stub.timestamp + TIMESTAMP_MAX_DELTA + 1; 
+    const uint32_t id_first_event = 0xAAAAAAAA;
+
+    ticker_insert_event(
+        &ticker_stub, 
+        &first_event, timestamp_first_event, id_first_event
+    );
+
+    TEST_ASSERT_EQUAL_PTR(&first_event, queue_stub.head);
+    TEST_ASSERT_EQUAL(2, interface_stub.set_interrupt_call);    
+    TEST_ASSERT_EQUAL_UINT32(
+        interface_stub.timestamp + TIMESTAMP_MAX_DELTA, 
+        interface_stub.interrupt_timestamp
+    );
+    TEST_ASSERT_EQUAL_PTR(&last_event, queue_stub.head->next);
+    TEST_ASSERT_EQUAL_UINT32(
+        timestamp_first_event, first_event.timestamp
+    );
+    TEST_ASSERT_EQUAL_UINT32(id_first_event, first_event.id);
+
+    TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call);
+}  
+
+/**
+ * Given an initialized ticker without user registered events.  
+ * When an event is inserted with ticker_insert_event and the timestamp in 
+ * parameter is less than the current timestamp value.
+ * Then 
+ *   - The event should be in the queue
+ *   - The timestamp of the event should reflect the timestamp requested:
+ *     + lower 8 bytes should be equal to the timestamp in input. 
+ *     + upper 8 bytes should be equal to the upper of the upper 8 bytes of the
+ *       timestamp state stored in the queue plus one.
+ *   - The id of the event should be equal to the id passed in parameter. 
+ */
+static void test_legacy_insert_event_overflow(){
+    ticker_set_handler(&ticker_stub, NULL);
+    interface_stub.set_interrupt_call = 0;
+
+    interface_stub.timestamp = 0x20000000;
+    ticker_read(&ticker_stub);
+
+    ticker_event_t event = { 0 };
+    const timestamp_t expected_timestamp = 
+        interface_stub.timestamp + 
+        TIMESTAMP_MAX_DELTA + 
+        1; 
+    const us_timestamp_t expected_us_timestamp = 
+        (((queue_stub.present_time >> 32) + 1) << 32) | expected_timestamp;
+    const uint32_t expected_id = 0xDEADDEAF;
+
+    ticker_insert_event(
+        &ticker_stub, 
+        &event, expected_timestamp, expected_id
+    );
+
+    TEST_ASSERT_EQUAL_PTR(&event, queue_stub.head);
+    TEST_ASSERT_EQUAL(1, interface_stub.set_interrupt_call);    
+    TEST_ASSERT_EQUAL_UINT32(
+        interface_stub.timestamp + TIMESTAMP_MAX_DELTA, 
+        interface_stub.interrupt_timestamp
+    );
+    TEST_ASSERT_EQUAL_PTR(NULL, queue_stub.head->next);
+    TEST_ASSERT_EQUAL_UINT32(expected_us_timestamp, event.timestamp);
+    TEST_ASSERT_EQUAL_UINT32(expected_id, event.id);
+
+    TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call);
+}  
+
+/**
+ * Given an initialized ticker.
+ * When an event is inserted with ticker_insert_event and a timestamp less than 
+ * the one for the next scheduled timestamp.
+ * Then 
+ *   - The event inserted should be the first in the queue
+ *   - The interrupt timestamp should be equal to the timestamp of the event or 
+ *     TIMESTAMP_MAX_DELTA if in the overflow range.
+ *   - The timestamp of the event should reflect the timestamp requested.
+ *   - The id of the event should be equal to the id passed in parameter. 
+ *   - Events in the queue should remained ordered by timestamp.
+ */
+static void test_legacy_insert_event_head()
+{
+    ticker_set_handler(&ticker_stub, NULL);
+    interface_stub.set_interrupt_call = 0;
+
+    const timestamp_t timestamps[] = { 
+        UINT32_MAX,
+        TIMESTAMP_MAX_DELTA + 1,
+        TIMESTAMP_MAX_DELTA,
+        TIMESTAMP_MAX_DELTA / 2,
+        TIMESTAMP_MAX_DELTA / 4,
+        TIMESTAMP_MAX_DELTA / 8,
+        TIMESTAMP_MAX_DELTA / 16,
+    };
+    ticker_event_t events[MBED_ARRAY_SIZE(timestamps)] = { 0 };
+
+    for (size_t i = 0; i < MBED_ARRAY_SIZE(events); ++i) { 
+        ticker_insert_event(
+            &ticker_stub, 
+            &events[i], timestamps[i], i
+        );
+
+        TEST_ASSERT_EQUAL_PTR(&events[i], queue_stub.head);
+        TEST_ASSERT_EQUAL(i + 1, interface_stub.set_interrupt_call);  
+        if (timestamps[i] < TIMESTAMP_MAX_DELTA) { 
+            TEST_ASSERT_EQUAL_UINT32(
+                timestamps[i], 
+                interface_stub.interrupt_timestamp
+            );
+        } else { 
+            TEST_ASSERT_EQUAL_UINT32(
+                TIMESTAMP_MAX_DELTA, 
+                interface_stub.interrupt_timestamp
+            );
+        }
+
+        TEST_ASSERT_EQUAL_UINT32(
+            timestamps[i], events[i].timestamp
+        );
+        TEST_ASSERT_EQUAL_UINT32(i, events[i].id);
+
+        ticker_event_t* e = &events[i];
+        while (e) { 
+            TEST_ASSERT_EQUAL_UINT32(timestamps[e->id], e->timestamp);
+            if (e->next) { 
+                TEST_ASSERT_TRUE(e->id > e->next->id);
+                TEST_ASSERT_TRUE(e->timestamp < e->next->timestamp);
+            } else { 
+                TEST_ASSERT_EQUAL_UINT32(0, e->id);
+            }
+            e = e->next;
+        }
+    }
+
+    TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call);
+}  
+
+/** 
+ * Given an initialized ticker.
+ * When an event is inserted with ticker_insert_event and its timestamp is bigger 
+ * than the one of the last event in the queue.
+ * Then 
+ *   - The event inserted should be the last in the queue
+ *   - The interrupt timestamp should remains equal to the interrupt timestamp 
+ *     of the head event .
+ *   - The timestamp of the event should reflect the timestamp requested.
+ *   - The id of the event should be equal to the id passed in parameter. 
+ *   - Events in the queue should remained ordered by timestamp.
+ */
+static void test_legacy_insert_event_tail()
+{
+    ticker_set_handler(&ticker_stub, NULL);
+    interface_stub.set_interrupt_call = 0;
+
+    const timestamp_t timestamps[] = { 
+        0xA,
+        0xAA,
+        0xAAA,
+        0xAAAA,
+        0xAAAAA,
+        0xAAAAAA,
+        0xAAAAAAA,
+        0xAAAAAAAA,
+    };
+    ticker_event_t events[MBED_ARRAY_SIZE(timestamps)] = { 0 };
+
+    for (size_t i = 0; i < MBED_ARRAY_SIZE(events); ++i) { 
+        ticker_insert_event(
+            &ticker_stub, 
+            &events[i], timestamps[i], i
+        );
+
+        TEST_ASSERT_EQUAL_PTR(&events[0], queue_stub.head);
+        TEST_ASSERT_EQUAL_UINT32(
+            timestamps[0], interface_stub.interrupt_timestamp
+        );
+
+        TEST_ASSERT_EQUAL_UINT32(timestamps[i], events[i].timestamp);
+        TEST_ASSERT_EQUAL_UINT32(i, events[i].id);
+
+        ticker_event_t* e = queue_stub.head;
+        while (e) { 
+            TEST_ASSERT_EQUAL_UINT32(timestamps[e->id], e->timestamp);
+            if (e->next) { 
+                TEST_ASSERT_TRUE(e->id < e->next->id);
+                TEST_ASSERT_TRUE(e->timestamp < e->next->timestamp);
+            } else { 
+                TEST_ASSERT_EQUAL_UINT32(&events[i], e);
+            }
+            e = e->next;
+        }
+    }
+
+    TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call);
+} 
+
+/**
+ * Given an initialized ticker.
+ * When an event is inserted with ticker_insert_event and a timestamp less 
+ * than the current timestamp in the interface and less than the relative 
+ * timestamp of the next event to execute.
+ * Then 
+ *   - The event inserted should be after the head
+ *   - The interrupt timestamp should remains equal to the interrupt timestamp 
+ *     of the head event .
+ *   - The timestamp of the event should reflect the timestamp requested (overflow)
+ *   - The id of the event should be equal to the id passed in parameter. 
+ *   - Events in the queue should remained ordered by timestamp.
+ */
+static void test_legacy_insert_event_multiple_overflow()
+{
+    ticker_set_handler(&ticker_stub, NULL);
+    interface_stub.set_interrupt_call = 0;
+
+    const timestamp_t timestamps[] = { 
+        0xA,
+        0xAA,
+        0xAAA,
+        0xAAAA,
+        0xAAAAA,
+        0xAAAAAA,
+        0xAAAAAAA,
+        0xAAAAAAAA
+    };
+    ticker_event_t events[MBED_ARRAY_SIZE(timestamps)] = { 0 };
+
+    ticker_event_t ref_event;
+    timestamp_t ref_event_timestamp = 0xCCCCCCCC;
+    ticker_insert_event(
+        &ticker_stub, 
+        &ref_event, ref_event_timestamp, 0xDEADBEEF
+    );
+
+    timestamp_t last_timestamp_to_insert = 
+        timestamps[MBED_ARRAY_SIZE(timestamps) - 1];
+    interface_stub.timestamp = 
+        last_timestamp_to_insert + 
+        ((ref_event_timestamp - last_timestamp_to_insert) / 2);
+
+    for (size_t i = 0; i < MBED_ARRAY_SIZE(events); ++i) { 
+        ticker_insert_event(
+            &ticker_stub, 
+            &events[i], timestamps[i], i
+        );
+
+        TEST_ASSERT_EQUAL_PTR(&ref_event, queue_stub.head);
+        TEST_ASSERT_EQUAL_PTR(&events[0], queue_stub.head->next);
+        TEST_ASSERT_EQUAL_UINT32(
+            ref_event_timestamp, interface_stub.interrupt_timestamp
+        );
+
+        TEST_ASSERT_EQUAL_UINT32(timestamps[i], events[i].timestamp);
+        TEST_ASSERT_EQUAL_UINT32(i, events[i].id);
+
+        ticker_event_t* e = queue_stub.head->next;
+        while (e) { 
+            TEST_ASSERT_EQUAL_UINT32(timestamps[e->id], e->timestamp);
+            if (e->next) { 
+                TEST_ASSERT_TRUE(e->id < e->next->id);
+                TEST_ASSERT_TRUE(e->timestamp < e->next->timestamp);
+            } else { 
+                TEST_ASSERT_EQUAL_UINT32(&events[i], e);
+            }
+            e = e->next;
+        }
+    }
+
+    TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call);
+}
+
+/**
+ * Given an initialized ticker.
+ * When an event is inserted with ticker_insert_event.
+ * Then 
+ *   - The event inserted should be at the correct position in the queue
+ *   - The event queue should remain ordered by timestamp
+ *   - The interrupt timestamp should be equal to the interrupt timestamp 
+ *     of the head event or TIMESTAMP_MAX_DELTA if the 
+ *     timestamp is in the overflow range.
+ *   - The timestamp of the event should reflect the timestamp requested (overflow)
+ *   - The id of the event should be equal to the id passed in parameter. 
+ *   - Events in the queue should remained ordered by timestamp.
+ */
+static void test_legacy_insert_event_multiple_random()
+{
+    ticker_set_handler(&ticker_stub, NULL);
+    interface_stub.set_interrupt_call = 0;
+
+    const timestamp_t ref_timestamp = UINT32_MAX / 2;
+    interface_stub.timestamp = ref_timestamp;
+
+    // insert first event at the head of the queue 
+    ticker_event_t first_event;
+    const timestamp_t first_event_timestamp = 
+        ref_timestamp + TIMESTAMP_MAX_DELTA + 100;
+
+    ticker_insert_event(
+        &ticker_stub,
+        &first_event, first_event_timestamp, (uint32_t) &first_event
+    );
+
+    TEST_ASSERT_EQUAL_PTR(&first_event, queue_stub.head);
+    TEST_ASSERT_EQUAL_PTR(NULL, first_event.next);
+    TEST_ASSERT_EQUAL_UINT32(
+        ref_timestamp + TIMESTAMP_MAX_DELTA, interface_stub.interrupt_timestamp
+    );
+    TEST_ASSERT_EQUAL_UINT32(first_event_timestamp, first_event.timestamp);
+    TEST_ASSERT_EQUAL_UINT64(
+        first_event.timestamp,
+        first_event_timestamp + 
+        ((first_event_timestamp < ref_timestamp) ? (1ULL << 32) : 0)
+    );
+    TEST_ASSERT_EQUAL_UINT32((uint32_t) &first_event, first_event.id);
+
+    // insert second event at the tail of the queue
+    ticker_event_t second_event;
+    const timestamp_t second_event_timestamp = first_event_timestamp + 1;
+
+    ticker_insert_event(
+        &ticker_stub,
+        &second_event, second_event_timestamp, (uint32_t) &second_event
+    );
+
+    TEST_ASSERT_EQUAL_PTR(&first_event, queue_stub.head);
+    TEST_ASSERT_EQUAL_PTR(&second_event, first_event.next);
+    TEST_ASSERT_EQUAL_PTR(NULL, second_event.next);
+    TEST_ASSERT_EQUAL_UINT32(
+        ref_timestamp + TIMESTAMP_MAX_DELTA, interface_stub.interrupt_timestamp
+    );
+    TEST_ASSERT_EQUAL_UINT32(second_event_timestamp, second_event.timestamp);
+    TEST_ASSERT_EQUAL_UINT64(
+        second_event.timestamp,
+        second_event_timestamp + 
+        ((second_event_timestamp < ref_timestamp) ? (1ULL << 32) : 0)
+    );
+    TEST_ASSERT_EQUAL_UINT32((uint32_t) &second_event, second_event.id);
+
+
+    // insert third event at the head of the queue out the overflow zone
+    ticker_event_t third_event;
+    const timestamp_t third_event_timestamp = 
+        ref_timestamp + TIMESTAMP_MAX_DELTA - 100;
+
+    ticker_insert_event(
+        &ticker_stub,
+        &third_event, third_event_timestamp, (uint32_t) &third_event
+    );
+
+    TEST_ASSERT_EQUAL_PTR(&third_event, queue_stub.head);
+    TEST_ASSERT_EQUAL_PTR(&first_event, third_event.next);
+    TEST_ASSERT_EQUAL_PTR(&second_event, first_event.next);
+    TEST_ASSERT_EQUAL_PTR(NULL, second_event.next);
+    TEST_ASSERT_EQUAL_UINT32(
+        third_event_timestamp, interface_stub.interrupt_timestamp
+    );
+    TEST_ASSERT_EQUAL_UINT32(third_event_timestamp, third_event.timestamp);
+    TEST_ASSERT_EQUAL_UINT64(
+        third_event.timestamp,
+        third_event_timestamp + 
+        ((third_event_timestamp < ref_timestamp) ? (1ULL << 32) : 0)
+    );
+    TEST_ASSERT_EQUAL_UINT32((uint32_t) &third_event, third_event.id);
+
+    // insert fourth event right after the third event
+    ticker_event_t fourth_event;
+    const timestamp_t fourth_event_timestamp = third_event_timestamp + 50;
+
+    ticker_insert_event(
+        &ticker_stub,
+        &fourth_event, fourth_event_timestamp, (uint32_t) &fourth_event
+    );
+
+    TEST_ASSERT_EQUAL_PTR(&third_event, queue_stub.head);
+    TEST_ASSERT_EQUAL_PTR(&fourth_event, third_event.next);
+    TEST_ASSERT_EQUAL_PTR(&first_event, fourth_event.next);
+    TEST_ASSERT_EQUAL_PTR(&second_event, first_event.next);
+    TEST_ASSERT_EQUAL_PTR(NULL, second_event.next);
+    TEST_ASSERT_EQUAL_UINT32(
+        third_event_timestamp, interface_stub.interrupt_timestamp
+    );
+    TEST_ASSERT_EQUAL_UINT32(fourth_event_timestamp, fourth_event.timestamp);
+    TEST_ASSERT_EQUAL_UINT64(
+        fourth_event.timestamp,
+        fourth_event_timestamp + 
+        ((fourth_event_timestamp < ref_timestamp) ? (1ULL << 32) : 0)
+    );
+    TEST_ASSERT_EQUAL_UINT32((uint32_t) &fourth_event, fourth_event.id);
+
+    TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call);
+}
+
+/**
+ * Given an initialized ticker without user registered events.  
+ * When an event is inserted with ticker_insert_event_us and the timestamp passed 
+ * in parameter is in range [ticker_timestamp : ticker_timestamp + 
+ * TIMESTAMP_MAX_DELTA[.
+ * Then 
+ *   - The event should be in the queue
+ *   - The interrupt timestamp should be equal to the lower 8 bytes of the event. 
+ *   - The timestamp of the event should be equal to the timestamp requested. 
+ *   - The id of the event should be equal to the id passed in parameter. 
+ */
+static void test_insert_event_us_outside_overflow_range()
+{
+    ticker_set_handler(&ticker_stub, NULL);
+    interface_stub.set_interrupt_call = 0;
+    interface_stub.timestamp = 0xAAAAAAAA;
+    queue_stub.tick_last_read = interface_stub.timestamp;
+    queue_stub.present_time = 10ULL << 32 | interface_stub.timestamp;
+
+    // test the end of the range
+    ticker_event_t last_event = { 0 };
+    const us_timestamp_t timestamp_last_event = 
+        queue_stub.present_time + TIMESTAMP_MAX_DELTA;
+    const uint32_t id_last_event = 0xDEADDEAF;
+
+    ticker_insert_event_us(
+        &ticker_stub, 
+        &last_event, timestamp_last_event, id_last_event
+    );
+
+    TEST_ASSERT_EQUAL_PTR(&last_event, queue_stub.head);
+    TEST_ASSERT_EQUAL(1, interface_stub.set_interrupt_call);    
+    TEST_ASSERT_EQUAL_UINT32(
+        timestamp_last_event, interface_stub.interrupt_timestamp
+    );
+    TEST_ASSERT_EQUAL_PTR(NULL, queue_stub.head->next);
+    TEST_ASSERT_EQUAL_UINT64(timestamp_last_event, last_event.timestamp);
+    TEST_ASSERT_EQUAL_UINT32(id_last_event, last_event.id);
+
+    // test the beginning of the range
+    ticker_event_t first_event = { 0 };
+    const us_timestamp_t timestamp_first_event = queue_stub.present_time + 1;
+    const uint32_t id_first_event = 0xAAAAAAAA;
+
+    ticker_insert_event_us(
+        &ticker_stub, 
+        &first_event, timestamp_first_event, id_first_event
+    );
+
+    TEST_ASSERT_EQUAL_PTR(&first_event, queue_stub.head);
+    TEST_ASSERT_EQUAL(2, interface_stub.set_interrupt_call);    
+    TEST_ASSERT_EQUAL_UINT32(
+        timestamp_first_event, interface_stub.interrupt_timestamp
+    );
+    TEST_ASSERT_EQUAL_PTR(&last_event, queue_stub.head->next);
+    TEST_ASSERT_EQUAL_UINT64(
+        timestamp_first_event, first_event.timestamp
+    );
+    TEST_ASSERT_EQUAL_UINT32(id_first_event, first_event.id);
+
+    TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call);
+}  
+
+/**
+ * Given an initialized ticker without user registered events.  
+ * When an event is inserted with ticker_insert_event_us and a timestamp in the 
+ * range [ticker_timestamp + TIMESTAMP_MAX_DELTA + 1 : UINT64_MAX [ 
+ * Then 
+ *   - The event should be in the queue
+ *   - The interrupt timestamp should be equal to TIMESTAMP_MAX_DELTA 
+ *   - The timestamp of the event should be equal to the timestamp in parameter. 
+ *   - The id of the event should be equal to the id passed in parameter. 
+ */
+static void test_insert_event_us_in_overflow_range()
+{
+    ticker_set_handler(&ticker_stub, NULL);
+    interface_stub.set_interrupt_call = 0;
+    interface_stub.timestamp = 0xAAAAAAAA;
+    queue_stub.tick_last_read = interface_stub.timestamp;
+    queue_stub.present_time = 10ULL << 32 | interface_stub.timestamp;
+
+    // test the end of the range
+    ticker_event_t last_event = { 0 };
+    const us_timestamp_t timestamp_last_event = UINT64_MAX; 
+    const uint32_t id_last_event = 0xDEADDEAF;
+
+    ticker_insert_event_us(
+        &ticker_stub, 
+        &last_event, timestamp_last_event, id_last_event
+    );
+
+    TEST_ASSERT_EQUAL_PTR(&last_event, queue_stub.head);
+    TEST_ASSERT_EQUAL(1, interface_stub.set_interrupt_call);    
+    TEST_ASSERT_EQUAL_UINT32(
+        interface_stub.timestamp + TIMESTAMP_MAX_DELTA, 
+        interface_stub.interrupt_timestamp
+    );
+    TEST_ASSERT_EQUAL_PTR(NULL, queue_stub.head->next);
+    TEST_ASSERT_EQUAL_UINT64(timestamp_last_event, last_event.timestamp);
+    TEST_ASSERT_EQUAL_UINT32(id_last_event, last_event.id);
+
+    // test the beginning of the range
+    ++interface_stub.timestamp;
+    ++queue_stub.present_time;
+
+    ticker_event_t first_event = { 0 };
+    const us_timestamp_t timestamp_first_event = 
+        queue_stub.present_time + TIMESTAMP_MAX_DELTA + 1;
+    uint32_t id_first_event = 0xAAAAAAAA;
+
+    ticker_insert_event_us(&ticker_stub, 
+        &first_event, timestamp_first_event, id_first_event
+    );
+
+    TEST_ASSERT_EQUAL_PTR(&first_event, queue_stub.head);
+    TEST_ASSERT_EQUAL(2, interface_stub.set_interrupt_call);    
+    TEST_ASSERT_EQUAL_UINT32(
+        interface_stub.timestamp + TIMESTAMP_MAX_DELTA, 
+        interface_stub.interrupt_timestamp
+    );
+    TEST_ASSERT_EQUAL_PTR(&last_event, queue_stub.head->next);
+    TEST_ASSERT_EQUAL_UINT64(timestamp_first_event, first_event.timestamp);
+    TEST_ASSERT_EQUAL_UINT32(id_first_event, first_event.id);
+
+    TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call);
+} 
+
+/**
+ * Given an initialized ticker without user registered events.  
+ * When an event is inserted with ticker_insert_event_us and a timestamp less 
+ * than timestamp value in the ticker interface.
+ * Then 
+ *   - The event should be in the queue
+ *   - The interrupt timestamp should be set to interface_stub.timestamp so it
+ *     is scheduled immediately.
+ */
+static void test_insert_event_us_underflow()
+{
+    ticker_set_handler(&ticker_stub, NULL);
+    interface_stub.set_interrupt_call = 0;
+
+    interface_stub.timestamp = 0xAAAAAAAA;
+    queue_stub.tick_last_read = interface_stub.timestamp;
+    queue_stub.present_time = 10ULL << 32 | interface_stub.timestamp;
+
+    // test the end of the range
+    ticker_event_t event = { 0 };
+    const timestamp_t expected_timestamp = queue_stub.present_time - 1;
+    const uint32_t expected_id = 0xDEADDEAF;
+
+    ticker_insert_event_us(
+        &ticker_stub,
+        &event, expected_timestamp, expected_id
+    );
+
+    TEST_ASSERT_EQUAL_PTR(&event, queue_stub.head);
+    TEST_ASSERT_EQUAL(1, interface_stub.fire_interrupt_call);
+
+    TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call);
+}  
+
+/**
+ * Given an initialized ticker.
+ * When an event is inserted with ticker_insert_event_us and a timestamp less 
+ * than the one for the next scheduled timestamp.
+ * Then 
+ *   - The event inserted should be the first in the queue
+ *   - The interrupt timestamp should be equal to the timestamp of the event or 
+ *     TIMESTAMP_MAX_DELTA if in the overflow range.
+ *   - The timestamp of the event should be equal to the timestamp in parameter. 
+ *   - The id of the event should be equal to the id passed in parameter. 
+ *   - Events in the queue should remained ordered by timestamp.
+ */
+static void test_insert_event_us_head()
+{
+    ticker_set_handler(&ticker_stub, NULL);
+    interface_stub.set_interrupt_call = 0;
+    interface_stub.timestamp = 0xAAAAAAAA;
+    queue_stub.tick_last_read = interface_stub.timestamp;
+    queue_stub.present_time = 10ULL << 32 | interface_stub.timestamp;
+
+    const us_timestamp_t timestamps[] = { 
+        UINT64_MAX,
+        queue_stub.present_time + TIMESTAMP_MAX_DELTA + 1,
+        queue_stub.present_time + TIMESTAMP_MAX_DELTA,
+        queue_stub.present_time + (TIMESTAMP_MAX_DELTA / 2),
+        queue_stub.present_time + (TIMESTAMP_MAX_DELTA / 4),
+        queue_stub.present_time + (TIMESTAMP_MAX_DELTA / 8),
+        queue_stub.present_time + (TIMESTAMP_MAX_DELTA / 16),
+    };
+    ticker_event_t events[MBED_ARRAY_SIZE(timestamps)] = { 0 };
+
+    for (size_t i = 0; i < MBED_ARRAY_SIZE(events); ++i) { 
+        ticker_insert_event_us(
+            &ticker_stub, 
+            &events[i], timestamps[i], i
+        );
+
+        TEST_ASSERT_EQUAL_PTR(&events[i], queue_stub.head);
+        if ((timestamps[i] - queue_stub.present_time) < TIMESTAMP_MAX_DELTA) {
+            TEST_ASSERT_EQUAL_UINT32(
+                timestamps[i], 
+                interface_stub.interrupt_timestamp
+            );
+        } else { 
+            TEST_ASSERT_EQUAL_UINT32(
+                queue_stub.present_time + TIMESTAMP_MAX_DELTA,
+                interface_stub.interrupt_timestamp
+            );
+        }
+
+        TEST_ASSERT_EQUAL_UINT64(timestamps[i], events[i].timestamp);
+        TEST_ASSERT_EQUAL_UINT32(i, events[i].id);
+
+        ticker_event_t* e = &events[i];
+        while (e) { 
+            TEST_ASSERT_EQUAL_UINT32(timestamps[e->id], e->timestamp);
+            if (e->next) { 
+                TEST_ASSERT_TRUE(e->id > e->next->id);
+                TEST_ASSERT_TRUE(e->timestamp < e->next->timestamp);
+            } else { 
+                TEST_ASSERT_EQUAL_UINT32(0, e->id);
+            }
+            e = e->next;
+        }
+    }
+
+    TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call);
+}  
+
+/** 
+ * Given an initialized ticker.
+ * When an event is inserted with ticker_insert_event_us and its timestamp is 
+ * bigger than the one of the last event in the queue.
+ * Then 
+ *   - The event inserted should be the last in the queue
+ *   - The interrupt timestamp should remains equal to the interrupt timestamp 
+ *     of the head event .
+ *   - The timestamp of the event should reflect the timestamp requested.
+ *   - The id of the event should be equal to the id passed in parameter. 
+ *   - Events in the queue should remained ordered by timestamp.
+ */
+static void test_insert_event_us_tail()
+{
+    ticker_set_handler(&ticker_stub, NULL);
+    interface_stub.set_interrupt_call = 0;
+
+    const us_timestamp_t timestamps[] = { 
+        0xA,
+        (1ULL << 32),
+        (2ULL << 32),
+        (4ULL << 32),
+        (8ULL << 32),
+        (16ULL << 32),
+        (32ULL << 32),
+        (64ULL << 32),
+    };
+    ticker_event_t events[MBED_ARRAY_SIZE(timestamps)] = { 0 };
+
+    for (size_t i = 0; i < MBED_ARRAY_SIZE(events); ++i) { 
+        ticker_insert_event_us(
+            &ticker_stub, 
+            &events[i], timestamps[i], i
+        );
+
+        TEST_ASSERT_EQUAL_PTR(&events[0], queue_stub.head); 
+        TEST_ASSERT_EQUAL_UINT32(
+            timestamps[0], interface_stub.interrupt_timestamp
+        );
+        TEST_ASSERT_EQUAL_UINT64(timestamps[i], events[i].timestamp);
+        TEST_ASSERT_EQUAL_UINT32(i, events[i].id);
+
+        ticker_event_t* e = queue_stub.head;
+        while (e) { 
+            TEST_ASSERT_EQUAL_UINT32(timestamps[e->id], e->timestamp);
+            if (e->next) { 
+                TEST_ASSERT_TRUE(e->id < e->next->id);
+                TEST_ASSERT_TRUE(e->timestamp < e->next->timestamp);
+            } else { 
+                TEST_ASSERT_EQUAL_UINT32(&events[i], e);
+            }
+            e = e->next;
+        }
+    }
+
+    TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call);
+} 
+
+/**
+ * Given an initialized ticker.
+ * When an event is inserted with ticker_insert_event_us.
+ * Then 
+ *   - The event inserted should be at the correct position in the queue
+ *   - The event queue should remain ordered by timestamp
+ *   - The interrupt timestamp should be equal to the interrupt timestamp 
+ *     of the head event or TIMESTAMP_MAX_DELTA if the 
+ *     timestamp is in the overflow range.
+ *   - The timestamp of the event should be equal to the timestamp parameter.
+ *   - The id of the event should be equal to the id passed in parameter. 
+ *   - Events in the queue should remained ordered by timestamp.
+ */
+static void test_insert_event_us_multiple_random()
+{
+    ticker_set_handler(&ticker_stub, NULL);
+    interface_stub.set_interrupt_call = 0;
+
+    const timestamp_t ref_timestamp = UINT32_MAX / 2;
+    interface_stub.timestamp = ref_timestamp;
+
+    // insert first event at the head of the queue 
+    ticker_event_t first_event;
+    const us_timestamp_t first_event_timestamp = 
+        ref_timestamp + TIMESTAMP_MAX_DELTA + 100;
+
+    ticker_insert_event_us(
+        &ticker_stub,
+        &first_event, first_event_timestamp, (uint32_t) &first_event
+    );
+
+    TEST_ASSERT_EQUAL_PTR(&first_event, queue_stub.head);
+    TEST_ASSERT_EQUAL_PTR(NULL, first_event.next);
+    TEST_ASSERT_EQUAL_UINT32(
+        ref_timestamp + TIMESTAMP_MAX_DELTA, interface_stub.interrupt_timestamp
+    );
+    TEST_ASSERT_EQUAL_UINT64(first_event.timestamp, first_event_timestamp);
+    TEST_ASSERT_EQUAL_UINT32((uint32_t) &first_event, first_event.id);
+
+    // insert second event at the tail of the queue
+    ticker_event_t second_event;
+    const us_timestamp_t second_event_timestamp = first_event_timestamp + 1;
+
+    ticker_insert_event_us(
+        &ticker_stub,
+        &second_event, second_event_timestamp, (uint32_t) &second_event
+    );
+
+    TEST_ASSERT_EQUAL_PTR(&first_event, queue_stub.head);
+    TEST_ASSERT_EQUAL_PTR(&second_event, first_event.next);
+    TEST_ASSERT_EQUAL_PTR(NULL, second_event.next);
+    TEST_ASSERT_EQUAL_UINT32(
+        ref_timestamp + TIMESTAMP_MAX_DELTA, interface_stub.interrupt_timestamp
+    );
+    TEST_ASSERT_EQUAL_UINT64(second_event_timestamp, second_event.timestamp);
+    TEST_ASSERT_EQUAL_UINT32((uint32_t) &second_event, second_event.id);
+
+
+    // insert third event at the head of the queue out the overflow zone
+    ticker_event_t third_event;
+    const us_timestamp_t third_event_timestamp = 
+        ref_timestamp + TIMESTAMP_MAX_DELTA - 100;
+
+    ticker_insert_event_us(
+        &ticker_stub,
+        &third_event, third_event_timestamp, (uint32_t) &third_event
+    );
+
+    TEST_ASSERT_EQUAL_PTR(&third_event, queue_stub.head);
+    TEST_ASSERT_EQUAL_PTR(&first_event, third_event.next);
+    TEST_ASSERT_EQUAL_PTR(&second_event, first_event.next);
+    TEST_ASSERT_EQUAL_PTR(NULL, second_event.next);
+    TEST_ASSERT_EQUAL_UINT32(
+        third_event_timestamp, interface_stub.interrupt_timestamp
+    );
+    TEST_ASSERT_EQUAL_UINT64(third_event_timestamp, third_event.timestamp);
+    TEST_ASSERT_EQUAL_UINT32((uint32_t) &third_event, third_event.id);
+
+    // insert fourth event right after the third event
+    ticker_event_t fourth_event;
+    const us_timestamp_t fourth_event_timestamp = third_event_timestamp + 50;
+
+    ticker_insert_event_us(
+        &ticker_stub,
+        &fourth_event, fourth_event_timestamp, (uint32_t) &fourth_event
+    );
+
+    TEST_ASSERT_EQUAL_PTR(&third_event, queue_stub.head);
+    TEST_ASSERT_EQUAL_PTR(&fourth_event, third_event.next);
+    TEST_ASSERT_EQUAL_PTR(&first_event, fourth_event.next);
+    TEST_ASSERT_EQUAL_PTR(&second_event, first_event.next);
+    TEST_ASSERT_EQUAL_PTR(NULL, second_event.next);
+    TEST_ASSERT_EQUAL_UINT32(
+        third_event_timestamp, interface_stub.interrupt_timestamp
+    );
+    TEST_ASSERT_EQUAL_UINT64(fourth_event_timestamp, fourth_event.timestamp);
+    TEST_ASSERT_EQUAL_UINT32((uint32_t) &fourth_event, fourth_event.id);
+
+    TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call);
+}
+
+/**
+ * Given an initialized ticker with multiple events registered. 
+ * When the event at the tail of the queue is removed from the queue.
+ * Then: 
+ *    - The event should not be in the queue.
+ *    - The events in the queue should remain ordered
+ *    - The interrupt timestamp should be unchanged. 
+ */
+static void test_remove_event_tail()
+{
+    ticker_set_handler(&ticker_stub, NULL);
+    const us_timestamp_t timestamps[] = { 
+        0xA,
+        (1ULL << 32),
+        (2ULL << 32),
+        (4ULL << 32),
+        (8ULL << 32),
+        (16ULL << 32),
+        (32ULL << 32),
+        (64ULL << 32),
+    };
+    ticker_event_t events[MBED_ARRAY_SIZE(timestamps)] = { 0 };
+
+    for (size_t i = 0; i < MBED_ARRAY_SIZE(events); ++i) { 
+        ticker_insert_event_us(
+            &ticker_stub, 
+            &events[i], timestamps[i], i
+        );
+    }
+
+    for (ssize_t i = MBED_ARRAY_SIZE(events) - 1; i >= 0; --i) { 
+        ticker_remove_event(&ticker_stub, &events[i]);
+
+        ticker_event_t* e = queue_stub.head;
+        size_t event_count = 0;
+        while (e) { 
+            TEST_ASSERT_NOT_EQUAL(e, &events[i]);
+            if (e->next) { 
+                TEST_ASSERT_TRUE(e->timestamp <= e->next->timestamp);
+            }
+            e = e->next;
+            ++event_count;
+        }
+
+        TEST_ASSERT_EQUAL(i, event_count);
+
+        if (i != 0 ) { 
+            TEST_ASSERT_EQUAL(
+                timestamps[0],
+                interface_stub.interrupt_timestamp
+            );
+        } else { 
+            TEST_ASSERT_EQUAL(
+                interface_stub.timestamp + TIMESTAMP_MAX_DELTA,
+                interface_stub.interrupt_timestamp
+            );
+        }
+    }
+
+    TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call);
+}
+
+/**
+ * Given an initialized ticker with multiple events registered. 
+ * When the event at the head of the queue is removed from the queue.
+ * Then: 
+ *    - The event should not be in the queue.
+ *    - The event at the head of the queue should be the equal to the one 
+ *      after the event removed.
+ *    - The interrupt timestamp should be equal to the interrupt timestamp 
+ *      of the head event or TIMESTAMP_MAX_DELTA if the 
+ *      timestamp is in the overflow range.
+ */
+static void test_remove_event_head()
+{
+    ticker_set_handler(&ticker_stub, NULL);
+    const us_timestamp_t timestamps[] = { 
+        TIMESTAMP_MAX_DELTA / 8,
+        TIMESTAMP_MAX_DELTA / 4,
+        TIMESTAMP_MAX_DELTA / 2,
+        TIMESTAMP_MAX_DELTA - 1,
+        TIMESTAMP_MAX_DELTA,
+        TIMESTAMP_MAX_DELTA + 1,
+        (1ULL << 32) | TIMESTAMP_MAX_DELTA,
+        UINT64_MAX
+    };
+    ticker_event_t events[MBED_ARRAY_SIZE(timestamps)] = { 0 };
+
+    for (size_t i = 0; i < MBED_ARRAY_SIZE(events); ++i) { 
+        ticker_insert_event_us(&ticker_stub, 
+            &events[i], timestamps[i], i
+        );
+    }
+
+    for (size_t i = 0; i < MBED_ARRAY_SIZE(events); ++i) { 
+        ticker_remove_event(&ticker_stub, &events[i]);
+
+        ticker_event_t* e = queue_stub.head;
+        size_t event_count = 0;
+        while (e) { 
+            TEST_ASSERT_NOT_EQUAL(e, &events[i]);
+            if (e->next) { 
+                TEST_ASSERT_TRUE(e->timestamp <= e->next->timestamp);
+            }
+            e = e->next;
+            ++event_count;
+        }
+
+        TEST_ASSERT_EQUAL(MBED_ARRAY_SIZE(events) - i - 1, event_count);
+
+        if (event_count) { 
+            TEST_ASSERT_EQUAL(
+                std::min(
+                    timestamps[i + 1], 
+                    interface_stub.timestamp + TIMESTAMP_MAX_DELTA
+                ),
+                interface_stub.interrupt_timestamp
+            );
+        } else { 
+            TEST_ASSERT_EQUAL(
+                interface_stub.timestamp + TIMESTAMP_MAX_DELTA,
+                interface_stub.interrupt_timestamp
+            );
+        }
+
+    }
+
+    TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call);
+}
+
+/**
+ * Given an initialized ticker with multiple events registered. 
+ * When an event not in the queue is attempted to be removed.
+ * Then the queue should remains identical as before.
+ */
+static void test_remove_event_invalid()
+{
+    ticker_set_handler(&ticker_stub, NULL);
+    const us_timestamp_t timestamps[] = { 
+        TIMESTAMP_MAX_DELTA / 8,
+        TIMESTAMP_MAX_DELTA / 4,
+        TIMESTAMP_MAX_DELTA / 2,
+        TIMESTAMP_MAX_DELTA - 1,
+        TIMESTAMP_MAX_DELTA,
+        TIMESTAMP_MAX_DELTA + 1,
+        (1ULL << 32) | TIMESTAMP_MAX_DELTA,
+        UINT64_MAX
+    };
+    ticker_event_t events[MBED_ARRAY_SIZE(timestamps)] = { 0 };
+
+    for (size_t i = 0; i < MBED_ARRAY_SIZE(events); ++i) { 
+        ticker_insert_event_us(
+            &ticker_stub, 
+            &events[i], timestamps[i], i
+        );
+    }
+
+    ticker_event_t invalid_event;
+    ticker_remove_event(&ticker_stub, &invalid_event);
+
+    TEST_ASSERT_EQUAL(&events[0], queue_stub.head);
+
+    ticker_event_t* e = queue_stub.head;
+    size_t event_count = 0;
+    while (e) { 
+        TEST_ASSERT_EQUAL(e, &events[event_count]);
+        e = e->next;
+        ++event_count;
+    }
+    TEST_ASSERT_EQUAL(MBED_ARRAY_SIZE(events), event_count);
+}
+
+/**
+ * Given an initialized ticker with multiple events inserted.
+ * When an event is remoced
+ * Then:
+ *   - the event should not be in the queue
+ *   - the queue should remain ordered
+ *   - the interrupt timestamp should be set to either head->timestamp or 
+ *     TIMESTAMP_MAX_DELTA depending on the distance between the current time 
+ *     ans the timestamp of the event at the head of the queue.
+ */
+static void test_remove_random()
+{
+    ticker_set_handler(&ticker_stub, NULL);
+    interface_stub.set_interrupt_call = 0;
+
+    const timestamp_t ref_timestamp = UINT32_MAX / 2;
+    interface_stub.timestamp = ref_timestamp;
+
+    // insert all events 
+    ticker_event_t first_event;
+    const us_timestamp_t first_event_timestamp = 
+        ref_timestamp + TIMESTAMP_MAX_DELTA + 100;
+
+    ticker_insert_event_us(
+        &ticker_stub,
+        &first_event, first_event_timestamp, (uint32_t) &first_event
+    );
+
+
+    ticker_event_t second_event;
+    const us_timestamp_t second_event_timestamp = first_event_timestamp + 1;
+
+    ticker_insert_event_us(
+        &ticker_stub,
+        &second_event, second_event_timestamp, (uint32_t) &second_event
+    );
+
+    ticker_event_t third_event;
+    const us_timestamp_t third_event_timestamp = 
+        ref_timestamp + TIMESTAMP_MAX_DELTA - 100;
+
+    ticker_insert_event_us(
+        &ticker_stub,
+        &third_event, third_event_timestamp, (uint32_t) &third_event
+    );
+
+    ticker_event_t fourth_event;
+    const us_timestamp_t fourth_event_timestamp = third_event_timestamp + 50;
+
+    ticker_insert_event_us(
+        &ticker_stub,
+        &fourth_event, fourth_event_timestamp, (uint32_t) &fourth_event
+    );
+
+    // test that the queue is in the correct state 
+    TEST_ASSERT_EQUAL_PTR(&third_event, queue_stub.head);
+    TEST_ASSERT_EQUAL_PTR(&fourth_event, third_event.next);
+    TEST_ASSERT_EQUAL_PTR(&first_event, fourth_event.next);
+    TEST_ASSERT_EQUAL_PTR(&second_event, first_event.next);
+    TEST_ASSERT_EQUAL_PTR(NULL, second_event.next);
+    TEST_ASSERT_EQUAL_UINT32(
+        third_event_timestamp, interface_stub.interrupt_timestamp
+    );
+    TEST_ASSERT_EQUAL_UINT64(fourth_event_timestamp, fourth_event.timestamp);
+    TEST_ASSERT_EQUAL_UINT32((uint32_t) &fourth_event, fourth_event.id);
+
+    // remove fourth event 
+    ticker_remove_event(&ticker_stub, &fourth_event);
+
+    TEST_ASSERT_EQUAL_PTR(&third_event, queue_stub.head);
+    TEST_ASSERT_EQUAL_PTR(&first_event, third_event.next);
+    TEST_ASSERT_EQUAL_PTR(&second_event, first_event.next);
+    TEST_ASSERT_EQUAL_PTR(NULL, second_event.next);
+    TEST_ASSERT_EQUAL_UINT32(
+        third_event_timestamp, interface_stub.interrupt_timestamp
+    );
+    TEST_ASSERT_EQUAL_UINT64(third_event_timestamp, third_event.timestamp);
+    TEST_ASSERT_EQUAL_UINT32((uint32_t) &third_event, third_event.id);
+
+    // remove third event 
+    ticker_remove_event(&ticker_stub, &third_event);
+
+    TEST_ASSERT_EQUAL_PTR(&first_event, queue_stub.head);
+    TEST_ASSERT_EQUAL_PTR(&second_event, first_event.next);
+    TEST_ASSERT_EQUAL_PTR(NULL, second_event.next);
+    TEST_ASSERT_EQUAL_UINT32(
+        ref_timestamp + TIMESTAMP_MAX_DELTA, interface_stub.interrupt_timestamp
+    );
+    TEST_ASSERT_EQUAL_UINT64(second_event_timestamp, second_event.timestamp);
+    TEST_ASSERT_EQUAL_UINT32((uint32_t) &second_event, second_event.id);
+
+    // remove second event 
+    ticker_remove_event(&ticker_stub, &second_event);
+
+    TEST_ASSERT_EQUAL_PTR(&first_event, queue_stub.head);
+    TEST_ASSERT_EQUAL_PTR(NULL, first_event.next);
+    TEST_ASSERT_EQUAL_UINT32(
+        ref_timestamp + TIMESTAMP_MAX_DELTA, interface_stub.interrupt_timestamp
+    );
+    TEST_ASSERT_EQUAL_UINT64(first_event.timestamp, first_event_timestamp);
+    TEST_ASSERT_EQUAL_UINT32((uint32_t) &first_event, first_event.id);
+
+    // remove first event 
+    ticker_remove_event(&ticker_stub, &first_event);
+
+    TEST_ASSERT_EQUAL_PTR(NULL, queue_stub.head);
+    TEST_ASSERT_EQUAL_PTR(NULL, first_event.next);
+    TEST_ASSERT_EQUAL_UINT32(
+        ref_timestamp + TIMESTAMP_MAX_DELTA, interface_stub.interrupt_timestamp
+    );
+
+    TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call);
+}
+
+/** 
+ * Given an initialized ticker without user registered events and a ticker 
+ * interface timestamp equal or bigger than the one registered by the overflow 
+ * event.
+ * When the interrupt handler is called.
+ * Then:
+ *   - The interrupt timestamp should be updated to the timestamp of the ticker 
+ *     interface plus TIMESTAMP_MAX_DELTA. 
+ *   - The irq handler registered should not be called.
+ */
+static void test_overflow_event_update()
+{
+    static uint32_t handler_call = 0;
+    struct irq_handler_stub_t { 
+        static void event_handler(uint32_t id) { 
+            ++handler_call;
+        }
+    };
+    handler_call = 0;
+
+    ticker_set_handler(&ticker_stub, irq_handler_stub_t::event_handler);
+    interface_stub.set_interrupt_call = 0;
+
+    for (size_t i = 0; i < 8; ++i) {
+        us_timestamp_t previous_timestamp = queue_stub.present_time;
+        timestamp_t interface_timestamp = 
+            previous_timestamp + (TIMESTAMP_MAX_DELTA + i * 100);
+        interface_stub.timestamp = interface_timestamp;
+            
+        ticker_irq_handler(&ticker_stub);
+        TEST_ASSERT_EQUAL(i + 1, interface_stub.clear_interrupt_call);
+
+        TEST_ASSERT_EQUAL(i + 1, interface_stub.set_interrupt_call);
+        TEST_ASSERT_EQUAL_UINT32(
+            interface_timestamp + TIMESTAMP_MAX_DELTA,
+            interface_stub.interrupt_timestamp
+        );
+        TEST_ASSERT_EQUAL(0, handler_call);
+    }
+
+    TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call);
+}  
+
+/** 
+ * Given an initialized ticker without user registered events and a ticker 
+ * interface timestamp less than the one registered to handle overflow.
+ * When the interrupt handler is called.
+ * Then:
+ *   - The interrupt timestamp should be updated to the timestamp of the ticker 
+ *     interface plus TIMESTAMP_MAX_DELTA. 
+ *   - The irq handler registered should not be called.
+ */
+static void test_overflow_event_update_when_spurious_interrupt()
+{
+    static uint32_t handler_call = 0;
+    struct irq_handler_stub_t { 
+        static void event_handler(uint32_t id) { 
+            ++handler_call;
+        }
+    };
+    handler_call = 0;
+
+    ticker_set_handler(&ticker_stub, irq_handler_stub_t::event_handler);
+    interface_stub.set_interrupt_call = 0;
+
+    for (size_t i = 0; i < 8; ++i) {
+        us_timestamp_t previous_timestamp = queue_stub.present_time;
+        timestamp_t interface_timestamp = 
+            previous_timestamp + (TIMESTAMP_MAX_DELTA / (2 + i));
+        interface_stub.timestamp = interface_timestamp;
+            
+        ticker_irq_handler(&ticker_stub);
+
+        TEST_ASSERT_EQUAL(i + 1, interface_stub.clear_interrupt_call);
+        TEST_ASSERT_EQUAL(i + 1, interface_stub.set_interrupt_call);
+        TEST_ASSERT_EQUAL_UINT32(
+            interface_timestamp + TIMESTAMP_MAX_DELTA,
+            interface_stub.interrupt_timestamp
+        );
+        TEST_ASSERT_EQUAL(0, handler_call);
+    }
+
+    TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call);
+}  
+
+/**
+ * Given an initialized ticker with a single ticker event inserted and a ticker 
+ * interface timestamp bigger than the one set for interrupt. 
+ * When ticker_irq_handler is called.
+ * Then: 
+ *   - The IRQ handler should be called with the id of the event at the head of 
+ *     the queue.
+ *   - The event at the head of the queue should be replaced by the next event.
+ *   - The interrupt timestamp in the ticker interface should be set to the 
+ *     value of the interface timestamp + TIMESTAMP_MAX_DELTA  
+ */
+static void test_irq_handler_single_event()
+{
+    static const timestamp_t event_timestamp = 0xAAAAAAAA;
+    static const timestamp_t interface_timestamp_after_irq = event_timestamp + 100;
+
+    uint32_t handler_call = 0;
+    struct irq_handler_stub_t { 
+        static void event_handler(uint32_t id) { 
+            ++ (*((uint32_t*) id));
+            interface_stub.timestamp = interface_timestamp_after_irq;
+        }
+    };
+
+    ticker_set_handler(&ticker_stub, irq_handler_stub_t::event_handler);
+    interface_stub.set_interrupt_call = 0;
+
+    ticker_event_t e; 
+    ticker_insert_event(&ticker_stub, &e, event_timestamp, (uint32_t) &handler_call);
+
+    interface_stub.timestamp = event_timestamp;
+    interface_stub.set_interrupt_call = 0;
+
+    ticker_irq_handler(&ticker_stub);
+
+    TEST_ASSERT_EQUAL(1, interface_stub.clear_interrupt_call);
+    TEST_ASSERT_EQUAL(1, interface_stub.set_interrupt_call);
+    TEST_ASSERT_EQUAL(1, handler_call);
+    TEST_ASSERT_EQUAL_UINT32(
+        interface_timestamp_after_irq + TIMESTAMP_MAX_DELTA,
+        interface_stub.interrupt_timestamp
+    );
+
+    TEST_ASSERT_NULL(queue_stub.head);
+
+    TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call);
+}
+
+/**
+ * Given an initialized ticker with at least a ticker event inserted and a ticker 
+ * interface timestamp less than the one set for interrupt. 
+ * When ticker_irq_handler is called.
+ * Then: 
+ *   - The IRQ handler should not be called.
+ *   - The event at the head of the queue should remains the same.
+ *   - The interrupt timestamp in the ticker interface should be set to the 
+ *     value of the event timestamp  
+ */
+static void test_irq_handler_single_event_spurious()
+{
+    struct irq_handler_stub_t { 
+        static void event_handler(uint32_t id) { 
+            TEST_FAIL();
+        }
+    };
+
+    ticker_set_handler(&ticker_stub, irq_handler_stub_t::event_handler);
+    interface_stub.set_interrupt_call = 0;
+
+    const us_timestamp_t timestamps [] = {
+        UINT32_MAX, 
+        TIMESTAMP_MAX_DELTA + 1, 
+        TIMESTAMP_MAX_DELTA,
+        TIMESTAMP_MAX_DELTA - 1
+    };
+
+    ticker_event_t events[MBED_ARRAY_SIZE(timestamps)] = { 0 };
+
+    for (size_t i = 0; i < MBED_ARRAY_SIZE(events); ++i) { 
+        ticker_insert_event_us(
+            &ticker_stub, 
+            &events[i], timestamps[i], timestamps[i]
+        );
+        interface_stub.set_interrupt_call = 0;
+        interface_stub.clear_interrupt_call = 0;
+
+        ticker_irq_handler(&ticker_stub);
+
+        TEST_ASSERT_EQUAL(1, interface_stub.clear_interrupt_call);
+        TEST_ASSERT_EQUAL(1, interface_stub.set_interrupt_call);
+        TEST_ASSERT_EQUAL_UINT32(
+            std::min(timestamps[i], TIMESTAMP_MAX_DELTA),
+            interface_stub.interrupt_timestamp
+        );
+    }
+
+    TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call);
+}
+
+/**
+ * Given an initialized ticker with multiple ticker event inserted, its 
+ * interface timestamp at greater than the timestamp of the next schedule event 
+ * and all event execution time taking at least the time befor ethe next event.
+ * When ticker_irq_handler is called.
+ * Then: 
+ *   - The IRQ handler should have been called for every event.
+ *   - The head of the queue should be set to NULL.
+ *   - The interrupt timestamp in the ticker interface should be scheduled in
+ *     TIMESTAMP_MAX_DELTAs
+ */
+static void test_irq_handler_multiple_event_multiple_dequeue()
+{
+    const us_timestamp_t timestamps [] = {
+        10, 
+        10 + TIMESTAMP_MAX_DELTA - 1,
+        10 + TIMESTAMP_MAX_DELTA,
+        10 + TIMESTAMP_MAX_DELTA + 1, 
+        UINT32_MAX
+    };
+
+    static size_t handler_called = 0;
+    struct irq_handler_stub_t { 
+        static void event_handler(uint32_t id) { 
+            ++handler_called;
+            ticker_event_t* e = (ticker_event_t*) id;
+            if (e->next) { 
+                interface_stub.timestamp = e->next->timestamp;
+            }
+        }
+    };
+    handler_called = 0;
+
+    ticker_set_handler(&ticker_stub, irq_handler_stub_t::event_handler);
+    interface_stub.set_interrupt_call = 0;
+
+    ticker_event_t events[MBED_ARRAY_SIZE(timestamps)] = { 0 };
+
+    for (size_t i = 0; i < MBED_ARRAY_SIZE(events); ++i) { 
+        ticker_insert_event_us(
+            &ticker_stub, 
+            &events[i], timestamps[i], (uint32_t) &events[i]
+        );
+    }
+
+    interface_stub.set_interrupt_call = 0;
+    interface_stub.clear_interrupt_call = 0;
+    interface_stub.timestamp = timestamps[0];
+    
+    ticker_irq_handler(&ticker_stub);
+
+    TEST_ASSERT_EQUAL(1, interface_stub.clear_interrupt_call);
+    TEST_ASSERT_EQUAL(1, interface_stub.set_interrupt_call);
+    TEST_ASSERT_EQUAL_UINT32(MBED_ARRAY_SIZE(timestamps), handler_called);
+    TEST_ASSERT_EQUAL_UINT32(
+        timestamps[MBED_ARRAY_SIZE(timestamps) - 1] + TIMESTAMP_MAX_DELTA,
+        interface_stub.interrupt_timestamp
+    );
+    TEST_ASSERT_NULL(queue_stub.head);
+
+    TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call);
+}
+
+/**
+ * Given an initialized ticker with two ticker event inserted scheduled from more 
+ * than TIMESTAMP_MAX_DELTA from one another. The interface 
+ * timestamp is equal to the timestamp of the first event. 
+ * When ticker_irq_handler is called.
+ * Then: 
+ *   - The IRQ handler should have been called for the first event.
+ *   - The head of the queue should be set to the event after the first event.
+ *   - The interrupt timestamp in the ticker interface should be scheduled in
+ *     TIMESTAMP_MAX_DELTA.
+ */
+static void test_irq_handler_multiple_event_single_dequeue_overflow()
+{
+    const us_timestamp_t timestamps [] = {
+        10, 
+        10 + TIMESTAMP_MAX_DELTA + 1
+    };
+
+    size_t handler_called = 0;
+    struct irq_handler_stub_t { 
+        static void event_handler(uint32_t id) { 
+            ++ (*((size_t*) id));
+        }
+    };
+
+    ticker_set_handler(&ticker_stub, irq_handler_stub_t::event_handler);
+    interface_stub.set_interrupt_call = 0;
+
+    ticker_event_t events[MBED_ARRAY_SIZE(timestamps)] = { 0 };
+
+    for (size_t i = 0; i < MBED_ARRAY_SIZE(events); ++i) { 
+        ticker_insert_event_us(
+            &ticker_stub, 
+            &events[i], timestamps[i], (uint32_t) &handler_called
+        );
+    }
+
+    interface_stub.set_interrupt_call = 0;
+    interface_stub.clear_interrupt_call = 0;
+    interface_stub.timestamp = timestamps[0];
+    
+    ticker_irq_handler(&ticker_stub);
+
+    TEST_ASSERT_EQUAL(1, interface_stub.clear_interrupt_call);
+    TEST_ASSERT_EQUAL(1, interface_stub.set_interrupt_call);
+    TEST_ASSERT_EQUAL_UINT32(1, handler_called);
+    TEST_ASSERT_EQUAL_UINT32(
+        timestamps[0] + TIMESTAMP_MAX_DELTA,
+        interface_stub.interrupt_timestamp
+    );
+    TEST_ASSERT_EQUAL_PTR(&events[1], queue_stub.head);
+
+    TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call);
+}
+
+/**
+ * Given an initialized ticker with two ticker event inserted scheduled from less 
+ * than TIMESTAMP_MAX_DELTA from one another. The interface 
+ * timestamp is equal to the timestamp of the first event. 
+ * When ticker_irq_handler is called.
+ * Then: 
+ *   - The IRQ handler should have been called for the first event.
+ *   - The head of the queue should be set to second event.
+ *   - The interrupt timestamp in the ticker interface should be equal to the 
+ *     timestamp of the second event.
+ */
+static void test_irq_handler_multiple_event_single_dequeue()
+{
+    const us_timestamp_t timestamps [] = {
+        10, 
+        10 + TIMESTAMP_MAX_DELTA - 1
+    };
+
+    size_t handler_called = 0;
+    struct irq_handler_stub_t { 
+        static void event_handler(uint32_t id) { 
+            ++ (*((size_t*) id));
+        }
+    };
+
+    ticker_set_handler(&ticker_stub, irq_handler_stub_t::event_handler);
+    interface_stub.set_interrupt_call = 0;
+
+    ticker_event_t events[MBED_ARRAY_SIZE(timestamps)] = { 0 };
+
+    for (size_t i = 0; i < MBED_ARRAY_SIZE(events); ++i) { 
+        ticker_insert_event_us(
+            &ticker_stub, 
+            &events[i], timestamps[i], (uint32_t) &handler_called
+        );
+    }
+
+    interface_stub.set_interrupt_call = 0;
+    interface_stub.clear_interrupt_call = 0;
+    interface_stub.timestamp = timestamps[0];
+    
+    ticker_irq_handler(&ticker_stub);
+
+    TEST_ASSERT_EQUAL(1, interface_stub.clear_interrupt_call);
+    TEST_ASSERT_EQUAL(1, interface_stub.set_interrupt_call);
+    TEST_ASSERT_EQUAL_UINT32(1, handler_called);
+    TEST_ASSERT_EQUAL_UINT32(
+        timestamps[1],
+        interface_stub.interrupt_timestamp
+    );
+    TEST_ASSERT_EQUAL_PTR(&events[1], queue_stub.head);
+
+    TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call);
+}
+
+/**
+ * Given an initialized ticker with multiple ticker event inserted and the 
+ * interface timestamp is equal to the timestamp of the first event. The first
+ * event to execute will insert an events in the ticker which have to be executed 
+ * immediately.
+ * When ticker_irq_handler is called.
+ * Then: 
+ *   - The IRQ handler should have been called for the first event and the event 
+ *     inserted during irq.
+ *   - The head of the queue should be set correctly.
+ *   - The interrupt timestamp in the ticker interface should be equal to 
+ *     timestamp of the head event.
+ */
+static void test_irq_handler_insert_immediate_in_irq()
+{
+    static const us_timestamp_t timestamps [] = {
+        10, 
+        10 + TIMESTAMP_MAX_DELTA - 1
+    };
+
+    static const us_timestamp_t expected_timestamp = 
+        ((timestamps[1] - timestamps[0]) / 2) + timestamps[0];
+
+    struct ctrl_block_t { 
+        bool irq_event_called;
+        ticker_event_t immediate_event; 
+        size_t handler_called;
+    };
+
+    ctrl_block_t ctrl_block = { 0 };
+
+    struct irq_handler_stub_t { 
+        static void event_handler(uint32_t id) { 
+            ctrl_block_t*  ctrl_block = (ctrl_block_t*) id;
+
+            if (ctrl_block->handler_called == 0) {
+                ticker_insert_event(
+                    &ticker_stub, 
+                    &ctrl_block->immediate_event, expected_timestamp, id
+                );
+                interface_stub.timestamp = expected_timestamp;
+            } else if (ctrl_block->handler_called > 1) { 
+                TEST_FAIL();
+            }
+            ++ctrl_block->handler_called;
+        }
+    };
+
+    ticker_set_handler(&ticker_stub, irq_handler_stub_t::event_handler);
+    interface_stub.set_interrupt_call = 0;
+
+    ticker_event_t events[MBED_ARRAY_SIZE(timestamps)] = { 0 };
+
+    for (size_t i = 0; i < MBED_ARRAY_SIZE(events); ++i) { 
+        ticker_insert_event_us(
+            &ticker_stub, 
+            &events[i], timestamps[i], (uint32_t) &ctrl_block
+        );
+    }
+
+    interface_stub.set_interrupt_call = 0;
+    interface_stub.clear_interrupt_call = 0;
+    interface_stub.timestamp = timestamps[0];
+    
+    ticker_irq_handler(&ticker_stub);
+
+    TEST_ASSERT_EQUAL(1, interface_stub.clear_interrupt_call);
+    TEST_ASSERT_EQUAL_UINT32(2, ctrl_block.handler_called);
+    TEST_ASSERT_EQUAL_UINT32(
+        timestamps[1],
+        interface_stub.interrupt_timestamp
+    );
+    TEST_ASSERT_EQUAL_PTR(&events[1], queue_stub.head);
+
+    TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call);
+}
+
+/**
+ * Given an initialized ticker with multiple ticker event inserted and the 
+ * interface timestamp is equal to the timestamp of the first event. The first
+ * event to execute will insert an events in the ticker which does not have to 
+ * be executed  immediately.
+ * When ticker_irq_handler is called.
+ * Then: 
+ *   - The IRQ handler should have been called for the first event.
+ *   - The head of the queue should be set to the event inserted in IRQ.
+ *   - The interrupt timestamp in the ticker interface should be equal to 
+ *     timestamp of the head event.
+ */
+static void test_irq_handler_insert_non_immediate_in_irq()
+{
+    static const us_timestamp_t timestamps [] = {
+        10, 
+        10 + TIMESTAMP_MAX_DELTA - 1
+    };
+
+    static const us_timestamp_t expected_timestamp = 
+        ((timestamps[1] - timestamps[0]) / 2) + timestamps[0];
+
+    struct ctrl_block_t { 
+        bool irq_event_called;
+        ticker_event_t non_immediate_event; 
+        size_t handler_called;
+    };
+
+    ctrl_block_t ctrl_block = { 0 };
+
+    struct irq_handler_stub_t { 
+        static void event_handler(uint32_t id) { 
+            ctrl_block_t*  ctrl_block = (ctrl_block_t*) id;
+
+            if (ctrl_block->handler_called == 0) {
+                ticker_insert_event(
+                    &ticker_stub, 
+                    &ctrl_block->non_immediate_event, expected_timestamp, id
+                );
+            } else { 
+                TEST_FAIL();
+            }
+            ++ctrl_block->handler_called;
+        }
+    };
+
+
+    ticker_set_handler(&ticker_stub, irq_handler_stub_t::event_handler);
+    interface_stub.set_interrupt_call = 0;
+
+    ticker_event_t events[MBED_ARRAY_SIZE(timestamps)] = { 0 };
+
+    for (size_t i = 0; i < MBED_ARRAY_SIZE(events); ++i) { 
+        ticker_insert_event_us(
+            &ticker_stub, 
+            &events[i], timestamps[i], (uint32_t) &ctrl_block
+        );
+    }
+
+    interface_stub.set_interrupt_call = 0;
+    interface_stub.clear_interrupt_call = 0;
+    interface_stub.timestamp = timestamps[0];
+    
+    ticker_irq_handler(&ticker_stub);
+
+    TEST_ASSERT_EQUAL(1, interface_stub.clear_interrupt_call);
+    TEST_ASSERT_EQUAL_UINT32(1, ctrl_block.handler_called);
+    TEST_ASSERT_EQUAL_UINT32(
+        expected_timestamp,
+        interface_stub.interrupt_timestamp
+    );
+    TEST_ASSERT_EQUAL_PTR(&ctrl_block.non_immediate_event, queue_stub.head);
+    TEST_ASSERT_EQUAL_PTR(&events[1], queue_stub.head->next);
+
+    TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call);
+}
+
+static uint32_t ticker_interface_stub_read_interrupt_time()
+{
+    ++interface_stub.read_call;
+    // only if set interrupt call, to test the condition afterwards
+    if (interface_stub.set_interrupt_call) {
+        return interface_stub.interrupt_timestamp;
+    } else {
+        return interface_stub.timestamp;
+    }
+} 
+
+/**
+ * Test to insert an event that is already in the past, the fire_interrupt should
+ * be invoked, instead of set_interrupt
+ */
+static void test_set_interrupt_past_time()
+{
+    ticker_set_handler(&ticker_stub, NULL);
+
+    interface_stub.set_interrupt_call = 0;
+    interface_stub.fire_interrupt_call = 0;
+    interface_stub.timestamp = 0xFF;
+
+
+    // This tests fire now functinality when next_event_timestamp <= present
+    ticker_event_t event = { 0 };
+    const timestamp_t event_timestamp = interface_stub.timestamp;
+    const uint32_t id_last_event = 0xDEADDEAF;
+
+    ticker_insert_event(&ticker_stub, &event, event_timestamp, id_last_event);
+    TEST_ASSERT_EQUAL(0, interface_stub.set_interrupt_call);
+    TEST_ASSERT_EQUAL(1, interface_stub.fire_interrupt_call);
+}
+/**
+ * Test to insert an event that is being delayed, set_interrupt is set
+ * but then event is already in the past, thus fire_interrupt should be invoked right-away
+ */
+static void test_set_interrupt_past_time_with_delay()
+{
+    ticker_set_handler(&ticker_stub, NULL);
+
+    interface_stub.set_interrupt_call = 0;
+    interface_stub.fire_interrupt_call = 0;
+    interface_stub.timestamp = 0xFF;
+
+    // This tests fire now functionality when present time >= new_match_time
+    interface_stub.interface.read = ticker_interface_stub_read_interrupt_time;
+    ticker_event_t event = { 0 };
+    const timestamp_t event_timestamp = interface_stub.timestamp + 5;
+    const uint32_t id_last_event = 0xDEADDEAF;
+
+    ticker_insert_event(&ticker_stub, &event, event_timestamp, id_last_event);
+    TEST_ASSERT_EQUAL(1, interface_stub.set_interrupt_call);
+    TEST_ASSERT_EQUAL(1, interface_stub.fire_interrupt_call);
+}
+
+/**
+ * Convert ticks at a given frequency to time in microseconds
+ *
+ * Assert if there is a 64-bit overflow
+ */
+static uint64_t convert_to_us(uint64_t ticks, uint32_t frequency)
+{
+    uint64_t scaled_ticks = ticks * 1000000;
+    // Assert that there was not an overflow
+    TEST_ASSERT_EQUAL(ticks, scaled_ticks / 1000000);
+    return scaled_ticks / frequency;
+}
+
+/**
+ * Given an uninitialized ticker instance and an interface of a
+ * certain frequency and bit width.
+ * Then the time returned the ticker should match the cumulative time.
+ */
+void test_frequencies_and_masks(uint32_t frequency, uint32_t bits)
+{
+    const uint32_t bitmask = ((uint64_t)1 << bits) - 1;
+
+    ticker_set_handler(&ticker_stub, NULL);
+    uint64_t ticks = 0;
+
+    // Single tick
+    ticks += 1;
+    interface_stub.timestamp = ticks & bitmask;
+    TEST_ASSERT_EQUAL_UINT32(convert_to_us(ticks, frequency), ticker_read(&ticker_stub));
+    TEST_ASSERT_EQUAL_UINT64(convert_to_us(ticks, frequency), ticker_read_us(&ticker_stub));
+
+    // Run until the loop before 64-bit overflow (worst case with frequency=1hz, bits=32)
+    for (unsigned int k = 0; k < 4294; k++) {
+
+        // Largest value possible tick
+        ticks += ((uint64_t)1 << bits) - 1;
+        interface_stub.timestamp = ticks & bitmask;
+        TEST_ASSERT_EQUAL_UINT32(convert_to_us(ticks, frequency), ticker_read(&ticker_stub));
+        TEST_ASSERT_EQUAL_UINT64(convert_to_us(ticks, frequency), ticker_read_us(&ticker_stub));
+    }
+}
+
+/**
+ * Given an uninitialized ticker_data instance.
+ * When the ticker is initialized
+ * Then:
+ *   - The internal ticker timestamp should be zero
+ *   - interrupt should be scheduled in current (timestamp +
+ *          TIMESTAMP_MAX_DELTA_BITS(bitwidth)) % modval
+ *   - The queue should not contains any event
+ */
+static void test_ticker_max_value()
+{
+    for (int bitwidth = 8; bitwidth <= 32; bitwidth++) {
+        const uint64_t modval = 1ULL << bitwidth;
+
+        // setup of the stub
+        reset_ticker_stub();
+        interface_info_stub.bits = bitwidth;
+        interface_stub.timestamp = 0xBA;
+
+        ticker_set_handler(&ticker_stub, NULL);
+
+        TEST_ASSERT_EQUAL_UINT64(0, queue_stub.present_time);
+        TEST_ASSERT_EQUAL(1, interface_stub.set_interrupt_call);
+        TEST_ASSERT_EQUAL_UINT32(
+            (interface_stub.timestamp + TIMESTAMP_MAX_DELTA_BITS(bitwidth)) % modval,
+            interface_stub.interrupt_timestamp
+        );
+        TEST_ASSERT_EQUAL_PTR(NULL, queue_stub.head);
+        TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call);
+    }
+}
+
+/**
+ * Check that _ticker_match_interval_passed correctly detects matches
+ *
+ * Brute force test that _ticker_match_interval_passed returns the correct match value
+ * for all cominations of values within a small range.
+ */
+static void test_match_interval_passed()
+{
+
+    for (int modval = 1; modval <= 5; modval++) {
+        for (int prev = 0; prev < modval; prev++) {
+            for (int cur = 0; cur < modval; cur++) {
+                for (int match = 0; match < modval; match++) {
+                    uint32_t delta = (cur - prev) % modval;
+                    uint32_t delta_to_match = (match - prev) % modval;
+                    bool match_expected = false;
+                    if (delta_to_match) {
+                        match_expected = delta >= delta_to_match;
+                    }
+
+                    // Sanity checks
+                    if (prev == cur) {
+                        // No time has passed
+                        TEST_ASSERT_EQUAL(false, match_expected);
+                    } else if (match == prev) {
+                        // Match can't occur without an overflow occurring
+                        TEST_ASSERT_EQUAL(false, match_expected);
+                    } else if (cur == match) {
+                        // All other cases where cur == match a match should be expected
+                        TEST_ASSERT_EQUAL(true, match_expected);
+                    }
+
+                    // Actual test
+                    TEST_ASSERT_EQUAL(match_expected, _ticker_match_interval_passed(prev, cur, match));
+                }
+            }
+        }
+    }
+}
+
+typedef struct  {
+    timestamp_t prev;
+    timestamp_t cur;
+    timestamp_t match;
+    bool result;
+} match_interval_entry_t;
+
+/**
+ * Check that _ticker_match_interval_passed correctly detects matches
+ *
+ * Use a table of pre-computed values to check that _ticker_match_interval_passed
+ * returns the correct match value.
+ */
+static void test_match_interval_passed_table()
+{
+    static const match_interval_entry_t test_values[] = {
+          /* prev,       cur,        match,      result */
+            {0x00000000, 0x00000000, 0x00000000, false},
+            {0x00000000, 0x00000000, 0xffffffff, false},
+            {0x00000000, 0x00000000, 0x00000001, false},
+            {0x00000000, 0xffffffff, 0x00000000, false},
+            {0x00000000, 0x00000001, 0x00000000, false},
+            {0xffffffff, 0x00000000, 0x00000000, true},
+            {0x00000001, 0x00000000, 0x00000000, true},
+            {0x00005555, 0x00005555, 0x00005555, false},
+            {0x00005555, 0x00005555, 0x00005554, false},
+            {0x00005555, 0x00005555, 0x00005556, false},
+            {0x00005555, 0x00005554, 0x00005555, false},
+            {0x00005555, 0x00005556, 0x00005555, false},
+            {0x00005554, 0x00005555, 0x00005555, true},
+            {0x00005556, 0x00005555, 0x00005555, true},
+            {0xffffffff, 0xffffffff, 0xffffffff, false},
+            {0xffffffff, 0xffffffff, 0xfffffffe, false},
+            {0xffffffff, 0xffffffff, 0x00000000, false},
+            {0xffffffff, 0xfffffffe, 0xffffffff, false},
+            {0xffffffff, 0x00000000, 0xffffffff, false},
+            {0xfffffffe, 0xffffffff, 0xffffffff, true},
+            {0x00000000, 0xffffffff, 0xffffffff, true},
+    };
+    for (int i = 0; i < MBED_ARRAY_SIZE(test_values); i++) {
+        const uint32_t prev = test_values[i].prev;
+        const uint32_t cur = test_values[i].cur;
+        const uint32_t match = test_values[i].match;
+        const uint32_t result = test_values[i].result;
+        TEST_ASSERT_EQUAL(result, _ticker_match_interval_passed(prev, cur, match));
+    }
+}
+
+static const case_t cases[] = {
+    MAKE_TEST_CASE("ticker initialization", test_ticker_initialization),
+    MAKE_TEST_CASE(
+        "ticker multiple initialization",  test_ticker_re_initialization
+    ),
+    MAKE_TEST_CASE("ticker read", test_ticker_read),
+    MAKE_TEST_CASE("ticker read overflow", test_ticker_read_overflow),
+    MAKE_TEST_CASE(
+        "legacy insert event outside overflow range", 
+        test_legacy_insert_event_outside_overflow_range
+    ),
+    MAKE_TEST_CASE(
+        "legacy insert event in overflow range", 
+        test_legacy_insert_event_in_overflow_range
+    ),
+    MAKE_TEST_CASE(
+        "legacy insert event overflow", test_legacy_insert_event_overflow
+    ),
+    MAKE_TEST_CASE(
+        "legacy insert event head", test_legacy_insert_event_head
+    ),
+    MAKE_TEST_CASE(
+        "legacy insert event tail", test_legacy_insert_event_tail
+    ),
+    MAKE_TEST_CASE(
+        "legacy insert event multiple overflow", 
+        test_legacy_insert_event_multiple_overflow
+    ),
+    MAKE_TEST_CASE(
+        "test_legacy_insert_event_multiple_random", 
+        test_legacy_insert_event_multiple_random
+    ),
+    MAKE_TEST_CASE(
+        "test_insert_event_us_outside_overflow_range", 
+        test_insert_event_us_outside_overflow_range
+    ),
+    MAKE_TEST_CASE(
+        "test_insert_event_us_in_overflow_range", 
+        test_insert_event_us_in_overflow_range
+    ),
+    MAKE_TEST_CASE(
+        "test_insert_event_us_underflow", test_insert_event_us_underflow
+    ),
+    MAKE_TEST_CASE("test_insert_event_us_head", test_insert_event_us_head),
+    MAKE_TEST_CASE("test_insert_event_us_tail", test_insert_event_us_tail),
+    MAKE_TEST_CASE(
+        "test_insert_event_us_multiple_random", 
+        test_insert_event_us_multiple_random
+    ),
+    MAKE_TEST_CASE("test_remove_event_tail", test_remove_event_tail),
+    MAKE_TEST_CASE("test_remove_event_head", test_remove_event_head),
+    MAKE_TEST_CASE("test_remove_event_invalid", test_remove_event_invalid),
+    MAKE_TEST_CASE("test_remove_random", test_remove_random),
+    MAKE_TEST_CASE("update overflow guard", test_overflow_event_update),
+    MAKE_TEST_CASE(
+        "update overflow guard in case of spurious interrupt", 
+        test_overflow_event_update_when_spurious_interrupt
+    ),
+    MAKE_TEST_CASE(
+        "test_irq_handler_single_event", test_irq_handler_single_event
+    ),
+    MAKE_TEST_CASE(
+        "test_irq_handler_single_event_spurious", 
+        test_irq_handler_single_event_spurious
+    ),
+    MAKE_TEST_CASE(
+        "test_irq_handler_multiple_event_multiple_dequeue", 
+        test_irq_handler_multiple_event_multiple_dequeue
+    ),
+    MAKE_TEST_CASE(
+        "test_irq_handler_multiple_event_single_dequeue_overflow", 
+        test_irq_handler_multiple_event_single_dequeue_overflow
+    ),
+    MAKE_TEST_CASE(
+        "test_irq_handler_multiple_event_single_dequeue", 
+        test_irq_handler_multiple_event_single_dequeue
+    ),
+    MAKE_TEST_CASE(
+        "test_irq_handler_insert_immediate_in_irq", 
+        test_irq_handler_insert_immediate_in_irq
+    ),
+    MAKE_TEST_CASE(
+        "test_irq_handler_insert_non_immediate_in_irq", 
+        test_irq_handler_insert_non_immediate_in_irq
+    ),
+    MAKE_TEST_CASE(
+        "test_set_interrupt_past_time", 
+        test_set_interrupt_past_time
+    ),
+    MAKE_TEST_CASE(
+        "test_set_interrupt_past_time_with_delay", 
+        test_set_interrupt_past_time_with_delay
+    ),
+    MAKE_TEST_CASE(
+        "test_frequencies_and_masks",
+        test_over_frequency_and_width<test_frequencies_and_masks>
+    ),
+    MAKE_TEST_CASE(
+        "test_ticker_max_value",
+        test_ticker_max_value
+    ),
+    MAKE_TEST_CASE(
+        "test_match_interval_passed",
+        test_match_interval_passed
+    ),
+    MAKE_TEST_CASE(
+        "test_match_interval_passed_table",
+        test_match_interval_passed_table
+    )
+};
+
+static utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
+{
+    GREENTEA_SETUP(60, "default_auto");
+    return verbose_test_setup_handler(number_of_cases);
+}
+
+int main()
+{
+    Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);
+    return !Harness::run(specification);
+}