13
13
* See the License for the specific language governing permissions and
14
14
* limitations under the License.
15
15
*/
16
+ #include <stdio.h>
16
17
#include <stddef.h>
17
18
#include "hal/ticker_api.h"
18
19
#include "platform/mbed_critical.h"
19
20
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))
22
22
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 );
24
113
}
25
114
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 ();
28
117
29
118
/* Go through all the pending TimerEvents */
30
119
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 ;
35
122
}
36
123
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 ) {
38
128
// This event was in the past:
39
129
// 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
44
134
}
45
135
/* Note: We continue back to examining the head because calling the
46
136
* event handler may have altered the chain of pending events. */
47
137
} 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
+ }
53
140
}
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
+ );
54
162
}
55
163
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 ) {
57
165
/* disable interrupts for the duration of the function */
58
166
core_util_critical_section_enter ();
59
167
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
+
60
177
// initialise our data
61
178
obj -> timestamp = timestamp ;
62
179
obj -> id = id ;
63
180
64
181
/* Go through the list until we either reach the end, or find
65
182
an element this should come before (which is possibly the
66
183
head). */
67
- ticker_event_t * prev = NULL , * p = data -> queue -> head ;
184
+ ticker_event_t * prev = NULL , * p = ticker -> queue -> head ;
68
185
while (p != NULL ) {
69
186
/* check if we come before p */
70
- if (( int )( timestamp - p -> timestamp ) < 0 ) {
187
+ if (timestamp < p -> timestamp ) {
71
188
break ;
72
189
}
73
190
/* go to the next element */
@@ -80,30 +197,27 @@ void ticker_insert_event(const ticker_data_t *const data, ticker_event_t *obj, t
80
197
81
198
/* if prev is NULL we're at the head */
82
199
if (prev == NULL ) {
83
- data -> queue -> head = obj ;
84
- data -> interface -> set_interrupt (timestamp );
200
+ ticker -> queue -> head = obj ;
85
201
} else {
86
202
prev -> next = obj ;
87
203
}
88
204
205
+ update_interrupt (ticker );
206
+
89
207
core_util_critical_section_exit ();
90
208
}
91
209
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 ) {
93
211
core_util_critical_section_enter ();
94
212
95
213
// remove this object from the list
96
- if (data -> queue -> head == obj ) {
214
+ if (ticker -> queue -> head == obj ) {
97
215
// 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 );
104
218
} else {
105
219
// find the object before me, then drop me
106
- ticker_event_t * p = data -> queue -> head ;
220
+ ticker_event_t * p = ticker -> queue -> head ;
107
221
while (p != NULL ) {
108
222
if (p -> next == obj ) {
109
223
p -> next = obj -> next ;
@@ -116,9 +230,13 @@ void ticker_remove_event(const ticker_data_t *const data, ticker_event_t *obj) {
116
230
core_util_critical_section_exit ();
117
231
}
118
232
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 ;
122
240
}
123
241
124
242
int ticker_get_next_timestamp (const ticker_data_t * const data , timestamp_t * timestamp )
0 commit comments