Skip to content

events: Introduce API to query how much time is left for delayed event #6901

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 1 commit into from
May 21, 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
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