Skip to content

Commit 1057720

Browse files
committed
[HAL] Add support of 64 bits timestamp in ticker API implementation.
1 parent b1f3aa7 commit 1057720

File tree

1 file changed

+154
-36
lines changed

1 file changed

+154
-36
lines changed

hal/mbed_ticker_api.c

Lines changed: 154 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -13,61 +13,178 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16+
#include <stdio.h>
1617
#include <stddef.h>
1718
#include "hal/ticker_api.h"
1819
#include "platform/mbed_critical.h"
1920

20-
void ticker_set_handler(const ticker_data_t *const data, ticker_event_handler handler) {
21-
data->interface->init();
21+
#define MBED_MIN(x,y) (((x)<(y))?(x):(y))
2222

23-
data->queue->event_handler = handler;
23+
static void update_interrupt(const ticker_data_t *const ticker);
24+
static void update_current_timestamp(const ticker_data_t *const ticker);
25+
26+
/*
27+
* Initialize a ticker instance.
28+
*/
29+
static void initialize(const ticker_data_t *ticker) {
30+
// return if the queue has already been initialized, in that case the
31+
// interface used by the queue is already initialized.
32+
if (ticker->queue->initialized) {
33+
return;
34+
}
35+
36+
ticker->interface->init();
37+
38+
ticker->queue->event_handler = NULL;
39+
ticker->queue->head = NULL;
40+
ticker->queue->timestamp = 0;
41+
ticker->queue->initialized = true;
42+
43+
update_current_timestamp(ticker);
44+
update_interrupt(ticker);
45+
}
46+
47+
/**
48+
* Set the event handler function of a ticker instance.
49+
*/
50+
static void set_handler(const ticker_data_t *const ticker, ticker_event_handler handler) {
51+
ticker->queue->event_handler = handler;
52+
}
53+
54+
/*
55+
* Convert a low res timestamp to a high res timestamp. An high resolution
56+
* timestamp is used as the reference point to convert the low res timestamp
57+
* into an high res one.
58+
*
59+
* It is important to note that the result will **never** be in the past. If the
60+
* value of the low res timetamp is less than the low res part of the reference
61+
* timestamp then an overflow is
62+
*
63+
* @param ref: The timestamp of reference.
64+
* @param relative_timestamp: The timestamp to convert.
65+
*/
66+
static us_timestamp_t convert_relative_timestamp(us_timestamp_t ref, timestamp_t relative_timestamp) {
67+
bool overflow = relative_timestamp < ((timestamp_t) ref) ? true : false;
68+
69+
us_timestamp_t result = (ref & ~((us_timestamp_t)UINT32_MAX)) | relative_timestamp;
70+
if (overflow) {
71+
result += (1ULL<<32);
72+
}
73+
74+
return result;
75+
}
76+
77+
/**
78+
* update the current timestamp value of a ticker.
79+
*/
80+
static void update_current_timestamp(const ticker_data_t *const ticker) {
81+
ticker->queue->timestamp = convert_relative_timestamp(
82+
ticker->queue->timestamp,
83+
ticker->interface->read()
84+
);
85+
}
86+
87+
/**
88+
* update the interrupt with the appropriate timestamp.
89+
* if there is no interrupt scheduled or the next event to execute is in more
90+
* than MBED_TICKER_INTERRUPT_TIMESTAMP_MAX_DELTA us from now then the
91+
* interrupt will be set to MBED_TICKER_INTERRUPT_TIMESTAMP_MAX_DELTA us from now.
92+
* Otherwise the interrupt will be set to head->timestamp - queue->timestamp us.
93+
*/
94+
static void update_interrupt(const ticker_data_t *const ticker) {
95+
update_current_timestamp(ticker);
96+
uint32_t diff = MBED_TICKER_INTERRUPT_TIMESTAMP_MAX_DELTA;
97+
98+
if (ticker->queue->head) {
99+
diff = MBED_MIN(
100+
(ticker->queue->head->timestamp - ticker->queue->timestamp),
101+
MBED_TICKER_INTERRUPT_TIMESTAMP_MAX_DELTA
102+
);
103+
}
104+
105+
ticker->interface->set_interrupt(
106+
ticker->queue->timestamp + diff
107+
);
108+
}
109+
110+
void ticker_set_handler(const ticker_data_t *const ticker, ticker_event_handler handler) {
111+
initialize(ticker);
112+
set_handler(ticker, handler);
24113
}
25114

26-
void ticker_irq_handler(const ticker_data_t *const data) {
27-
data->interface->clear_interrupt();
115+
void ticker_irq_handler(const ticker_data_t *const ticker) {
116+
ticker->interface->clear_interrupt();
28117

29118
/* Go through all the pending TimerEvents */
30119
while (1) {
31-
if (data->queue->head == NULL) {
32-
// There are no more TimerEvents left, so disable matches.
33-
data->interface->disable_interrupt();
34-
return;
120+
if (ticker->queue->head == NULL) {
121+
break;
35122
}
36123

37-
if ((int)(data->queue->head->timestamp - data->interface->read()) <= 0) {
124+
// update the current timestamp used by the queue
125+
update_current_timestamp(ticker);
126+
127+
if (ticker->queue->head->timestamp <= ticker->queue->timestamp) {
38128
// This event was in the past:
39129
// point to the following one and execute its handler
40-
ticker_event_t *p = data->queue->head;
41-
data->queue->head = data->queue->head->next;
42-
if (data->queue->event_handler != NULL) {
43-
(*data->queue->event_handler)(p->id); // NOTE: the handler can set new events
130+
ticker_event_t *p = ticker->queue->head;
131+
ticker->queue->head = ticker->queue->head->next;
132+
if (ticker->queue->event_handler != NULL) {
133+
(*ticker->queue->event_handler)(p->id); // NOTE: the handler can set new events
44134
}
45135
/* Note: We continue back to examining the head because calling the
46136
* event handler may have altered the chain of pending events. */
47137
} else {
48-
// This event and the following ones in the list are in the future:
49-
// set it as next interrupt and return
50-
data->interface->set_interrupt(data->queue->head->timestamp);
51-
return;
52-
}
138+
break;
139+
}
53140
}
141+
142+
update_interrupt(ticker);
143+
}
144+
145+
void ticker_insert_event(const ticker_data_t *const ticker, ticker_event_t *obj, timestamp_t timestamp, uint32_t id) {
146+
/* disable interrupts for the duration of the function */
147+
core_util_critical_section_enter();
148+
149+
// update the current timestamp
150+
update_current_timestamp(ticker);
151+
us_timestamp_t absolute_timestamp = convert_relative_timestamp(
152+
ticker->queue->timestamp,
153+
timestamp
154+
);
155+
core_util_critical_section_exit();
156+
157+
// defer to ticker_insert_event_us
158+
ticker_insert_event_us(
159+
ticker,
160+
obj, absolute_timestamp, id
161+
);
54162
}
55163

56-
void ticker_insert_event(const ticker_data_t *const data, ticker_event_t *obj, timestamp_t timestamp, uint32_t id) {
164+
void ticker_insert_event_us(const ticker_data_t *const ticker, ticker_event_t *obj, us_timestamp_t timestamp, uint32_t id) {
57165
/* disable interrupts for the duration of the function */
58166
core_util_critical_section_enter();
59167

168+
// update the current timestamp
169+
update_current_timestamp(ticker);
170+
171+
// filter out timestamp in the past
172+
if (timestamp < ticker->queue->timestamp) {
173+
update_interrupt(ticker);
174+
return;
175+
}
176+
60177
// initialise our data
61178
obj->timestamp = timestamp;
62179
obj->id = id;
63180

64181
/* Go through the list until we either reach the end, or find
65182
an element this should come before (which is possibly the
66183
head). */
67-
ticker_event_t *prev = NULL, *p = data->queue->head;
184+
ticker_event_t *prev = NULL, *p = ticker->queue->head;
68185
while (p != NULL) {
69186
/* check if we come before p */
70-
if ((int)(timestamp - p->timestamp) < 0) {
187+
if (timestamp < p->timestamp) {
71188
break;
72189
}
73190
/* go to the next element */
@@ -80,30 +197,27 @@ void ticker_insert_event(const ticker_data_t *const data, ticker_event_t *obj, t
80197

81198
/* if prev is NULL we're at the head */
82199
if (prev == NULL) {
83-
data->queue->head = obj;
84-
data->interface->set_interrupt(timestamp);
200+
ticker->queue->head = obj;
85201
} else {
86202
prev->next = obj;
87203
}
88204

205+
update_interrupt(ticker);
206+
89207
core_util_critical_section_exit();
90208
}
91209

92-
void ticker_remove_event(const ticker_data_t *const data, ticker_event_t *obj) {
210+
void ticker_remove_event(const ticker_data_t *const ticker, ticker_event_t *obj) {
93211
core_util_critical_section_enter();
94212

95213
// remove this object from the list
96-
if (data->queue->head == obj) {
214+
if (ticker->queue->head == obj) {
97215
// first in the list, so just drop me
98-
data->queue->head = obj->next;
99-
if (data->queue->head == NULL) {
100-
data->interface->disable_interrupt();
101-
} else {
102-
data->interface->set_interrupt(data->queue->head->timestamp);
103-
}
216+
ticker->queue->head = obj->next;
217+
update_interrupt(ticker);
104218
} else {
105219
// find the object before me, then drop me
106-
ticker_event_t* p = data->queue->head;
220+
ticker_event_t* p = ticker->queue->head;
107221
while (p != NULL) {
108222
if (p->next == obj) {
109223
p->next = obj->next;
@@ -116,9 +230,13 @@ void ticker_remove_event(const ticker_data_t *const data, ticker_event_t *obj) {
116230
core_util_critical_section_exit();
117231
}
118232

119-
timestamp_t ticker_read(const ticker_data_t *const data)
120-
{
121-
return data->interface->read();
233+
timestamp_t ticker_read(const ticker_data_t *const ticker) {
234+
return ticker_read_us(ticker);
235+
}
236+
237+
us_timestamp_t ticker_read_us(const ticker_data_t *const ticker) {
238+
update_current_timestamp(ticker);
239+
return ticker->queue->timestamp;
122240
}
123241

124242
int ticker_get_next_timestamp(const ticker_data_t *const data, timestamp_t *timestamp)

0 commit comments

Comments
 (0)