AKOS  v1.0.0
Documentation
Loading...
Searching...
No Matches
timer.c
Go to the documentation of this file.
1/****************************************************************************/
12
13#include "core.h"
14#include "timer.h"
15#include "thread.h"
16#include "message.h"
17#include "list.h"
18
19static ak_timer_t timer_pool[OS_CFG_TIMER_POOL_SIZE];
20static ak_timer_t *free_list_timer_pool;
21static uint8_t timer_pool_used;
22
23static uint32_t timer_counter;
24
25static list_t timer_list_1;
26static list_t timer_list_2;
27
28static list_t *volatile timer_list_ptr; /* Current */
29static list_t *volatile overflow_timer_list_ptr;
30
31static volatile uint32_t next_tick_to_unblock_timer = (uint32_t)OS_CFG_DELAY_MAX;
32
36static void timer_pool_init()
37{
38 uint8_t index;
39
40 free_list_timer_pool = (ak_timer_t *)timer_pool;
41
42 for (index = 0; index < OS_CFG_TIMER_POOL_SIZE; index++)
43 {
44 if (index == (OS_CFG_TIMER_POOL_SIZE - 1))
45 {
46 timer_pool[index].next = NULL;
47 }
48 else
49 {
50 timer_pool[index].next = (ak_timer_t *)&timer_pool[index + 1];
51 }
52 }
53
54 timer_pool_used = 0;
55}
56
60static void init_timer_lists(void)
61{
62 /* Initialize lists */
63 akos_list_init(&timer_list_1);
64 akos_list_init(&timer_list_2);
65 timer_list_ptr = &timer_list_1;
66 overflow_timer_list_ptr = &timer_list_2;
67 /********************/
68}
69
73static void timer_switch_lists()
74{
75 list_t *p_list_temp;
76 p_list_temp = timer_list_ptr;
77 timer_list_ptr = overflow_timer_list_ptr;
78 overflow_timer_list_ptr = p_list_temp;
79
80 if (list_is_empty(timer_list_ptr) == OS_TRUE)
81 {
82 next_tick_to_unblock_timer = OS_CFG_DELAY_MAX;
83 }
84 else
85 {
86 next_tick_to_unblock_timer = 0u;
87 }
88}
93static void add_timer_to_list(ak_timer_t *p_timer)
94{
95 AKOS_CORE_ENTER_CRITICAL();
96 {
97 const uint32_t const_tick = akos_thread_get_tick();
98 uint32_t tick_to_trigger = list_item_get_value(&(p_timer->timer_list_item));
99 if (tick_to_trigger < const_tick)
100 {
101 /* Wake time has overflowed. Place this item in the overflow
102 * list. */
103 akos_list_insert(overflow_timer_list_ptr, &(p_timer->timer_list_item));
104 }
105 else
106 {
107 /* The wake time has not overflowed, so the current block list
108 * is used. */
109 akos_list_insert(timer_list_ptr, &(p_timer->timer_list_item));
110 }
111 }
112 AKOS_CORE_EXIT_CRITICAL();
113}
117static void update_next_tick_to_unblock()
118{
119 ak_timer_t *p_timer;
120 uint32_t item_value;
121 if (list_is_empty(timer_list_ptr) == OS_TRUE)
122 {
123 next_tick_to_unblock_timer = OS_CFG_DELAY_MAX;
124 }
125 else
126 {
127 p_timer = list_get_owner_of_head_item(timer_list_ptr);
128 item_value = list_item_get_value(&(p_timer->timer_list_item));
129 if (item_value < next_tick_to_unblock_timer)
130 {
131 next_tick_to_unblock_timer = item_value;
132 }
133 }
134}
135
146ak_timer_t *akos_timer_create(timer_id_t id, int32_t sig, timer_cb func_cb, uint8_t des_thread_id, uint32_t period, timer_type_t type)
147{
148 /*It is important to set value for timer_list_item, because it holds time stamp*/
149 if (des_thread_id >= akos_thread_get_app_thread_count())
150 {
151 // OSUniversalError = OS_ERR_DES_TASK_ID_INVALID;
152 core_assert(0, "OS_ERR_DES_THREAD_ID_INVALID");
153 return NULL;
154 }
155 if (des_thread_id == akos_thread_get_timer_thread_id())
156 {
157 // OSUniversalError = OS_ERR_CAN_NOT_SET_DES_TO_ITSELF;
158 core_assert(0, "OS_ERR_CAN_NOT_SET_DES_TO_ITSELF");
159 return NULL;
160 }
161 if (period == 0u && type == TIMER_PERIODIC)
162 {
163 // OSUniversalError = OS_ERR_TIMER_NOT_ACECPT_ZERO_PERIOD;
164 core_assert(0, "OS_ERR_TIMER_NOT_ACECPT_ZERO_PERIOD");
165 return NULL;
166 }
167 ak_timer_t *p_timer;
168 AKOS_CORE_ENTER_CRITICAL();
169 if ((timer_pool_used >= OS_CFG_TIMER_POOL_SIZE) || (free_list_timer_pool == NULL))
170 {
171 AKOS_CORE_EXIT_CRITICAL();
172 core_assert(0, "OS_ERR_TIMER_POOL_IS_FULL");
173 return NULL;
174 }
175 p_timer = free_list_timer_pool;
176 free_list_timer_pool = p_timer->next;
177 timer_pool_used++;
178 AKOS_CORE_EXIT_CRITICAL();
179
180 p_timer->id = id;
181 p_timer->sig = sig;
182 p_timer->func_cb = func_cb;
183 p_timer->des_thread_id = des_thread_id;
184
185 switch (type)
186 {
187 case TIMER_ONE_SHOT:
188 /* code */
189 p_timer->period = 0;
190 break;
191 case TIMER_PERIODIC:
192 p_timer->period = period;
193 break;
194 default:
195 break;
196 }
197 /* Make connection */
198 akos_list_item_init(&(p_timer->timer_list_item));
199 list_item_set_owner(&(p_timer->timer_list_item), (void *)p_timer);
200
201 // list_item_set_value(&(p_timer->timer_list_item), period + akos_thread_get_tick());
202 // add_timer_to_list(p_timer);
203 // update_next_tick_to_unblock();
204 // akos_thread_post_msg_pure(OS_CFG_TIMER_TASK_ID, TIMER_CMD_UPDATE);
205 return p_timer;
206}
207
211void akos_timer_remove(ak_timer_t *p_timer)
212{
213 AKOS_CORE_ENTER_CRITICAL();
214 if (timer_pool_used == 0u)
215 {
216 AKOS_CORE_EXIT_CRITICAL();
217 core_assert(0, "OS_ERR_TIMER_POOL_UNDERFLOW");
218 return;
219 }
220
221 p_timer->next = free_list_timer_pool;
222 free_list_timer_pool = p_timer;
223 timer_pool_used--;
224
225 if (list_item_get_list_contain(&(p_timer->timer_list_item)) != NULL)
226 akos_list_remove(&(p_timer->timer_list_item));
227
228 AKOS_CORE_EXIT_CRITICAL();
229}
230
235{
236 timer_pool_init();
237 init_timer_lists();
238 next_tick_to_unblock_timer = OS_CFG_DELAY_MAX;
239 /*TODO: Create a thread for timer here, or maybe in thread.c and call akos_timer_processing*/
240}
241
248{
249 msg_t *p_msg;
250 ak_timer_t *p_timer;
251 uint32_t item_value;
252 static uint32_t last_time = (uint32_t)0U;
253 uint32_t time_now = akos_thread_get_tick();
254 if (time_now < last_time)
255 {
256 /* Overflown */
257 timer_switch_lists();
258 }
259 if (time_now >= next_tick_to_unblock_timer)
260 {
261 for (;;)
262 {
263 if (list_is_empty(timer_list_ptr) == OS_TRUE)
264 {
265 next_tick_to_unblock_timer = OS_CFG_DELAY_MAX;
266 break;
267 }
268 else
269 {
270 p_timer = list_get_owner_of_head_item(timer_list_ptr);
271 item_value = list_item_get_value(&(p_timer->timer_list_item));
272 if (item_value > time_now)
273 {
274 /* Stop condition */
275 next_tick_to_unblock_timer = item_value;
276 break;
277 }
278 akos_list_remove(&(p_timer->timer_list_item));
279
280 if (p_timer->func_cb != NULL)
281 p_timer->func_cb();
282 else
283 akos_thread_post_msg_pure(p_timer->des_thread_id, p_timer->sig);
284 if (p_timer->period != 0)
285 {
286 list_item_set_value(&(p_timer->timer_list_item), p_timer->period + time_now);
287 add_timer_to_list(p_timer);
288 }
289 else
290 akos_timer_remove(p_timer); /* One shot */
291 update_next_tick_to_unblock();
292 }
293 }
294 }
295 last_time = time_now;
296 p_msg = akos_thread_wait_for_msg(next_tick_to_unblock_timer - time_now);
297 if (p_msg != NULL)
298 akos_message_free(p_msg);
299}
300
306void akos_timer_start(ak_timer_t *p_timer, uint32_t tick_to_wait)
307{
308 uint32_t time_now = akos_thread_get_tick();
309
310 list_item_set_value(&(p_timer->timer_list_item), tick_to_wait + time_now);
311
312 add_timer_to_list(p_timer);
313 update_next_tick_to_unblock();
315}
316
321void akos_timer_reset(ak_timer_t *p_timer)
322{
323 if (list_item_get_list_contain(&(p_timer->timer_list_item)) == NULL)
324 {
325 // OSUniversalError = OS_ERR_TIMER_IS_NOT_RUNNING;
326 core_assert(0, "OS_ERR_TIMER_IS_NOT_RUNNING");
327 return;
328 }
329 uint32_t time_now = akos_thread_get_tick();
330 akos_list_remove(&(p_timer->timer_list_item));
331 if (p_timer->period != 0)
332 {
333 list_item_set_value(&(p_timer->timer_list_item), p_timer->period + time_now);
334 add_timer_to_list(p_timer);
335 }
336 else
337 akos_timer_remove(p_timer); /* One shot */
338 update_next_tick_to_unblock();
340}
#define OS_CFG_TIMER_POOL_SIZE
Definition config.h:38
#define OS_CFG_DELAY_MAX
Definition config.h:27
Kernel control and critical-section API.
Doubly-linked list types and APIs for scheduler internals.
void akos_list_item_init(list_item_t *const p_list_item)
Initialize list item linkage and ownership metadata.
Definition list.c:35
void akos_list_init(list_t *const p_list)
Initialize list metadata and sentinel.
Definition list.c:20
void akos_list_insert(list_t *const p_list, list_item_t *const p_list_item)
Insert item in ascending order by list_item::value.
Definition list.c:104
uint16_t akos_list_remove(list_item_t *const p_list_item)
Remove item from containing list.
Definition list.c:141
Message object and message queue APIs.
void akos_message_free(msg_t *p_msg)
Return message to message pool.
Definition message.c:62
Thread scheduling and thread messaging APIs.
msg_t * akos_thread_wait_for_msg(uint32_t time_out)
Wait for message from current thread queue.
Definition thread.c:735
uint8_t akos_thread_get_timer_thread_id(void)
Get the runtime thread ID assigned to the timer thread.
Definition thread.c:79
uint32_t akos_thread_get_tick(void)
Get current system tick.
Definition thread.c:64
uint8_t akos_thread_get_app_thread_count(void)
Get number of application threads defined via AKOS_THREAD_DEFINE.
Definition thread.c:69
void akos_thread_post_msg_pure(uint8_t des_thread_id, int32_t sig)
Post pure signal message to destination thread.
Definition thread.c:654
void akos_timer_remove(ak_timer_t *p_timer)
Remove timer from lists and return it to pool.
Definition timer.c:211
void akos_timer_processing()
Timer-task processing function.
Definition timer.c:247
ak_timer_t * akos_timer_create(timer_id_t id, int32_t sig, timer_cb func_cb, uint8_t des_thread_id, uint32_t period, timer_type_t type)
Create a timer object from timer pool.
Definition timer.c:146
void akos_timer_reset(ak_timer_t *p_timer)
Reset a running timer to its next period.
Definition timer.c:321
void akos_timer_init(void)
Initialize timer module state.
Definition timer.c:234
void akos_timer_start(ak_timer_t *p_timer, uint32_t tick_to_wait)
Start timer with initial delay.
Definition timer.c:306
Software timer APIs.
timer_type_t
Timer mode.
Definition timer.h:44
@ TIMER_PERIODIC
Definition timer.h:46
@ TIMER_ONE_SHOT
Definition timer.h:45
uint8_t timer_id_t
Timer identifier type.
Definition timer.h:29
void(* timer_cb)()
Timer callback signature.
Definition timer.h:37