1 /* mbed Microcontroller Library
2  * Copyright (c) 2006-2013 ARM Limited
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include <stddef.h>
17 #include "us_ticker_api.h"
18 #include "cmsis.h"
19 
20 static ticker_event_handler event_handler;
21 static ticker_event_t *head = NULL;
22 
us_ticker_set_handler(ticker_event_handler handler)23 void us_ticker_set_handler(ticker_event_handler handler)
24 {
25 	us_ticker_init();
26 
27 	event_handler = handler;
28 }
29 
us_ticker_irq_handler(void)30 void us_ticker_irq_handler(void)
31 {
32 	us_ticker_clear_interrupt();
33 
34 	/* Go through all the pending TimerEvents */
35 	while (1) {
36 		if (head == NULL) {
37 			/*  There are no more TimerEvents left, so disable matches. */
38 			us_ticker_disable_interrupt();
39 			return;
40 		}
41 
42 		if ((int)(head->timestamp - us_ticker_read()) <= 0) {
43 			/* This event was in the past: point to the following one and execute its handler */
44 			ticker_event_t *p = head;
45 			head = head->next;
46 			if (event_handler != NULL) {
47 				event_handler(p->id); // NOTE: the handler can set new events
48 			}
49 			/* Note: We continue back to examining the head because calling the */
50 			/* event handler may have altered the chain of pending events. */
51 		} else {
52 			/* This event and the following ones in the list are in the future: set it as next interrupt and return */
53 			us_ticker_set_interrupt(head->timestamp);
54 			return;
55 		}
56 	}
57 }
58 
us_ticker_insert_event(ticker_event_t * obj,timestamp_t timestamp,uint32_t id)59 void us_ticker_insert_event(ticker_event_t *obj, timestamp_t timestamp, uint32_t id)
60 {
61 	/* disable interrupts for the duration of the function */
62 	__disable_irq();
63 
64 	/*  initialise our data */
65 	obj->timestamp = timestamp;
66 	obj->id = id;
67 
68 	/* Go through the list until we either reach the end, or find */
69 	/* an element this should come before (which is possibly the head). */
70 	ticker_event_t *prev = NULL, *p = head;
71 	while (p != NULL) {
72 		/* check if we come before p */
73 		if ((int)(timestamp - p->timestamp) <= 0) {
74 			break;
75 		}
76 		/* go to the next element */
77 		prev = p;
78 		p = p->next;
79 	}
80 	/* if prev is NULL we're at the head */
81 	if (prev == NULL) {
82 		head = obj;
83 		us_ticker_set_interrupt(timestamp);
84 	} else {
85 		prev->next = obj;
86 	}
87 	/* if we're at the end p will be NULL, which is correct */
88 	obj->next = p;
89 
90 	__enable_irq();
91 }
92 
us_ticker_remove_event(ticker_event_t * obj)93 void us_ticker_remove_event(ticker_event_t *obj)
94 {
95 	__disable_irq();
96 
97 	/* remove this object from the list */
98 	if (head == obj) {
99 		/*  first in the list, so just drop me */
100 		head = obj->next;
101 		if (head == NULL) {
102 			us_ticker_disable_interrupt();
103 		} else {
104 			us_ticker_set_interrupt(head->timestamp);
105 		}
106 	} else {
107 		/* find the object before me, then drop me */
108 		ticker_event_t* p = head;
109 		while (p != NULL) {
110 			if (p->next == obj) {
111 				p->next = obj->next;
112 				break;
113 			}
114 			p = p->next;
115 		}
116 	}
117 
118 	__enable_irq();
119 }
120