Skip to content

Commit

Permalink
Introduce API to query how much time is left for delayed event
Browse files Browse the repository at this point in the history
If user has initiated a delayed event (either with call_in or call_every),
user might need to know how much time is left until the event is
due to be dispatched.

Added time_left() function can be used to get the remaining time.
  • Loading branch information
Kimmo Vaisanen committed May 18, 2018
1 parent 80e1093 commit 990da08
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 0 deletions.
42 changes: 42 additions & 0 deletions TESTS/events/queue/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,46 @@ void event_inference_test() {
TEST_ASSERT_EQUAL(counter, 60);
}

int timeleft_events[2];

void check_time_left(EventQueue* queue, int index, int expected) {
const int event_id = timeleft_events[index];
TEST_ASSERT_INT_WITHIN(2, expected, queue->time_left(event_id));
touched = true;
}

void time_left(EventQueue* queue, int index) {
const int event_id = timeleft_events[index];
TEST_ASSERT_EQUAL(0, queue->time_left(event_id));
}

void time_left_test() {
EventQueue queue(TEST_EQUEUE_SIZE);

// Enque check events
TEST_ASSERT(queue.call_in(50, check_time_left, &queue, 0, 100-50));
TEST_ASSERT(queue.call_in(200, check_time_left, &queue, 1, 200-200));

// Enque events to be checked
timeleft_events[0] = queue.call_in(100, time_left, &queue, 0);
timeleft_events[1] = queue.call_in(200, time_left, &queue, 1);
TEST_ASSERT(timeleft_events[0]);
TEST_ASSERT(timeleft_events[1]);

queue.dispatch(300);

// Ensure check was called
TEST_ASSERT(touched);
touched = false;

int id = queue.call(func0);
TEST_ASSERT(id);
TEST_ASSERT_EQUAL(0, queue.time_left(id));
queue.dispatch(10);

// Test invalid event id
TEST_ASSERT_EQUAL(-1, queue.time_left(0));
}

// Test setup
utest::v1::status_t test_setup(const size_t number_of_cases) {
Expand All @@ -274,6 +314,8 @@ const Case cases[] = {
Case("Testing the event class", event_class_test),
Case("Testing the event class helpers", event_class_helper_test),
Case("Testing the event inference", event_inference_test),

Case("Testing time_left", time_left_test),
};

Specification specification(test_setup, cases);
Expand Down
4 changes: 4 additions & 0 deletions events/EventQueue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ void EventQueue::cancel(int id) {
return equeue_cancel(&_equeue, id);
}

int EventQueue::time_left(int id) {
return equeue_timeleft(&_equeue, id);
}

void EventQueue::background(Callback<void(int)> update) {
_update = update;

Expand Down
23 changes: 23 additions & 0 deletions events/EventQueue.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ class EventQueue : private mbed::NonCopyable<EventQueue> {
* one of the call functions. It is safe to call cancel after an event
* has already been dispatched.
*
* id must be valid i.e. event must have not finished executing.
*
* The cancel function is irq safe.
*
* If called while the event queue's dispatch loop is active, the cancel
Expand All @@ -124,6 +126,25 @@ class EventQueue : private mbed::NonCopyable<EventQueue> {
*/
void cancel(int id);

/** Query how much time is left for delayed event
*
* If the event is delayed, this function can be used to query how much time
* is left until the event is due to be dispatched.
*
* id must be valid i.e. event must have not finished executing.
*
* This function is irq safe.
*
* @param id Unique id of the event
*
* @return Remaining time in milliseconds or
* 0 if event is already due to be dispatched or
* is currently executing.
* Undefined if id is invalid.
*
*/
int time_left(int id);

/** Background an event queue onto a single-shot timer-interrupt
*
* When updated, the event queue will call the provided update function
Expand Down Expand Up @@ -171,6 +192,8 @@ class EventQueue : private mbed::NonCopyable<EventQueue> {
* @return A unique id that represents the posted event and can
* be passed to cancel, or an id of 0 if there is not
* enough memory to allocate the event.
* Returned id will remain valid until event has finished
* executing.
*/
template <typename F>
int call(F f) {
Expand Down
19 changes: 19 additions & 0 deletions events/equeue/equeue.c
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,25 @@ void equeue_cancel(equeue_t *q, int id) {
}
}

int equeue_timeleft(equeue_t *q, int id) {
int ret = -1;

if (!id) {
return -1;
}

// decode event from unique id and check that the local id matches
struct equeue_event *e = (struct equeue_event *)
&q->buffer[id & ((1 << q->npw2)-1)];

equeue_mutex_lock(&q->queuelock);
if (e->id == id >> q->npw2) {
ret = equeue_clampdiff(e->target, equeue_tick());
}
equeue_mutex_unlock(&q->queuelock);
return ret;
}

void equeue_break(equeue_t *q) {
equeue_mutex_lock(&q->queuelock);
q->break_requested = true;
Expand Down
9 changes: 9 additions & 0 deletions events/equeue/equeue.h
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,15 @@ int equeue_post(equeue_t *queue, void (*cb)(void *), void *event);
// the event may have already begun executing.
void equeue_cancel(equeue_t *queue, int id);

// Query how much time is left for delayed event
//
// If event is delayed, this function can be used to query how much time
// is left until the event is due to be dispatched.
//
// This function is irq safe.
//
int equeue_timeleft(equeue_t *q, int id);

// Background an event queue onto a single-shot timer
//
// The provided update function will be called to indicate when the queue
Expand Down

0 comments on commit 990da08

Please sign in to comment.