mirror of https://github.com/ARMmbed/mbed-os.git
[HAL] Add support of 64 bits timestamp in ticker API implementation.
parent
b1f3aa76bb
commit
1057720114
|
|
@ -13,50 +13,167 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
#include "hal/ticker_api.h"
|
||||
#include "platform/mbed_critical.h"
|
||||
|
||||
void ticker_set_handler(const ticker_data_t *const data, ticker_event_handler handler) {
|
||||
data->interface->init();
|
||||
#define MBED_MIN(x,y) (((x)<(y))?(x):(y))
|
||||
|
||||
data->queue->event_handler = handler;
|
||||
static void update_interrupt(const ticker_data_t *const ticker);
|
||||
static void update_current_timestamp(const ticker_data_t *const ticker);
|
||||
|
||||
/*
|
||||
* Initialize a ticker instance.
|
||||
*/
|
||||
static void initialize(const ticker_data_t *ticker) {
|
||||
// return if the queue has already been initialized, in that case the
|
||||
// interface used by the queue is already initialized.
|
||||
if (ticker->queue->initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
ticker->interface->init();
|
||||
|
||||
ticker->queue->event_handler = NULL;
|
||||
ticker->queue->head = NULL;
|
||||
ticker->queue->timestamp = 0;
|
||||
ticker->queue->initialized = true;
|
||||
|
||||
update_current_timestamp(ticker);
|
||||
update_interrupt(ticker);
|
||||
}
|
||||
|
||||
void ticker_irq_handler(const ticker_data_t *const data) {
|
||||
data->interface->clear_interrupt();
|
||||
/**
|
||||
* Set the event handler function of a ticker instance.
|
||||
*/
|
||||
static void set_handler(const ticker_data_t *const ticker, ticker_event_handler handler) {
|
||||
ticker->queue->event_handler = handler;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert a low res timestamp to a high res timestamp. An high resolution
|
||||
* timestamp is used as the reference point to convert the low res timestamp
|
||||
* into an high res one.
|
||||
*
|
||||
* It is important to note that the result will **never** be in the past. If the
|
||||
* value of the low res timetamp is less than the low res part of the reference
|
||||
* timestamp then an overflow is
|
||||
*
|
||||
* @param ref: The timestamp of reference.
|
||||
* @param relative_timestamp: The timestamp to convert.
|
||||
*/
|
||||
static us_timestamp_t convert_relative_timestamp(us_timestamp_t ref, timestamp_t relative_timestamp) {
|
||||
bool overflow = relative_timestamp < ((timestamp_t) ref) ? true : false;
|
||||
|
||||
us_timestamp_t result = (ref & ~((us_timestamp_t)UINT32_MAX)) | relative_timestamp;
|
||||
if (overflow) {
|
||||
result += (1ULL<<32);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* update the current timestamp value of a ticker.
|
||||
*/
|
||||
static void update_current_timestamp(const ticker_data_t *const ticker) {
|
||||
ticker->queue->timestamp = convert_relative_timestamp(
|
||||
ticker->queue->timestamp,
|
||||
ticker->interface->read()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* update the interrupt with the appropriate timestamp.
|
||||
* if there is no interrupt scheduled or the next event to execute is in more
|
||||
* than MBED_TICKER_INTERRUPT_TIMESTAMP_MAX_DELTA us from now then the
|
||||
* interrupt will be set to MBED_TICKER_INTERRUPT_TIMESTAMP_MAX_DELTA us from now.
|
||||
* Otherwise the interrupt will be set to head->timestamp - queue->timestamp us.
|
||||
*/
|
||||
static void update_interrupt(const ticker_data_t *const ticker) {
|
||||
update_current_timestamp(ticker);
|
||||
uint32_t diff = MBED_TICKER_INTERRUPT_TIMESTAMP_MAX_DELTA;
|
||||
|
||||
if (ticker->queue->head) {
|
||||
diff = MBED_MIN(
|
||||
(ticker->queue->head->timestamp - ticker->queue->timestamp),
|
||||
MBED_TICKER_INTERRUPT_TIMESTAMP_MAX_DELTA
|
||||
);
|
||||
}
|
||||
|
||||
ticker->interface->set_interrupt(
|
||||
ticker->queue->timestamp + diff
|
||||
);
|
||||
}
|
||||
|
||||
void ticker_set_handler(const ticker_data_t *const ticker, ticker_event_handler handler) {
|
||||
initialize(ticker);
|
||||
set_handler(ticker, handler);
|
||||
}
|
||||
|
||||
void ticker_irq_handler(const ticker_data_t *const ticker) {
|
||||
ticker->interface->clear_interrupt();
|
||||
|
||||
/* Go through all the pending TimerEvents */
|
||||
while (1) {
|
||||
if (data->queue->head == NULL) {
|
||||
// There are no more TimerEvents left, so disable matches.
|
||||
data->interface->disable_interrupt();
|
||||
return;
|
||||
if (ticker->queue->head == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ((int)(data->queue->head->timestamp - data->interface->read()) <= 0) {
|
||||
// update the current timestamp used by the queue
|
||||
update_current_timestamp(ticker);
|
||||
|
||||
if (ticker->queue->head->timestamp <= ticker->queue->timestamp) {
|
||||
// This event was in the past:
|
||||
// point to the following one and execute its handler
|
||||
ticker_event_t *p = data->queue->head;
|
||||
data->queue->head = data->queue->head->next;
|
||||
if (data->queue->event_handler != NULL) {
|
||||
(*data->queue->event_handler)(p->id); // NOTE: the handler can set new events
|
||||
ticker_event_t *p = ticker->queue->head;
|
||||
ticker->queue->head = ticker->queue->head->next;
|
||||
if (ticker->queue->event_handler != NULL) {
|
||||
(*ticker->queue->event_handler)(p->id); // NOTE: the handler can set new events
|
||||
}
|
||||
/* Note: We continue back to examining the head because calling the
|
||||
* event handler may have altered the chain of pending events. */
|
||||
} else {
|
||||
// This event and the following ones in the list are in the future:
|
||||
// set it as next interrupt and return
|
||||
data->interface->set_interrupt(data->queue->head->timestamp);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
update_interrupt(ticker);
|
||||
}
|
||||
|
||||
void ticker_insert_event(const ticker_data_t *const data, ticker_event_t *obj, timestamp_t timestamp, uint32_t id) {
|
||||
void ticker_insert_event(const ticker_data_t *const ticker, ticker_event_t *obj, timestamp_t timestamp, uint32_t id) {
|
||||
/* disable interrupts for the duration of the function */
|
||||
core_util_critical_section_enter();
|
||||
|
||||
// update the current timestamp
|
||||
update_current_timestamp(ticker);
|
||||
us_timestamp_t absolute_timestamp = convert_relative_timestamp(
|
||||
ticker->queue->timestamp,
|
||||
timestamp
|
||||
);
|
||||
core_util_critical_section_exit();
|
||||
|
||||
// defer to ticker_insert_event_us
|
||||
ticker_insert_event_us(
|
||||
ticker,
|
||||
obj, absolute_timestamp, id
|
||||
);
|
||||
}
|
||||
|
||||
void ticker_insert_event_us(const ticker_data_t *const ticker, ticker_event_t *obj, us_timestamp_t timestamp, uint32_t id) {
|
||||
/* disable interrupts for the duration of the function */
|
||||
core_util_critical_section_enter();
|
||||
|
||||
// update the current timestamp
|
||||
update_current_timestamp(ticker);
|
||||
|
||||
// filter out timestamp in the past
|
||||
if (timestamp < ticker->queue->timestamp) {
|
||||
update_interrupt(ticker);
|
||||
return;
|
||||
}
|
||||
|
||||
// initialise our data
|
||||
obj->timestamp = timestamp;
|
||||
obj->id = id;
|
||||
|
|
@ -64,10 +181,10 @@ void ticker_insert_event(const ticker_data_t *const data, ticker_event_t *obj, t
|
|||
/* Go through the list until we either reach the end, or find
|
||||
an element this should come before (which is possibly the
|
||||
head). */
|
||||
ticker_event_t *prev = NULL, *p = data->queue->head;
|
||||
ticker_event_t *prev = NULL, *p = ticker->queue->head;
|
||||
while (p != NULL) {
|
||||
/* check if we come before p */
|
||||
if ((int)(timestamp - p->timestamp) < 0) {
|
||||
if (timestamp < p->timestamp) {
|
||||
break;
|
||||
}
|
||||
/* go to the next element */
|
||||
|
|
@ -80,30 +197,27 @@ void ticker_insert_event(const ticker_data_t *const data, ticker_event_t *obj, t
|
|||
|
||||
/* if prev is NULL we're at the head */
|
||||
if (prev == NULL) {
|
||||
data->queue->head = obj;
|
||||
data->interface->set_interrupt(timestamp);
|
||||
ticker->queue->head = obj;
|
||||
} else {
|
||||
prev->next = obj;
|
||||
}
|
||||
|
||||
update_interrupt(ticker);
|
||||
|
||||
core_util_critical_section_exit();
|
||||
}
|
||||
|
||||
void ticker_remove_event(const ticker_data_t *const data, ticker_event_t *obj) {
|
||||
void ticker_remove_event(const ticker_data_t *const ticker, ticker_event_t *obj) {
|
||||
core_util_critical_section_enter();
|
||||
|
||||
// remove this object from the list
|
||||
if (data->queue->head == obj) {
|
||||
if (ticker->queue->head == obj) {
|
||||
// first in the list, so just drop me
|
||||
data->queue->head = obj->next;
|
||||
if (data->queue->head == NULL) {
|
||||
data->interface->disable_interrupt();
|
||||
} else {
|
||||
data->interface->set_interrupt(data->queue->head->timestamp);
|
||||
}
|
||||
ticker->queue->head = obj->next;
|
||||
update_interrupt(ticker);
|
||||
} else {
|
||||
// find the object before me, then drop me
|
||||
ticker_event_t* p = data->queue->head;
|
||||
ticker_event_t* p = ticker->queue->head;
|
||||
while (p != NULL) {
|
||||
if (p->next == obj) {
|
||||
p->next = obj->next;
|
||||
|
|
@ -116,9 +230,13 @@ void ticker_remove_event(const ticker_data_t *const data, ticker_event_t *obj) {
|
|||
core_util_critical_section_exit();
|
||||
}
|
||||
|
||||
timestamp_t ticker_read(const ticker_data_t *const data)
|
||||
{
|
||||
return data->interface->read();
|
||||
timestamp_t ticker_read(const ticker_data_t *const ticker) {
|
||||
return ticker_read_us(ticker);
|
||||
}
|
||||
|
||||
us_timestamp_t ticker_read_us(const ticker_data_t *const ticker) {
|
||||
update_current_timestamp(ticker);
|
||||
return ticker->queue->timestamp;
|
||||
}
|
||||
|
||||
int ticker_get_next_timestamp(const ticker_data_t *const data, timestamp_t *timestamp)
|
||||
|
|
|
|||
Loading…
Reference in New Issue