diff --git a/doc/en/tmgr.txt b/doc/en/tmgr.txt new file mode 100644 index 0000000..5b1233d --- /dev/null +++ b/doc/en/tmgr.txt @@ -0,0 +1,196 @@ +tmgr: Simple task manager and scheduler +--------------------------------------- + +Description +----------- + +Task scheduler should be easily used if your program could be logically divided +into different threads or delayed function calls. In this case scheduler allows +you to work with tasks in the easiest way. + +Features +-------- + +* Easy in understanding and usage + +* Cross-platform (written fully in C without assembler magic) + + +How to use? +----------- + +1. Initialization +----------------- + +Operation of scheduler consists of two periodic function calls: +tmgr_process() and tmgr_interrupt(). + +tmgr_interrupt() function should be called in system timer interrupt hander which +counts time quantums. Optimal time quantum size is 1 ms (author's opinion). +In this case, frequency of timer interrupt handler calls is 1 kHz. +tmgr_interrupt() function just counts system time, so it is fast and safe for +interrupt context. + +tmgr_process() function should be called in main program loop. In this function +context all user's tasks will be executed, so it's not recommended to call this +function in interrupt handles. + +Also you need to set system timer frequency (for time conversion functions) using +menuconfig entry "Scheduler timer frequency" (in Hz). + +Initialization of system timer depends on current +platform, so tmgr library will _not_ initialize it. It is an user's problem. + +A sample program that correctly runs scheduler base: + +#include + +void SYSTEM_TIMER_IRQ() +{ + /* This function means an abstract timer interrupt handler */ + tmgr_interrupt(); +} + +int main(void) +{ + /* Platform-dependent initialization of system timer */ + SYSTEM_TIMER_INIT(1000); + + /* Run tick function in infinite loop */ + while (1) + tmgr_tick(); + + return 0; +} + +2. How to use scheduler +----------------------- + +First, you need a handler function. Its prototype is: + + void my_handler(void *data); + +You see that function accepts a void pointer. It is a +field for user information (if you want to control the context of +function running). You can keep it as is, or use this feature to give +something you need for your handler. (For example, set mode of operation). +This parameter is stored in timer structure, you set it once when you +initialize or re-initialize timer. + +Note that the value should be stored in static memory, because there are +no guarantees that there will be a right information in the stack when the +handler runs. + +Next, scheduler need to know about the value of delay. Also +it needs a piece of memory to save the task description. + +To keep timer data, scheduler needs a piece of _static_ memory. You can +init the memory yourself, but there is a macros to save your time: + + TMGR_DEFINE_TIMER(timer_name, handler, data, expires); + +If you want to define it as static, just write + + static TMGR_DEFINE_TIMER(timer_name, handler, data, expires); + +in the right place. + +'expires' value here is an uptime timestamp when the handler need to be +called. + +After all that, call this to add timer (launch it; really add to queue): + + tmgr_add_timer(&timer_name); + +To make a "delayed call" (ex. for 1000 ticks), set 'expires' value as + + TMGR_DELAYED(1000) +or + tmgr_get_uptime() + 1000 + +, which is the same. + +To setup (reinit) defined timer, you can use macros + + TMGR_SETUP_TIMER(timer_name, handler, data, expires); + +It just updates the fields of timer structure. NOTE: Don't do it if +you have added this timer and not sure that it's not in the queue. + +To remove timer from the queue, use + + tmgr_del_timer(&timer_name); + +After it, you can fully reinit your timer. + +To modify uptime trigger ('expires' value), use + + tmgr_mod_timer(&timer_name, new_expires); + +just if you timer is in queue. + +In real application, you should want to calculate the time in s, ms etc. +To convert value from "natural" units to ticks, there are few macroses: + + tmgr_us_to_ticks(us) + tmgr_ms_to_ticks(ms) + tmgr_s_to_ticks(s) + +There are also macroses for convertions from ticks to natural units: + + tmgr_ticks_to_us(ticks) + tmgr_ticks_to_ms(ticks) + tmgr_ticks_to_s(ticks) + +Time values (ticks or natural) are stored in tmgr_uptime_t variables. + +So, this is correct way to run my_func() with 500 ms delay and without params: + + static TMGR_DEFINE_TIMER(my_timer, my_func, NULL, + TMGR_DELAYED(tmgr_ms_to_ticks(500))); + tmgr_add_timer(&my_timer); + + +3. Operation +------------ + +The base of time counting is system uptime value. You can get +the current value of system uptime by calling + + tmgr_get_uptime(). + +This function returns the value of tmgr_uptime_t type (signed integer). + +In the timer interrupt handler only one action is performed - increment of uptime +value and in main loop, task runs if its "expire time" is equal to system +uptime. + +Uptime is stored in tmgr_uptime_t variable. By adjusting its size (tmgr_uptime_t), +you can move the uptime limits. Available sizes are 32 and 64 bits. + +The maximal time of stable operation in uptime counter move vs. tmgr_uptime_t size +(system timers frequency = 1000 Hz): + + 32 bits - 2147483.65 s ~ 596 h ~ 25 days + 64 bits - 10^11 days + + +4. Extra features +----------------- + +tmgr_delay(delay) - performs a simple delay (waiting in loop). To set delay +in natural units, use time convertion macroses. + + tmgr_delay(tmgr_ms_to_ticks(500)); + +means 500 ms delay. + +Function receives one tmgr_uptime_t value. + +Notice. We DO NOT RECOMMEND to use this function, especially in task +context, because it can break down the tasks queue (tasks could not +run when delay is performed). Try to split your function onto several +subtasks. + +tmgr_get_fq() function just returns the value of system timer +frequency which was set before. (in tmgr_uptime_t type) diff --git a/doc/ru/tmgr.txt b/doc/ru/tmgr.txt new file mode 100644 index 0000000..293a6d8 --- /dev/null +++ b/doc/ru/tmgr.txt @@ -0,0 +1,219 @@ +tmgr: Простейший планировщик задач +---------------------------------- + +Описание +-------- + +Планировщик задач удобно использовать в том случае, если ваша программа логично +разбивается нa несколько отдельных потоков или циклично выполняемых блоков. +В таком случае планировщик предоставляет возможность сделать работу с потоками +максимально прозрачной. + +Особенности +----------- + +* Максимальная простота обращения с точки зрения пользователя + +* Кроссплатформенность (реализация полностью на Си, без ассемблера) + + +Как использовать? +----------------- + +1. Инициализация +---------------- + +Работа планировщика организуется циклическими вызовами двух функций: +tmgr_process() и tmgr_interrupt(). + +Функцию tmgr_interrupt() следует вызывать в обработчике прерывания таймера, который +отсчитывает кванты времени планировщика. Оптимальным размером кванта времени +автор считает 1 мс (соответственно, частота вызова функции tmgr_timer() будет +1 кГц). Эта функция обеспечивает только отсчёт времени (в зависимости от режима +работы планировщика) и минимально загружает систему в контексте прерывания. + +Функцию tmgr_process() следует вызывать в основном цикле программы. В рамках вызова +этой функции будет происходить выполение задач пользователя, так что её вызов +в контексте прерывания не рекомендуется. + +Для функции конвертирования времени требуется передать библиотеке значение частоты +системного таймера (в Гц). Это делается в меню настройки menuconfig, параметр +Scheduler timer frequency. + +Замечание: Планировщик _не инициализирует_ таймер. Инициализация системного +таймера и организация вызовов функций планировщика лежит на пользователе. + +Пример программы, обеспечивающей корректную работу таймера: + +#include + +void SYSTEM_TIMER_IRQ() +{ + /* Прерывание системного таймера (абстрактно) */ + tmgr_interrupt(); +} + +int main(void) +{ + /* Инициализация системного таймера, платформо-зависима */ + SYSTEM_TIMER_INIT(1000); + + /* Вызов основной функции планировщика в бесконечном цикле */ + while (1) + tmgr_process(); + + return 0; +} + +2. Работа с планировщиком +------------------------- + +Для начала вам понадобится функция-обработчик, которая будет вызвана таймером. +Прототип функции: + + void my_handler(void *data); + +Она принимает в качестве аргумента один указатель на void. Это можно +использовать для передачи какой-либо пользовательской информации обработчику +(например, для того, чтобы управлять контекстом выполнения задачи). Можно +оставить всё как есть, установив при инициализации таймера NULL в качестве +параметра. Этот параметр хранится в структуре таймера, задаётся при +(ре-)инициализации таймера. + +Важно, чтобы данные, указатель на которые передаётся функции, хранились в +статической памяти. Никаких гарантий, что, если вы храните их на стеке +(в локальной переменной), в момент вызова обработчика в стеке будет именно +нужное значение. + +Планировщику также требуется знать, когда запускать обработчик. + +Для хранения данных таймера, планировщику требуется немного _статической_ +памяти. Можно объявить одну переменную типа tmgr_timer_t (структура) вручную, +а можно использовать встроенные макросы, облегчающие жизнь: + + TMGR_DEFINE_TIMER(timer_name, handler, data, expires); + +Переменная будет называться timer_name, handler - название функции-обработчика, +data - указатель на данные, expires - таймстемп, в какое время (аптайм) +выполнить обработчик. + +Если переменная должна быть static, просто допишите + + static TMGR_DEFINE_TIMER(timer_name, handler, data, expires); + +После всей инициализации, для того, чтобы запустить таймер (добавить в очередь), +запускаем: + + tmgr_add_timer(&timer_name); + +Для того, чтобы вручную не считать время для "запуска с задержкой", в качестве +'expires' можно записать так (сейчас, для примера, задержка на 1000 тиков): + + TMGR_DELAYED(1000) +или + tmgr_get_uptime() + 1000 + +, что, в сущности, одно и то же. + +Чтобы изменить таймер (пока он не в очереди), можно использовать макрос + + TMGR_SETUP_TIMER(timer_name, handler, data, expires); + +Он просто обновляет значения в полях структуры. + +Для того, чтобы удалить таймер из очереди, используем + + tmgr_del_timer(&timer_name); + +После этого его можно спокойно перенастроить. + +Для того, чтобы просто обновить время запуска, можно использовать + + tmgr_mod_timer(&timer_name, new_expires); + +, если таймер сейчас в очереди. + +В общем случае задержка запуска считается в тиках системного таймера. Для того, +чтобы выразить задержку в нормальных единицах времени, следует использовать +макросы конвертирования времени планировщика: + + tmgr_us_to_ticks(us) + tmgr_ms_to_ticks(ms) + tmgr_s_to_ticks(s) + +Существуют также и макросы обратного конвертирования: + + tmgr_ticks_to_us(ticks) + tmgr_ticks_to_ms(ticks) + tmgr_ticks_to_s(ticks) + +Время (число тиков, а также нормальных единиц) определяется типом данных +tmgr_uptime_t (целый знаковый, размер устанавливается пользователем в меню +конфигурации menuconfig). Таким образом, все функции конвертирования времени +принимают и возвращают tmgr_uptime_t. + +Таким образом, вызов функции my_func с задержкой 500 мс будет выглядеть так: + + static TMGR_DEFINE_TIMER(my_timer, my_func, NULL, + TMGR_DELAYED(tmgr_ms_to_ticks(500))); + tmgr_add_timer(&my_timer); + + +3. Режим работы планировщика +---------------------------- + +Основанием отсчёта времени является значение "времени +работы" (uptime) программы. При этом пользователь может в любой момент узнать +текущее значение uptime, вызвав функцию + + tmgr_get_uptime(). + +Функция возвращает тип tmgr_uptime_t (целочисленный знаковый, размер которого +устанавливается пользователем в меню конфигурации menuconfig). + +Такой метод работы быстрее (в прерывании происходит только инкрементирование +значения переменной uptime, в основном цикле программы вызов задачи происходит +при совпадении текущего значения uptime с установленным при добавлении). + +Отсчитанное время хранится в переменной типа tmgr_time_t. Это целый знаковый тип, +размер которого можно установить в меню конфигурации menuconfig. +Возможно использование 32 и 64-битной переменной. + +Предельное время стабильной работы в uptime-режиме в зависимости от размера +переменной (частота системного таймера - 1 кГц): + + 32 бит - 2147483.65 с ~ 596 ч ~ 25 суток + 64 бит - 10^11 суток + +4. Описание параметров планировщика (menuconfig) +------------------------------------------------ + +Time variable size +----------------------- +Размер переменной для хранения времени. (см. Режим работы). + + +5. Дополнительные возможности +----------------------------- + +У планировщика есть функция tmgr_delay(delay). Она обеспечивает простую +задержку работы программы на нужный промежуток времени. В качестве единственного +аргумента функция принимает число тиков системного таймера, которые нужно +прождать. (С помощью функций конвертирования времени можно записывать время +задержки в стандартных единицах). Например, вызов + + tmgr_delay(tmgr_ms_to_ticks(500)); + +обеспечит остановку работы программы на 500 мс. + +Принимаемый параметр имеет тип tmgr_time_t, неоднократно описанный выше. + +Замечание. Использование этой функции с планировщиком НЕ РЕКОМЕНДУЕТСЯ. +Особенно в рамках вызываемых задач. Всё дело в том, что во время задержки +прерывается нормальное выполнение задач в планировщике (данный способ +задержки просто в цикле ждёт нужный момент времени, "подвешивая" +процессор.) + +Функцию tmgr_get_fq() можно использовать для того, чтобы в любой момент +времени получить установленное ранее значение частоты системного таймера. +Возвращаемый тип - tmgr_time_t. diff --git a/include/lib/inttypes.h b/include/lib/inttypes.h new file mode 100644 index 0000000..01e8203 --- /dev/null +++ b/include/lib/inttypes.h @@ -0,0 +1,22 @@ +#ifndef _ANTARES_LIB_INTTYPES_H +#define _ANTARES_LIB_INTTYPES_H + +/** + * Platform-dependent inttypes.h + * This file collects data about integer sizes + * of current platform by including platform-dependent files + * + * TODO: fill this file with extra includes + */ + +#if defined(CONFIG_ARCH_AVR) + #include +#elif defined(CONFIG_ARCH_ARM) + #if defined(CONFIG_STM32F1X) + #include + #endif +#elif defined(CONFIG_ARCH_NATIVE) + #include +#endif + +#endif diff --git a/include/lib/tasks.h b/include/lib/tasks.h deleted file mode 100644 index be8c45f..0000000 --- a/include/lib/tasks.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef TMGR_H -#define TMGR_H - -/** @defgroup Defines section - * @{ - */ - -#define TIME_OVER 1 // do not change. hm... doesn't matter :) - -/** @} - */ - -/** @defgroup Config section - * @{ - */ -#ifndef TASKS_CONFIG -// Config: if defined, you can add only 1 handler for 1 function-listener -// Optimises the work of the task manager if you use it for delayed looped run -#define REM_HANDLER_IS_DEFINED - -#endif -/** @} - */ - - -/** @defgroup About variables - * @{ - */ - -// Number of registered handlers - -// Typedef for handler data structure -typedef struct hndlr{ - void (*handler)(void); // address of handler function (void) - unsigned int uptime; // uptime to run - // private: address of the next structure in list - struct hndlr * next; -} handler_t; - -/** @} - */ - -/** @defgroup About functions - * @{ - */ - -// Returns 0 in normal case, or 1 (TIME_OVER constant) if system uptime is above than handler's start time -int tmgr_register(handler_t * data); // NOTE: It's better if data structure declared in global scope - // And, DO NOT CHANGE STRUCTURES OF REGISTERED HANDLERS! - // TODO: remove this limitation - -void tmgr_tick(void); // add this function to SysTick timer / another simple timer / just in forever loop :) - -void sleep_ticks(unsigned int ticks); // sleep for n timer ticks - -unsigned int tmgr_get_uptime(); -/** @} - */ - - -#endif // TASKS_H diff --git a/include/lib/tmgr.h b/include/lib/tmgr.h new file mode 100644 index 0000000..cd1cfb2 --- /dev/null +++ b/include/lib/tmgr.h @@ -0,0 +1,62 @@ +#ifndef INCLUDE_LIB_TMGR_H +#define INCLUDE_LIB_TMGR_H + +#include "inttypes.h" +#include +#include + +/* TODO: remove it ASAP */ +#ifndef ANTARES_ENABLE_IRQS +#define ANTARES_ENABLE_IRQS() +#define ANTARES_DISABLE_IRQS() +#endif + +#if defined(CONFIG_LIB_TMGR_TIME_32) +typedef int32_t tmgr_uptime_t; +#elif defined(CONFIG_LIB_TMGR_TIME_64) +typedef int64_t tmgr_uptime_t; +#else +#error "tmgr: Wrong tmgr_uptime_t size (must be 32 or 64 bits)" +#endif + +#define tmgr_ticks_to_us(ticks) (1000000U * (ticks) / CONFIG_LIB_TMGR_FQ) +#define tmgr_ticks_to_ms(ticks) (1000 * (ticks) / CONFIG_LIB_TMGR_FQ) +#define tmgr_ticks_to_s(ticks) ((ticks) / CONFIG_LIB_TMGR_FQ) +#define tmgr_us_to_ticks(us) ((us) * CONFIG_LIB_TMGR_FQ / 1000000U) +#define tmgr_ms_to_ticks(ms) ((ms) * CONFIG_LIB_TMGR_FQ / 1000) +#define tmgr_s_to_ticks(s) ((s) * CONFIG_LIB_TMGR_FQ) + +#define tmgr_get_fq() CONFIG_LIB_TMGR_FQ + +/* Timer initializer macros. + * Creates right structure for timer and fill it + */ +#define TMGR_TIMER_INIT(_function, _data, _expires) { .expires = (_expires), .func = (_function), .data = (_data) } +#define TMGR_DEFINE_TIMER(_name, _function, _data, _expires) tmgr_timer_t _name = TMGR_TIMER_INIT(_function, _data, _expires) +#define TMGR_SETUP_TIMER(_timer, _function, _data, _expires) _timer.func = (_function); _timer.data = (_data); _timer.expires = (_expires) + +#define TMGR_DELAYED(delay) (tmgr_get_uptime() + delay) + +/* Timers are making doubly-linked list, it's good for + * fast search and removal of timer object. + */ +typedef struct struct_tmgr_timer_t { + tmgr_uptime_t expires; + void (*func)(uint8_t *); + uint8_t *data; + + struct struct_tmgr_timer_t *next; + struct struct_tmgr_timer_t *prev; +} tmgr_timer_t; + +void tmgr_process(void); +void tmgr_interrupt(void); + +void tmgr_add_timer(tmgr_timer_t *timer); +void tmgr_mod_timer(tmgr_timer_t *timer, tmgr_uptime_t expires); +void tmgr_del_timer(tmgr_timer_t *timer); + +tmgr_uptime_t tmgr_get_uptime(void); +void tmgr_delay(tmgr_uptime_t time); + +#endif diff --git a/src/lib/kcnf b/src/lib/kcnf index 4ee5168..b121490 100644 --- a/src/lib/kcnf +++ b/src/lib/kcnf @@ -27,8 +27,31 @@ if LIB_ANTARES_CORE help Enables initcall debugging to system console - config LIB_TMGR - bool "Simple cron and uptime counter [NEEDS REWORK]" + menuconfig LIB_PRINTK + bool "printk and dbg() macro support [NEEDS REWORK]" + + if LIB_PRINTK + + config LIB_PRINTK_TIMESTAMP + depends on LIB_TMGR_UPTIME && LIB_PRINTK + bool "Add an uptime timestamp to printks" + + config LIB_PRINTK_PREFIX + depends on LIB_PRINTK + bool "Add a prefix to all printks" + + config LIB_PRINTK_PREFIX_V + depends on LIB_PRINTK_PREFIX + string "Prefix" + + endif + + menuconfig LIB_TMGR + bool "Simple cron and uptime counter [NEEDS TESTING]" + + if LIB_TMGR + source "antares/src/lib/ulc/kcnf" + endif endif diff --git a/src/lib/ulc/kcnf b/src/lib/ulc/kcnf new file mode 100644 index 0000000..217572e --- /dev/null +++ b/src/lib/ulc/kcnf @@ -0,0 +1,16 @@ +config LIB_TMGR_FQ + int "Scheduler timer frequecy (in Hz)" + default 1000 + +choice + prompt "Time variable size" + help + Size of tmgr_time_t type (signed integer) + + config LIB_TMGR_TIME_32 + bool "32 bit" + + config LIB_TMGR_TIME_64 + bool "64 bit" + +endchoice diff --git a/src/lib/ulc/tmgr.c b/src/lib/ulc/tmgr.c index 67074ce..17d7864 100644 --- a/src/lib/ulc/tmgr.c +++ b/src/lib/ulc/tmgr.c @@ -1,123 +1,171 @@ -#include +#include +static volatile tmgr_uptime_t sys_uptime = 0; +static volatile uint8_t tick_parsed = 0; -static volatile unsigned int uptime = 0; -static volatile unsigned int rate = 0; -static int num_handlers = 0; -static handler_t * first = 0; +/* Dirty-hack, but saves memory and runs on each platworm. + * We will use pointers to the two previous vars for + * "flag" pointers to check if timer list element is in + * main queue or in fast queue (or NULL if is not in queue) + */ +#define IN_MAIN (tmgr_timer_t *) (&sys_uptime) +#define IN_FAST (tmgr_timer_t *) (&tick_parsed) -void tmgr_msleep(unsigned int time) +static volatile tmgr_timer_t *fast_queue = NULL; +static volatile tmgr_timer_t *main_queue = NULL; + +/** + * @section Task Manager core + * @{ + */ + +void tmgr_interrupt(void) { - unsigned int end = uptime + time; - while ( uptime < end );; + sys_uptime++; + tick_parsed = 0; } -void tmgr_set_rate(unsigned int nrate) +void tmgr_process(void) { - rate = nrate; - /* TODO: Reschedule pending tasks based on new rate */ + if (tick_parsed) /* this is to save time for interrupts if we had just parsed queues */ + return; + + /* Full function is atomic; accept it as it is */ + ANTARES_DISABLE_IRQS(); + + /* Check fast queue */ + if (fast_queue != NULL) { + /* Save fast_queue list and make it ready for next timers. + * Also, prepare main_queue for insertions. + */ + tmgr_timer_t *fast = (tmgr_timer_t *) fast_queue, + *current = (tmgr_timer_t *) main_queue, + *previous = NULL; + + fast_queue = NULL; + + while (fast != NULL) { + while (current != NULL && current->expires < fast->expires) { + previous = current; + current = current->next; + } + + if (!previous) { /* if new element is root */ + main_queue = fast; + fast->prev = IN_MAIN; + + fast = fast->next; /* shift fast queue */ + + main_queue->next = current; + + if (current) + current->prev = (tmgr_timer_t *) main_queue; + + } else { /* new element is NOT root */ + previous->next = fast; + fast->prev = previous; + + fast = fast->next; /* shift fast queue */ + + if (current) { /* if our element is NOT last */ + previous->next->next = current; + current->prev = previous->next; + } else { /* if our element IS last */ + previous->next->next = NULL; + } + + } + + current = (tmgr_timer_t *) main_queue; + previous = NULL; + } + } + + /* Run main queue tasks */ + if (main_queue != NULL) { + while (main_queue != NULL && main_queue->expires <= sys_uptime) { + tmgr_timer_t *current = (tmgr_timer_t *) main_queue; + main_queue = main_queue->next; + + void (*func)(uint8_t *) = current->func; + uint8_t *data = current->data; + current->prev = NULL; + current->next = NULL; + + if (main_queue) + main_queue->prev = IN_MAIN; /* dummy pointer-flag */ + + ANTARES_ENABLE_IRQS(); /* run of timer function is no atomic, save interrupts! */ + func(data); + ANTARES_DISABLE_IRQS(); + } + } + ANTARES_ENABLE_IRQS(); } -unsigned int tmgr_get_uptime() +void tmgr_add_timer(tmgr_timer_t *timer) { - return uptime; + if (!timer) + return; + + /* these lines are atomic */ + /* TODO!!! REPLACE WITH ANTARES_ATOMIC() {} TO SAVE STATE! */ + ANTARES_DISABLE_IRQS(); + timer->next = (tmgr_timer_t *) fast_queue; + timer->prev = IN_FAST; /* set flag that this timer in fast queue */ + + if (fast_queue) + fast_queue->prev = timer; + + fast_queue = timer; + ANTARES_ENABLE_IRQS(); } -int tmgr_register(handler_t * data) +void tmgr_del_timer(tmgr_timer_t *timer) { - // 0. The most simplest case - too late to run handler - if(data->uptime < uptime) return TIME_OVER; - // 1. The simplest case - no handlers. So, let's add the first one - if(num_handlers == 0) - { - first = data; - } - // 2. The second case - there is only 1 handler. - else if(num_handlers == 1) - { - #ifdef REM_HANDLER_IF_DEFINED - if(first->handler == data->handler) // if this handler has been registered before - { - first->uptime = data->uptime; - return; - } - #endif - if(first->uptime > data->uptime) first->next = data; - else - { - data->next = first; - first = data; + if (!timer) + return; + + /* these lines are atomic */ + /* TODO!!! REPLACE WITH ANTARES_ATOMIC TO SAVE STATE! */ + ANTARES_DISABLE_IRQS(); + if (timer->prev == IN_MAIN) { + main_queue = timer->next; + if (main_queue) + main_queue->prev = IN_MAIN; + } else if (timer->prev == IN_FAST) { + fast_queue = timer->next; + if (fast_queue) + fast_queue->prev = IN_FAST; + } else if (timer->prev) { + timer->prev->next = timer->next; } - } - // 3. There are many handlers - run sorting algorythm - else - { - int i = num_handlers; - handler_t * current = first; - handler_t * prev = 0; - - while(i != 0) - { - #ifdef REM_HANDLER_IF_DEFINED - if(current->handler == data->handler) // remove this handler if registered - { - if(prev == 0) first = first->next; - else prev->next = current->next; - num_handlers--; - } - #endif - if(current->uptime <= data->uptime) - { - data->next = current; - if(prev == 0) first = data; - else prev->next = data; - i++; - break; - } - prev = current; - current = current->next; - i--; - } - if(i==0) prev->next = data; - #ifdef REM_HANDLER_IF_DEFINED - else - { - while(i != 0) - { - if(current->handler == data->handler) - { - prev->next = current->next; - num_handlers--; - break; - } - prev = current; - current = current->next; - i--; - } - } - #endif - } + ANTARES_ENABLE_IRQS(); +} + +void tmgr_mod_timer(tmgr_timer_t *timer, tmgr_uptime_t expires) +{ + if (!timer) + return; - num_handlers++; - return 0; + /* these lines are atomic */ + /* TODO!!! REPLACE WITH ANTARES_ATOMIC() {} TO SAVE STATE! */ + ANTARES_DISABLE_IRQS(); + tmgr_del_timer(timer); + timer->expires = expires; + tmgr_add_timer(timer); + ANTARES_ENABLE_IRQS(); } -void tmgr_tick(void) +tmgr_uptime_t tmgr_get_uptime(void) { - int i = num_handlers; - handler_t * current = first; - while(i != 0) - { - if(current->uptime == uptime) - { - current->handler(); - } - else if(current->uptime < uptime) break; + return sys_uptime; +} - current = current->next; - i--; - } - num_handlers -= i; - uptime++; +void tmgr_delay(tmgr_uptime_t time) +{ + time += sys_uptime; + while (time > sys_uptime) + asm volatile ("nop"); }