├── README.md ├── example_board.h ├── example_em_config_task.h ├── port ├── cortex-m3 │ ├── em_port.c │ └── em_port.h └── cortex-m4 │ ├── em_port.c │ └── em_port.h └── src ├── em_event.c ├── em_event.h ├── em_heap.c ├── em_heap.h ├── em_list.c ├── em_list.h ├── em_mutex.c ├── em_mutex.h ├── em_queue.c ├── em_queue.h ├── em_sem.c ├── em_sem.h ├── em_task.c ├── em_task.h ├── em_timer_task.c ├── em_timer_task.h └── task_include.h /README.md: -------------------------------------------------------------------------------- 1 | # EmTask 2 | -------------------------------------------------------------------------------- /example_board.h: -------------------------------------------------------------------------------- 1 | #ifndef _BOARD_H_ 2 | #define _BOARD_H_ 3 | 4 | #include "main.h" 5 | #include "xconfig.h" 6 | #include "debug_deb.h" 7 | #define BOARD_MCK (84000000UL) 8 | 9 | enum { 10 | __PRI_TASK_TEST = 1, 11 | __PRI_TASK_LCD = 2, 12 | __PRI_TASK_WS2815 = 3, 13 | //-------------- 14 | __PRI_MAX 15 | }; 16 | 17 | #ifndef sizeof_m 18 | #define sizeof_m(a) (sizeof(a)/sizeof((a)[0])) 19 | #endif 20 | 21 | #endif /* _BOARD_H_ */ 22 | -------------------------------------------------------------------------------- /example_em_config_task.h: -------------------------------------------------------------------------------- 1 | // 2 | // Author: Shipaev Ivan Vladimirovich 3 | // iva_n_@mail.ru 4 | 5 | #ifndef _EM_CONFIG_TASK_H_ 6 | #define _EM_CONFIG_TASK_H_ 7 | 8 | #include "board.h" 9 | 10 | #define EM_MIN(a, b) ((a) < (b) ? (a) : (b)) 11 | #define EM_MAX(a, b) ((a) > (b) ? (a) : (b)) 12 | #define EM_TIM_INFINITY (~0) 13 | #define EM_MAX_UNSIGNED_VALUE (~0) 14 | 15 | #define ALLIGN_LEAST(size, allign) ((size) & ~((allign) - 1)) 16 | #define ALLIGN_LARGEST(size, allign) (((size) + (allign) - 1) & ~((allign) - 1)) 17 | 18 | #ifdef __NVIC_PRIO_BITS 19 | #define configPRIO_BITS __NVIC_PRIO_BITS 20 | #else 21 | #define configPRIO_BITS 4 22 | #endif 23 | 24 | #define cfgLIB_LOW_PRI 0x0f 25 | #define cfgLIB_MAX_PRI 10 26 | 27 | #define cfgSIZE_STACK_IDLE_TASK 130 28 | #define cfgNUM_PRI __PRI_MAX 29 | #define cfgMEM_ALLIGN 8 30 | #define cfgSIZE_HEAP_BUF (1024*40UL) 31 | #define cfgCPU_CLOCK_HZ ( BOARD_MCK ) 32 | #define cfgTICK_RATE_HZ ( 1000 ) 33 | #define cfgLEN_TASK_NAME 16 34 | #define cfgUSE_IDLE_HOOK 0 35 | #define cfgUSE_SYSTIC_HOOK 0 36 | #define cfgSTATIC_SYSTEM_TASK 0 37 | #define cfgUSE_TIMER_TASK 1 38 | #define cfgUSE_ASSERT 1 39 | #define EM_PRINTF(...) DEB_PRINTF(DEBUG_ROOT, __VA_ARGS__) 40 | #define cfgTEST_SP_SWITCH_TASK 0 41 | #define cfgFILL_SP 0x55555555 42 | // Timer task 43 | #if cfgUSE_TIMER_TASK 44 | #define cfgSIZE_STACK_TIMER_TASK 256 45 | #define cfgPRI_TIMER_TASK (cfgNUM_PRI-1) 46 | #define cfgSTATIC_TIMER_TASK 0 47 | #endif 48 | 49 | #if (cfgUSE_ASSERT) 50 | void __em_assert_func(char* file, unsigned line); 51 | #define EM_ASSERT(a) ((a) ? (void)0 : __em_assert_func((char*)__func__, __LINE__)) 52 | #endif 53 | 54 | #endif /* _EM_CONFIG_TASK_H_ */ 55 | -------------------------------------------------------------------------------- /port/cortex-m3/em_port.c: -------------------------------------------------------------------------------- 1 | // 2 | // Author: Shipaev Ivan Vladimirovich 3 | // iva_n_@mail.ru 4 | 5 | #define _EM_TASK_PRIVATE_ 6 | #include "task_include.h" 7 | 8 | #define portNVIC_SYSPRI2 ((volatile unsigned*)0xe000ed20) 9 | #define portNVIC_PENDSV_PRI (cfgKERNEL_LOW_PRI << 16) 10 | #define portNVIC_SYSTICK_PRI (cfgKERNEL_LOW_PRI << 24) 11 | 12 | #define portNVIC_INT_CTRL ((volatile unsigned*)0xe000ed04) 13 | #define portNVIC_PENDSVSET (0x10000000) 14 | 15 | static unsigned count_critical_task = 0x7fffffff; 16 | static unsigned count_critical_irq = 0x7fffffff; 17 | 18 | //------------------------------------------------------------- 19 | // Interrupt functions 20 | //------------------------------------------------------------- 21 | void SVC_Handler(void); 22 | void PendSV_Handler(void); 23 | void SysTick_Handler(void); 24 | //------------------------------------------------------------- 25 | // Disable/enable systems priority ISR 26 | //------------------------------------------------------------- 27 | void EM_DISABLE_TASK(void) 28 | { 29 | __set_BASEPRI(cfgKERNEL_MAX_PRI); 30 | count_critical_task++; 31 | } 32 | void EM_ENABLE_TASK(void) 33 | { 34 | if ((count_critical_task == 0) || (--count_critical_task == 0)) 35 | __set_BASEPRI(0); 36 | } 37 | //------------------------------------------------------------- 38 | // Disable/enable systems all systems ISR 39 | //------------------------------------------------------------- 40 | void EM_DISABLE_ISR(void) 41 | { 42 | __disable_irq(); 43 | ++count_critical_irq; 44 | } 45 | void EM_ENABLE_ISR(void) 46 | { 47 | if ((count_critical_irq == 0) || (--count_critical_irq == 0)) 48 | __enable_irq(); 49 | } 50 | //-------------------------------------------------------------- 51 | //-------------------------------------------------------------- 52 | unsigned* rt_em_port_init_stack(unsigned* sp, unsigned size_sp, 53 | void (*start_func)(void*), void* par, void (*exit_func)(void)) 54 | { 55 | // Initialization stack 56 | for (int i = 0; i < size_sp; i++) 57 | *sp++ = cfgFILL_SP; 58 | --sp; 59 | *sp = 0x01000000; // xPSR 60 | --sp; 61 | *sp = (unsigned) start_func; 62 | --sp; 63 | *sp = (unsigned) exit_func; // LR 64 | sp -= 5; // R12, R3, R2, R1 65 | *sp = (unsigned) par; // R0 66 | sp -= 8; // R11, R10, R9, R8, R7, R6, R5, R4 67 | *sp = 0; 68 | return sp; 69 | } 70 | //-------------------------------------------------------------- 71 | static void __port_init_sys_timer(void) 72 | { 73 | if (SysTick_Config(cfgCPU_CLOCK_HZ / cfgTICK_RATE_HZ)) 74 | while (1); 75 | } 76 | //-------------------------------------------------------------- 77 | static void __rt_em_port_start_first_task(void) 78 | { 79 | __asm volatile 80 | ( 81 | " ldr r0, =0xE000ED08 \n" 82 | " ldr r0, [r0] \n" 83 | " ldr r0, [r0] \n" 84 | " msr msp, r0 \n" 85 | " cpsie i \n" 86 | " cpsie f \n" 87 | " svc 0 \n" 88 | " nop \n" 89 | ); 90 | } 91 | //-------------------------------------------------------------- 92 | void rt_em_port_start_first_task(void) 93 | { 94 | count_critical_task = 0; 95 | count_critical_irq = 0; 96 | __port_init_sys_timer(); 97 | *(portNVIC_SYSPRI2) |= portNVIC_PENDSV_PRI; 98 | *(portNVIC_SYSPRI2) |= portNVIC_SYSTICK_PRI; 99 | __rt_em_port_start_first_task(); 100 | } 101 | //-------------------------------------------------------------- 102 | //-------------------------------------------------------------- 103 | //-------------------------------------------------------------- 104 | // ISR 105 | //-------------------------------------------------------------- 106 | // SVC ISR 107 | //-------------------------------------------------------------- 108 | void SVC_Handler(void) 109 | { 110 | __asm volatile 111 | ( 112 | " ldr r3, =ctask \n" 113 | " ldr r1, [r3] \n" 114 | " ldr r0, [r1] \n" 115 | " ldmia r0!, {r4-r11} \n" 116 | " msr psp, r0 \n" 117 | " mov r0, #0 \n" 118 | " msr basepri, r0 \n" 119 | " orr r14, r14, #13 \n" 120 | " bx r14 \n" 121 | ); 122 | } 123 | //-------------------------------------------------------------- 124 | // PendSV ISR 125 | //-------------------------------------------------------------- 126 | void PendSV_Handler(void) 127 | { 128 | __asm volatile 129 | ( 130 | " mrs r0, psp \n" 131 | 132 | " ldr r3, =ctask \n" // Get SP for current task 133 | " ldr r2, [r3] \n" // Get stack 134 | 135 | " stmdb r0!, {r4-r11} \n" // Save registers 136 | " str r0, [r2] \n" 137 | 138 | " stmdb sp!, {r3, r14} \n" 139 | " mov r0, %0 \n" // Up base priority 140 | " msr basepri, r0 \n" 141 | " bl rt_em_switch_context \n" // Change task 142 | " mov r0, #0 \n" 143 | " msr basepri, r0 \n" // Down base priority 144 | " ldmia sp!, {r3, r14} \n" 145 | 146 | " ldr r1, [r3] \n" // Get SP for current task 147 | " ldr r0, [r1] \n" 148 | 149 | " ldmia r0!, {r4-r11} \n" // Load registers 150 | 151 | " msr psp, r0 \n" 152 | " bx r14 \n" 153 | :: "i" (cfgKERNEL_MAX_PRI) 154 | ); 155 | } 156 | //-------------------------------------------------------------- 157 | // System timer ISR 158 | //-------------------------------------------------------------- 159 | void SysTick_Handler(void) 160 | { 161 | rt_em_isr_system_tic(); 162 | } 163 | //-------------------------------------------------------------- 164 | int rt_em_find_first_bit(int value) 165 | { 166 | __asm volatile ( "clz %0, %0" : "=r" (value) ); 167 | return 31 - value; 168 | } 169 | //-------------------------------------------------------------- 170 | #if cfgTEST_SP_SWITCH_TASK 171 | void rt_em_port_test_sp_switch_task(void) 172 | { 173 | extern void EM_TEST_SP_SWITCH_HOOK(const char* task_name); 174 | unsigned* p = ctask->sp_start; 175 | if (ctask->sp < &p[20]) { 176 | EM_TEST_SP_SWITCH_HOOK(ctask->name); 177 | while (1) 178 | ; 179 | } else { 180 | for (int i = 0; i < 20; i++) { 181 | if (p[i] != cfgFILL_SP) { 182 | EM_TEST_SP_SWITCH_HOOK(ctask->name); 183 | while (1) 184 | ; 185 | } 186 | } 187 | } 188 | } 189 | #endif /* cfgTEST_SP_SWITCH_TASK */ 190 | //-------------------------------------------------------------- 191 | void rt_em_port_request_switch_context(void) 192 | { 193 | *(portNVIC_INT_CTRL) = portNVIC_PENDSVSET; 194 | } 195 | //-------------------------------------------------------------- 196 | void rt_em_port_test_sp(em_list_t* list_task) 197 | { 198 | int len; 199 | unsigned* p; 200 | em_task_t *task; 201 | em_list_t *lst; 202 | 203 | EM_PRINTF("****************Test SP****************\r\n"); 204 | lst = list_task->next; 205 | while (lst != list_task) { 206 | task = rt_em_get_struct_by_field(lst, em_task_t, init_list); 207 | for (p = task->sp_start; p < task->sp_start + task->sp_size; p++) 208 | if (*p != cfgFILL_SP) 209 | break; 210 | len = p - task->sp_start; 211 | EM_PRINTF("Task %s: sp %d state %d pri %d\r\n", task->name, len, 212 | task->state, task->pri); 213 | lst = lst->next; 214 | } 215 | EM_PRINTF("Free Heap space %u\r\n", em_heap_get_free_space()); 216 | EM_PRINTF("***************************************\r\n"); 217 | } 218 | -------------------------------------------------------------------------------- /port/cortex-m3/em_port.h: -------------------------------------------------------------------------------- 1 | // 2 | // Author: Shipaev Ivan Vladimirovich 3 | // iva_n_@mail.ru 4 | 5 | #ifndef _PORT_H_ 6 | #define _PORT_H_ 7 | 8 | #define cfgKERNEL_LOW_PRI (cfgLIB_LOW_PRI << (8 - configPRIO_BITS)) 9 | #define cfgKERNEL_MAX_PRI (cfgLIB_MAX_PRI << (8 - configPRIO_BITS)) 10 | 11 | void EM_DISABLE_TASK(void); 12 | void EM_ENABLE_TASK(void); 13 | void EM_DISABLE_ISR(void); 14 | void EM_ENABLE_ISR(void); 15 | 16 | #ifdef _EM_TASK_PRIVATE_ 17 | 18 | void rt_em_port_start_first_task(void); 19 | unsigned* rt_em_port_init_stack(unsigned* sp, unsigned size_sp, void (*start_func) (void*), 20 | void* par, void (*exit_func) (void)); 21 | int rt_em_find_first_bit(int val); 22 | void rt_em_port_request_switch_context(void); 23 | void rt_em_port_test_sp(em_list_t* list_task); 24 | 25 | #endif /* _EM_TASK_PRIVATE_ */ 26 | 27 | #endif /*_PORT_H_*/ 28 | -------------------------------------------------------------------------------- /port/cortex-m4/em_port.c: -------------------------------------------------------------------------------- 1 | // 2 | // Author: Shipaev Ivan Vladimirovich 3 | // iva_n_@mail.ru 4 | 5 | #define _EM_TASK_PRIVATE_ 6 | #include "task_include.h" 7 | 8 | #ifndef __VFP_FP__ 9 | #error Error - Hardware floating point support not enable. 10 | #endif 11 | 12 | #define portNVIC_SYSPRI2 ((volatile unsigned*)0xe000ed20) 13 | #define portNVIC_PENDSV_PRI (cfgKERNEL_LOW_PRI << 16) 14 | #define portNVIC_SYSTICK_PRI (cfgKERNEL_LOW_PRI << 24) 15 | 16 | #define portNVIC_INT_CTRL ((volatile unsigned*)0xe000ed04) 17 | #define portNVIC_PENDSVSET (0x10000000) 18 | 19 | // FPU 20 | #define portFPU_CPACR ((volatile unsigned*)0xe000ed88) 21 | #define portFPU_FPCCR ((volatile unsigned*)0xe000ef34) 22 | 23 | static unsigned count_critical_task = 0x7fffffff; 24 | static unsigned count_critical_irq = 0x7fffffff; 25 | 26 | //------------------------------------------------------------- 27 | // Interrupt functions 28 | //------------------------------------------------------------- 29 | void SVC_Handler(void); 30 | void PendSV_Handler(void); 31 | void SysTick_Handler(void); 32 | //------------------------------------------------------------- 33 | // Disable/enable systems priority ISR 34 | //------------------------------------------------------------- 35 | void EM_DISABLE_TASK(void) 36 | { 37 | __set_BASEPRI(cfgKERNEL_MAX_PRI); 38 | count_critical_task++; 39 | } 40 | void EM_ENABLE_TASK(void) 41 | { 42 | if ((count_critical_task == 0) || (--count_critical_task == 0)) 43 | __set_BASEPRI(0); 44 | } 45 | //------------------------------------------------------------- 46 | // Disable/enable systems all systems ISR 47 | //------------------------------------------------------------- 48 | void EM_DISABLE_ISR(void) 49 | { 50 | __disable_irq(); 51 | ++count_critical_irq; 52 | } 53 | void EM_ENABLE_ISR(void) 54 | { 55 | if ((count_critical_irq == 0) || (--count_critical_irq == 0)) 56 | __enable_irq(); 57 | } 58 | //-------------------------------------------------------------- 59 | //-------------------------------------------------------------- 60 | unsigned* rt_em_port_init_stack(unsigned* sp, unsigned size_sp, 61 | void (*start_func)(void*), void* par, void (*exit_func)(void)) 62 | { 63 | // Initialization stack 64 | for (int i = 0; i < size_sp; i++) 65 | *sp++ = cfgFILL_SP; 66 | --sp; 67 | *sp = 0x01000000; // xPSR 68 | --sp; 69 | *sp = (unsigned) start_func; 70 | --sp; 71 | *sp = (unsigned) exit_func; // LR 72 | sp -= 5; // R12, R3, R2, R1 73 | *sp = (unsigned) par; // R0 74 | --sp; 75 | *sp = 0xfffffffd; // FPU register not used by this context 76 | sp -= 8; // R11, R10, R9, R8, R7, R6, R5, R4 77 | *sp = 0; 78 | return sp; 79 | } 80 | //-------------------------------------------------------------- 81 | static void __port_init_sys_timer(void) 82 | { 83 | if (SysTick_Config(cfgCPU_CLOCK_HZ / cfgTICK_RATE_HZ)) 84 | while (1); 85 | } 86 | //-------------------------------------------------------------- 87 | static void __rt_em_port_start_first_task(void) 88 | { 89 | __asm volatile 90 | ( 91 | " ldr r0, =0xE000ED08 \n" 92 | " ldr r0, [r0] \n" 93 | " ldr r0, [r0] \n" 94 | " msr msp, r0 \n" 95 | 96 | " mov r0, #0 \n" // Clear bit FPU is in use 97 | " msr control, r0 \n" 98 | 99 | " cpsie i \n" 100 | " cpsie f \n" 101 | " svc 0 \n" 102 | " nop \n" 103 | ); 104 | } 105 | //-------------------------------------------------------------- 106 | void rt_em_port_start_first_task(void) 107 | { 108 | count_critical_task = 0; 109 | count_critical_irq = 0; 110 | __port_init_sys_timer(); 111 | *(portNVIC_SYSPRI2) |= portNVIC_PENDSV_PRI; 112 | *(portNVIC_SYSPRI2) |= portNVIC_SYSTICK_PRI; 113 | 114 | // Enable CP10 and CP11 115 | *(portFPU_CPACR) |= 0x0fUL << 20; 116 | // Set ASPEN and LSPEN bits 117 | *(portFPU_FPCCR) |= 0x03UL << 30; 118 | 119 | __rt_em_port_start_first_task(); 120 | } 121 | //-------------------------------------------------------------- 122 | //-------------------------------------------------------------- 123 | //-------------------------------------------------------------- 124 | // ISR 125 | //-------------------------------------------------------------- 126 | // SVC ISR 127 | //-------------------------------------------------------------- 128 | void SVC_Handler(void) 129 | { 130 | __asm volatile 131 | ( 132 | " ldr r3, =ctask \n" 133 | " ldr r1, [r3] \n" 134 | " ldr r0, [r1] \n" 135 | " ldmia r0!, {r4-r11, r14} \n" 136 | " msr psp, r0 \n" 137 | " mov r0, #0 \n" 138 | " msr basepri, r0 \n" 139 | " bx r14 \n" 140 | ); 141 | } 142 | //-------------------------------------------------------------- 143 | // PendSV ISR 144 | //-------------------------------------------------------------- 145 | void PendSV_Handler(void) 146 | { 147 | __asm volatile 148 | ( 149 | " mrs r0, psp \n" 150 | 151 | " ldr r3, =ctask \n" // Get SP for current task 152 | " ldr r2, [r3] \n" // Get stack 153 | 154 | " tst r14, #0x10 \n" // Is using FPU context? 155 | " it eq \n" 156 | " vstmdbeq r0!, {s16-s31} \n" // Save FPU context 157 | 158 | " stmdb r0!, {r4-r11, r14} \n" // Save registers 159 | " str r0, [r2] \n" 160 | 161 | " stmdb sp!, {r3} \n" 162 | " mov r0, %0 \n" // Up base priority 163 | " msr basepri, r0 \n" 164 | " bl rt_em_switch_context \n" // Change task 165 | " mov r0, #0 \n" 166 | " msr basepri, r0 \n" // Down base priority 167 | " ldmia sp!, {r3} \n" 168 | 169 | " ldr r1, [r3] \n" // Get SP for current task 170 | " ldr r0, [r1] \n" 171 | 172 | " ldmia r0!, {r4-r11, r14} \n" // Load registers 173 | 174 | " tst r14, #0x10 \n" // Is using FPU context? 175 | " it eq \n" 176 | " vldmiaeq r0!, {s16-s31} \n" // Load FPU context 177 | 178 | " msr psp, r0 \n" 179 | " bx r14 \n" 180 | :: "i" (cfgKERNEL_MAX_PRI) 181 | ); 182 | } 183 | //-------------------------------------------------------------- 184 | // System timer ISR 185 | //-------------------------------------------------------------- 186 | void SysTick_Handler(void) 187 | { 188 | rt_em_isr_system_tic(); 189 | } 190 | //-------------------------------------------------------------- 191 | int rt_em_find_first_bit(int value) 192 | { 193 | __asm volatile ( "clz %0, %0" : "=r" (value) ); 194 | return 31 - value; 195 | } 196 | //-------------------------------------------------------------- 197 | #if cfgTEST_SP_SWITCH_TASK 198 | void rt_em_port_test_sp_switch_task(void) 199 | { 200 | extern void EM_TEST_SP_SWITCH_HOOK(const char* task_name); 201 | unsigned* p = ctask->sp_start; 202 | if (ctask->sp < &p[20]) { 203 | EM_TEST_SP_SWITCH_HOOK(ctask->name); 204 | while (1) 205 | ; 206 | } else { 207 | for (int i = 0; i < 20; i++) { 208 | if (p[i] != cfgFILL_SP) { 209 | EM_TEST_SP_SWITCH_HOOK(ctask->name); 210 | while (1) 211 | ; 212 | } 213 | } 214 | } 215 | } 216 | #endif /* cfgTEST_SP_SWITCH_TASK */ 217 | //-------------------------------------------------------------- 218 | void rt_em_port_request_switch_context(void) 219 | { 220 | *(portNVIC_INT_CTRL) = portNVIC_PENDSVSET; 221 | } 222 | //-------------------------------------------------------------- 223 | void rt_em_port_test_sp(em_list_t* list_task) 224 | { 225 | int len; 226 | unsigned* p; 227 | em_task_t *task; 228 | em_list_t *lst; 229 | 230 | EM_PRINTF("****************Test SP****************\r\n"); 231 | lst = list_task->next; 232 | while (lst != list_task) { 233 | task = rt_em_get_struct_by_field(lst, em_task_t, init_list); 234 | for (p = task->sp_start; p < task->sp_start + task->sp_size; p++) 235 | if (*p != cfgFILL_SP) 236 | break; 237 | len = p - task->sp_start; 238 | EM_PRINTF("Task %s: sp %d state %d pri %d\r\n", task->name, len, 239 | task->state, task->pri); 240 | lst = lst->next; 241 | } 242 | EM_PRINTF("Free Heap space %u\r\n", em_heap_get_free_space()); 243 | EM_PRINTF("***************************************\r\n"); 244 | } 245 | -------------------------------------------------------------------------------- /port/cortex-m4/em_port.h: -------------------------------------------------------------------------------- 1 | // 2 | // Author: Shipaev Ivan Vladimirovich 3 | // iva_n_@mail.ru 4 | 5 | #ifndef _PORT_H_ 6 | #define _PORT_H_ 7 | 8 | #define cfgKERNEL_LOW_PRI (cfgLIB_LOW_PRI << (8 - configPRIO_BITS)) 9 | #define cfgKERNEL_MAX_PRI (cfgLIB_MAX_PRI << (8 - configPRIO_BITS)) 10 | 11 | void EM_DISABLE_TASK(void); 12 | void EM_ENABLE_TASK(void); 13 | void EM_DISABLE_ISR(void); 14 | void EM_ENABLE_ISR(void); 15 | 16 | #ifdef _EM_TASK_PRIVATE_ 17 | 18 | void rt_em_port_start_first_task(void); 19 | unsigned* rt_em_port_init_stack(unsigned* sp, unsigned size_sp, void (*start_func) (void*), 20 | void* par, void (*exit_func) (void)); 21 | int rt_em_find_first_bit(int val); 22 | void rt_em_port_request_switch_context(void); 23 | void rt_em_port_test_sp(em_list_t* list_task); 24 | 25 | #endif /* _EM_TASK_PRIVATE_ */ 26 | 27 | #endif /*_PORT_H_*/ 28 | -------------------------------------------------------------------------------- /src/em_event.c: -------------------------------------------------------------------------------- 1 | // 2 | // Author: Shipaev Ivan Vladimirovich 3 | // iva_n_@mail.ru 4 | 5 | #define _EM_TASK_PRIVATE_ 6 | #include "task_include.h" 7 | 8 | static __EM_LIST_INIT(event_init_list); 9 | 10 | //-------------------------------------------------------------- 11 | static inline void rt_em_event_clean(em_event_t* ev, unsigned flags) 12 | { 13 | ev->flags &= ~flags; 14 | } 15 | //-------------------------------------------------------------- 16 | static unsigned rt_em_event_is_set(em_event_t* ev, enum ev_mode mode, 17 | unsigned flags) 18 | { 19 | unsigned ev_flag = ev->flags; 20 | 21 | if (mode & EM_EVENT_MODE_AND) { 22 | if ((ev_flag & flags) == flags) 23 | return flags; 24 | return 0; 25 | } 26 | 27 | return ev_flag & flags; 28 | } 29 | //-------------------------------------------------------------- 30 | int rt_em_event_set(em_event_t* ev, unsigned flags) 31 | { 32 | em_list_t *lst; 33 | em_task_t *task; 34 | unsigned rc; 35 | unsigned fclean = 0; 36 | 37 | if ((ev->flags & flags) != flags) { 38 | ev->flags |= flags; 39 | // Checking tasks in list 40 | lst = ev->wait_list.next; 41 | while (lst != &ev->wait_list) { 42 | task = rt_em_get_task_by_task_list(lst); 43 | lst = lst->next; 44 | rc = rt_em_event_is_set(ev, task->event.mode, task->event.flags); 45 | if (rc) { 46 | if (task->event.mode & EM_EVENT_MODE_CLEAR) 47 | fclean |= rc; 48 | task->event.flags = rc; 49 | rt_em_complete_wait_action(task, EMERR_OK); 50 | } 51 | } 52 | if (fclean) 53 | rt_em_event_clean(ev, fclean); 54 | rt_em_scheduler(); 55 | } 56 | 57 | return EMERR_OK; 58 | } 59 | //-------------------------------------------------------------- 60 | // Get event initialization list 61 | //-------------------------------------------------------------- 62 | em_list_t* rt_em_get_event_init_list(void) 63 | { 64 | return &event_init_list; 65 | } 66 | //-------------------------------------------------------------- 67 | // Initialization 68 | //-------------------------------------------------------------- 69 | void em_event_init(em_event_t* ev) 70 | { 71 | EM_ASSERT(ev != NULL); 72 | 73 | EM_DISABLE_TASK(); 74 | 75 | ev->flags = 0; 76 | rt_em_list_clear(&ev->wait_list); 77 | rt_em_list_add_tail(&event_init_list, &ev->init_list); 78 | 79 | EM_ENABLE_TASK(); 80 | } 81 | //-------------------------------------------------------------- 82 | // De-initialization 83 | //-------------------------------------------------------------- 84 | void em_event_deinit(em_event_t* ev) 85 | { 86 | em_task_t* task; 87 | 88 | EM_ASSERT(ev != NULL); 89 | 90 | EM_DISABLE_TASK(); 91 | 92 | while (rt_em_is_list_empty(&ev->wait_list) == 0) { 93 | task = rt_em_get_task_by_task_list(ev->wait_list.next); 94 | rt_em_complete_wait_action(task, EMERR_DEINIT); 95 | } 96 | rt_em_list_remove_entry(&ev->init_list); 97 | rt_em_scheduler(); 98 | 99 | EM_ENABLE_TASK(); 100 | } 101 | //-------------------------------------------------------------- 102 | // Create 103 | //-------------------------------------------------------------- 104 | em_event_t* em_event_new(void) 105 | { 106 | em_event_t* ev = em_malloc(sizeof(em_event_t)); 107 | 108 | if (ev) 109 | em_event_init(ev); 110 | 111 | return ev; 112 | } 113 | //-------------------------------------------------------------- 114 | // Delete 115 | //-------------------------------------------------------------- 116 | void em_event_delete(em_event_t* ev) 117 | { 118 | EM_ASSERT(ev != NULL); 119 | 120 | em_event_deinit(ev); 121 | em_free(ev); 122 | } 123 | //-------------------------------------------------------------- 124 | // Test 125 | //-------------------------------------------------------------- 126 | unsigned em_event_is_set(em_event_t* ev, enum ev_mode mode, unsigned flags) 127 | { 128 | unsigned rc; 129 | 130 | EM_DISABLE_TASK(); 131 | 132 | rc = rt_em_event_is_set(ev, mode, flags); 133 | 134 | EM_ENABLE_TASK(); 135 | 136 | return rc; 137 | } 138 | //-------------------------------------------------------------- 139 | // Wait 140 | //-------------------------------------------------------------- 141 | int em_event_wait(em_event_t* ev, enum ev_mode mode, unsigned flags, 142 | unsigned timeout, unsigned* value) 143 | { 144 | unsigned rc; 145 | 146 | EM_DISABLE_TASK(); 147 | 148 | if ((mode & EM_EVENT_MODE_AND) == 0) 149 | mode |= EM_EVENT_MODE_OR; 150 | 151 | rc = rt_em_event_is_set(ev, mode, flags); 152 | if (rc) { 153 | if (mode & EM_EVENT_MODE_CLEAR) 154 | rt_em_event_clean(ev, rc); 155 | EM_ENABLE_TASK(); 156 | return EMERR_OK; 157 | } else if (timeout == 0) { 158 | EM_ENABLE_TASK(); 159 | return EMERR_TIMEOUT; 160 | } 161 | 162 | EM_ASSERT(rt_em_scheduler_is_enable()); 163 | 164 | // TASK 165 | ctask->event.mode = mode; 166 | ctask->event.flags = flags; 167 | ctask->error = EMERR_TIMEOUT; 168 | rt_em_add_wait_action(ctask, ev, &ev->wait_list, _S_WAIT_EVENT, timeout); 169 | rt_em_scheduler(); 170 | 171 | EM_ENABLE_TASK(); 172 | 173 | if (ctask->error == EMERR_OK && value) 174 | *value = ctask->event.flags; 175 | 176 | return ctask->error; 177 | } 178 | //-------------------------------------------------------------- 179 | // Set 180 | //-------------------------------------------------------------- 181 | int em_event_set(em_event_t* ev, unsigned flags) 182 | { 183 | int rc; 184 | 185 | EM_ASSERT(ev != NULL); 186 | 187 | EM_DISABLE_TASK(); 188 | 189 | rc = rt_em_event_set(ev, flags); 190 | 191 | EM_ENABLE_TASK(); 192 | 193 | return rc; 194 | } 195 | //-------------------------------------------------------------- 196 | // Clean 197 | //-------------------------------------------------------------- 198 | int em_event_clean(em_event_t* ev, unsigned flags) 199 | { 200 | EM_ASSERT(ev != NULL); 201 | 202 | EM_DISABLE_TASK(); 203 | 204 | rt_em_event_clean(ev, flags); 205 | 206 | EM_ENABLE_TASK(); 207 | 208 | return EMERR_OK; 209 | } 210 | //-------------------------------------------------------------- 211 | // Sync 212 | //-------------------------------------------------------------- 213 | int em_event_sync_flags(em_event_t* ev, unsigned flags) 214 | { 215 | unsigned t_flags; 216 | int rc; 217 | 218 | EM_ASSERT(ev != NULL); 219 | 220 | EM_DISABLE_TASK(); 221 | 222 | t_flags = (ev->flags & flags); 223 | rt_em_event_clean(ev, t_flags ^ ev->flags); 224 | rc = rt_em_event_set(ev, t_flags ^ flags); 225 | 226 | EM_ENABLE_TASK(); 227 | 228 | return rc; 229 | } 230 | -------------------------------------------------------------------------------- /src/em_event.h: -------------------------------------------------------------------------------- 1 | // 2 | // Author: Shipaev Ivan Vladimirovich 3 | // iva_n_@mail.ru 4 | 5 | #ifndef _EM_EVENT_H_ 6 | #define _EM_EVENT_H_ 7 | 8 | enum ev_mode 9 | { 10 | EM_EVENT_MODE_OR = (1 << 0), // Test by OR 11 | EM_EVENT_MODE_AND = (1 << 1), // Test by AND 12 | EM_EVENT_MODE_CLEAR = (1 << 2), // Clearing after waiting 13 | }; 14 | 15 | typedef struct _em_event_t 16 | { 17 | em_list_t init_list; 18 | em_list_t wait_list; // Waiting tasks list 19 | unsigned flags; // Flags 20 | } em_event_t; 21 | 22 | void em_event_init(em_event_t* ev); 23 | void em_event_deinit(em_event_t* ev); 24 | em_event_t* em_event_new(void); 25 | void em_event_delete(em_event_t* ev); 26 | int em_event_wait(em_event_t* ev, enum ev_mode mode, unsigned flags, 27 | unsigned timeout, unsigned *value); 28 | //-------------------------------------------------------------- 29 | // These functions can be called both in tasks and in ISR 30 | //-------------------------------------------------------------- 31 | int em_event_set(em_event_t* ev, unsigned flags); 32 | int em_event_clean(em_event_t* ev, unsigned flags); 33 | int em_event_sync_flags(em_event_t* ev, unsigned flags); 34 | unsigned em_event_is_set(em_event_t* ev, enum ev_mode mode, unsigned flags); 35 | 36 | #ifdef _EM_TASK_PRIVATE_ 37 | em_list_t* rt_em_get_event_init_list(void); 38 | static inline em_event_t* rt_em_get_event_by_init_list(em_list_t* list) 39 | { 40 | return rt_em_get_struct_by_field(list, em_event_t, init_list); 41 | } 42 | int rt_em_event_set(em_event_t* ev, unsigned flags); 43 | #endif /* _EM_TASK_PRIVATE_ */ 44 | 45 | #endif /* _EM_EVENT_H_ */ 46 | -------------------------------------------------------------------------------- /src/em_heap.c: -------------------------------------------------------------------------------- 1 | // 2 | // Author: Shipaev Ivan Vladimirovich 3 | // iva_n_@mail.ru 4 | 5 | #define _EM_TASK_PRIVATE_ 6 | #include "task_include.h" 7 | 8 | typedef struct _em_memblc_t 9 | { 10 | struct _em_memblc_t *next; 11 | struct 12 | { 13 | uint32_t size :31; 14 | uint32_t busy :1; 15 | }; 16 | } em_memblc_t; 17 | 18 | #define SIZE_HEAP_BUF ALLIGN_LEAST(cfgSIZE_HEAP_BUF, cfgMEM_ALLIGN) 19 | #define SIZE_STRUCT_HEAP ALLIGN_LARGEST(sizeof(em_memblc_t), cfgMEM_ALLIGN) 20 | 21 | typedef struct _em_heap_t 22 | { 23 | union 24 | { 25 | #if (cfgMEM_ALLIGN == 8) 26 | uint64_t dummy; 27 | #else 28 | uint32_t dummy; 29 | #endif 30 | uint8_t buf[SIZE_HEAP_BUF]; 31 | }; 32 | } em_heap_t; 33 | 34 | static size_t heap_free_size; 35 | static uint8_t heap_finit; 36 | static em_heap_t heap; 37 | 38 | //-------------------------------------------------------------- 39 | // Initialization 40 | //-------------------------------------------------------------- 41 | void em_mem_init(void) 42 | { 43 | em_memblc_t *first = (em_memblc_t*) heap.buf; 44 | first->next = NULL; 45 | first->size = SIZE_HEAP_BUF; 46 | first->busy = 0; 47 | heap_free_size = SIZE_HEAP_BUF; 48 | heap_finit = 1; 49 | } 50 | //-------------------------------------------------------------- 51 | // Malloc 52 | //-------------------------------------------------------------- 53 | void* em_malloc(size_t size) 54 | { 55 | em_memblc_t *cmem, *tmp; 56 | 57 | size = ALLIGN_LARGEST(size + SIZE_STRUCT_HEAP, cfgMEM_ALLIGN); 58 | 59 | em_scheduler_disable(); 60 | 61 | if (!heap_finit) 62 | em_mem_init(); 63 | 64 | cmem = (em_memblc_t*) heap.buf; 65 | 66 | while (cmem) { 67 | if (!cmem->busy && cmem->size >= size) { 68 | if (cmem->size > size + SIZE_STRUCT_HEAP) { 69 | // Dividing into small 70 | tmp = (em_memblc_t*) ((uint8_t*) cmem + size); 71 | tmp->next = cmem->next; 72 | tmp->size = cmem->size - size; 73 | tmp->busy = 0; 74 | cmem->next = tmp; 75 | cmem->size = size; 76 | } 77 | heap_free_size -= cmem->size; 78 | cmem->busy = 1; 79 | break; 80 | } 81 | cmem = cmem->next; 82 | } 83 | 84 | #if (sfgSTATISTIC == 1) 85 | if (cmem == NULL) 86 | stat_error(STAT_NEW_MEM, size); 87 | #endif 88 | 89 | em_scheduler_enable(); 90 | 91 | return cmem ? (uint8_t*) cmem + SIZE_STRUCT_HEAP : NULL; 92 | } 93 | //-------------------------------------------------------------- 94 | // Calloc 95 | //-------------------------------------------------------------- 96 | void* em_calloc(size_t count, size_t size) 97 | { 98 | void *p = em_malloc(count * size); 99 | if (p) 100 | memset(p, 0, count * size); 101 | return p; 102 | } 103 | //-------------------------------------------------------------- 104 | // Free 105 | //-------------------------------------------------------------- 106 | void em_free(void* ptr) 107 | { 108 | em_memblc_t *cmem, *tmp; 109 | 110 | if (ptr == NULL || !heap_finit) 111 | return; 112 | 113 | em_scheduler_disable(); 114 | 115 | cmem = (em_memblc_t*) heap.buf; 116 | tmp = NULL; 117 | 118 | while (cmem) { 119 | if (cmem->busy && ((uint8_t*) cmem + SIZE_STRUCT_HEAP == ptr)) { 120 | cmem->busy = 0; 121 | heap_free_size += cmem->size; 122 | // Combining adjacent 123 | if (tmp && !tmp->busy) { 124 | tmp->next = cmem->next; 125 | tmp->size += cmem->size; 126 | cmem = tmp; 127 | } 128 | tmp = cmem->next; 129 | if (tmp && !tmp->busy) { 130 | cmem->next = tmp->next; 131 | cmem->size += tmp->size; 132 | } 133 | break; 134 | } 135 | tmp = cmem; 136 | cmem = cmem->next; 137 | } 138 | 139 | #if (sfgSTATISTIC == 1) 140 | if (cmem == NULL) 141 | stat_error(STAT_FREE_MEM, ptr); 142 | #endif 143 | 144 | em_scheduler_enable(); 145 | } 146 | //-------------------------------------------------------------- 147 | // Get free space 148 | //-------------------------------------------------------------- 149 | size_t em_heap_get_free_space(void) 150 | { 151 | return heap_free_size; 152 | } 153 | -------------------------------------------------------------------------------- /src/em_heap.h: -------------------------------------------------------------------------------- 1 | // 2 | // Author: Shipaev Ivan Vladimirovich 3 | // iva_n_@mail.ru 4 | 5 | #ifndef _EM_MEM_HEAP_H_ 6 | #define _EM_MEM_HEAP_H_ 7 | 8 | void em_mem_init(void); 9 | void* em_malloc(size_t size); 10 | void* em_calloc(size_t count, size_t size); 11 | void em_free(void*); 12 | size_t em_heap_get_free_space(void); 13 | 14 | #endif /* _EM_MEM_HEAP_H_ */ 15 | -------------------------------------------------------------------------------- /src/em_list.c: -------------------------------------------------------------------------------- 1 | // 2 | // Author: Shipaev Ivan Vladimirovich 3 | // iva_n_@mail.ru 4 | 5 | #include 6 | #include "em_list.h" 7 | //-------------------------------------------------------------- 8 | // Clear 9 | //-------------------------------------------------------------- 10 | void rt_em_list_clear(em_list_t *lst) 11 | { 12 | lst->prev = lst->next = lst; 13 | } 14 | //-------------------------------------------------------------- 15 | // Is empty? 16 | //-------------------------------------------------------------- 17 | int rt_em_is_list_empty(em_list_t* lst) 18 | { 19 | return (lst->next == lst); 20 | } 21 | //-------------------------------------------------------------- 22 | // Is whole? 23 | //-------------------------------------------------------------- 24 | int rt_em_is_list_whole(em_list_t *lst) 25 | { 26 | if ((lst->next == NULL) || (lst->prev == NULL)) 27 | return 0; 28 | return 1; 29 | } 30 | //-------------------------------------------------------------- 31 | // Add to tail 32 | //-------------------------------------------------------------- 33 | void rt_em_list_add_tail(em_list_t *lst, em_list_t *nlst) 34 | { 35 | nlst->prev = lst->prev; 36 | nlst->next = lst; 37 | lst->prev->next = nlst; 38 | lst->prev = nlst; 39 | } 40 | //-------------------------------------------------------------- 41 | // Add to head 42 | //-------------------------------------------------------------- 43 | void rt_em_list_add_head(em_list_t *lst, em_list_t *nlst) 44 | { 45 | nlst->next = lst->next; 46 | nlst->prev = lst; 47 | lst->next->prev = nlst; 48 | lst->next = nlst; 49 | } 50 | //-------------------------------------------------------------- 51 | // Remove entry 52 | //-------------------------------------------------------------- 53 | void rt_em_list_remove_entry(em_list_t * lst) 54 | { 55 | lst->prev->next = lst->next; 56 | lst->next->prev = lst->prev; 57 | lst->prev = lst->next = lst; 58 | } 59 | //-------------------------------------------------------------- 60 | // Jump to head 61 | //-------------------------------------------------------------- 62 | void rt_em_list_jump_head(em_list_t *lst) 63 | { 64 | lst->prev->next = lst->next; 65 | lst->next->prev = lst->prev; 66 | rt_em_list_add_head(lst->next, lst); 67 | } 68 | //-------------------------------------------------------------- 69 | // Jump to tail 70 | //-------------------------------------------------------------- 71 | void rt_em_list_jump_tail(em_list_t *lst) 72 | { 73 | lst->prev->next = lst->next; 74 | lst->next->prev = lst->prev; 75 | rt_em_list_add_tail(lst->prev, lst); 76 | } 77 | -------------------------------------------------------------------------------- /src/em_list.h: -------------------------------------------------------------------------------- 1 | // 2 | // Author: Shipaev Ivan Vladimirovich 3 | // iva_n_@mail.ru 4 | 5 | #ifndef _EM_LIST_H_ 6 | #define _EM_LIST_H_ 7 | 8 | typedef struct _em_list_t 9 | { 10 | struct _em_list_t *next; 11 | struct _em_list_t *prev; 12 | } em_list_t; 13 | 14 | #define __EM_LIST_INIT(list) em_list_t list = {&list, &list} 15 | 16 | #define rt_em_get_struct_by_field(addr_field, type, field) \ 17 | ((type *)((unsigned char *)(addr_field) - (unsigned char *)(&((type *)0)->field))) 18 | 19 | void rt_em_list_clear(em_list_t *lst); 20 | int rt_em_is_list_empty(em_list_t *lst); 21 | int rt_em_is_list_whole(em_list_t *lst); 22 | void rt_em_list_add_tail(em_list_t *lst, em_list_t *nlst); 23 | void rt_em_list_add_head(em_list_t *lst, em_list_t *nlst); 24 | void rt_em_list_remove_entry(em_list_t * lst); 25 | void rt_em_list_jump_head(em_list_t *lst); 26 | void rt_em_list_jump_tail(em_list_t *lst); 27 | 28 | #endif /* _EM_LIST_H_ */ 29 | -------------------------------------------------------------------------------- /src/em_mutex.c: -------------------------------------------------------------------------------- 1 | // 2 | // Author: Shipaev Ivan Vladimirovich 3 | // iva_n_@mail.ru 4 | 5 | #define _EM_TASK_PRIVATE_ 6 | #include "task_include.h" 7 | 8 | static __EM_LIST_INIT(mutex_init_list); 9 | 10 | //-------------------------------------------------------------- 11 | // The priority of the mutex is determined by the priority of the tasks waiting for it 12 | //-------------------------------------------------------------- 13 | static em_task_t* __synhr_pri_mutex(em_mutex_t* mutex) 14 | { 15 | em_list_t* lst; 16 | em_task_t* task; 17 | unsigned old_pri; 18 | unsigned pri = 0; 19 | 20 | lst = mutex->wait_list.next; 21 | while (lst != &mutex->wait_list) { 22 | task = rt_em_get_task_by_task_list(lst); 23 | lst = lst->next; 24 | if (pri < task->pri) 25 | pri = task->pri; 26 | } 27 | 28 | if (mutex->pri != pri) { 29 | old_pri = mutex->pri; 30 | mutex->pri = pri; 31 | if (mutex->ptask && mutex->ptask->pri == old_pri) 32 | return mutex->ptask; 33 | } 34 | 35 | return NULL; 36 | } 37 | //-------------------------------------------------------------- 38 | // The priority of the task is determined by the priority of the locked mutexes 39 | //-------------------------------------------------------------- 40 | static em_mutex_t* __synhr_pri_task(em_task_t* task) 41 | { 42 | em_list_t* lst; 43 | em_mutex_t* mutex; 44 | unsigned old_pri; 45 | unsigned pri = task->base_pri; 46 | 47 | lst = task->mutex_lock_list.next; 48 | while (lst != &task->mutex_lock_list) { 49 | mutex = rt_em_get_mutex_by_lock_list(lst); 50 | lst = lst->next; 51 | if (pri < mutex->pri) { 52 | pri = mutex->pri; 53 | } 54 | } 55 | 56 | if (task->pri != pri) { 57 | old_pri = task->pri; 58 | rt_em_task_set_pri(task, pri); 59 | if (task->state == _S_WAIT_MUTEX 60 | && ((em_mutex_t*) task->wait_object)->pri == old_pri) 61 | return task->wait_object; 62 | } 63 | 64 | return NULL; 65 | } 66 | //-------------------------------------------------------------- 67 | // Mutex priority synchronization 68 | //-------------------------------------------------------------- 69 | void rt_em_synhr_pri_mutex(em_mutex_t* mutex) 70 | { 71 | em_task_t* task; 72 | while ((task = __synhr_pri_mutex(mutex)) && 73 | (mutex = __synhr_pri_task(task))); 74 | } 75 | //-------------------------------------------------------------- 76 | // Task priority synchronization 77 | //-------------------------------------------------------------- 78 | void rt_em_synhr_pri_task(em_task_t* task) 79 | { 80 | em_mutex_t* mutex; 81 | while ((mutex = __synhr_pri_task(task)) && 82 | (task = __synhr_pri_mutex(mutex))); 83 | } 84 | //-------------------------------------------------------------- 85 | // Get mutex initialization list 86 | //-------------------------------------------------------------- 87 | em_list_t* rt_em_get_mutex_init_list(void) 88 | { 89 | return &mutex_init_list; 90 | } 91 | //-------------------------------------------------------------- 92 | // Initialization 93 | //-------------------------------------------------------------- 94 | void em_mutex_init(em_mutex_t* mutex) 95 | { 96 | EM_ASSERT(mutex != NULL); 97 | 98 | EM_DISABLE_TASK(); 99 | 100 | mutex->ptask = NULL; 101 | mutex->coun = 0; 102 | mutex->pri = 0; 103 | rt_em_list_clear(&mutex->wait_list); 104 | rt_em_list_clear(&mutex->lock_list); 105 | rt_em_list_add_tail(&mutex_init_list, &mutex->init_list); 106 | 107 | EM_ENABLE_TASK(); 108 | } 109 | //-------------------------------------------------------------- 110 | // De-initialization 111 | //-------------------------------------------------------------- 112 | void em_mutex_deinit(em_mutex_t* mutex) 113 | { 114 | em_task_t* task; 115 | 116 | EM_ASSERT(mutex != NULL); 117 | 118 | EM_DISABLE_TASK(); 119 | 120 | while (rt_em_is_list_empty(&mutex->wait_list) == 0) { 121 | task = rt_em_get_task_by_task_list(mutex->wait_list.next); 122 | rt_em_complete_wait_action(task, EMERR_DEINIT); 123 | } 124 | if (mutex->ptask) { 125 | rt_em_list_remove_entry(&mutex->lock_list); 126 | rt_em_synhr_pri_task(mutex->ptask); 127 | mutex->ptask = NULL; 128 | } 129 | rt_em_list_remove_entry(&mutex->init_list); 130 | rt_em_scheduler(); 131 | 132 | EM_ENABLE_TASK(); 133 | } 134 | //-------------------------------------------------------------- 135 | // Create 136 | //-------------------------------------------------------------- 137 | em_mutex_t* em_mutex_new(void) 138 | { 139 | em_mutex_t* mutex = em_malloc(sizeof(em_mutex_t)); 140 | if (mutex == NULL) 141 | return NULL; 142 | 143 | em_mutex_init(mutex); 144 | 145 | return mutex; 146 | } 147 | //-------------------------------------------------------------- 148 | // Delete 149 | //-------------------------------------------------------------- 150 | void em_mutex_delete(em_mutex_t* mutex) 151 | { 152 | EM_ASSERT(mutex != NULL); 153 | 154 | em_mutex_deinit(mutex); 155 | em_free(mutex); 156 | } 157 | //-------------------------------------------------------------- 158 | // Take 159 | //-------------------------------------------------------------- 160 | int em_mutex_take(em_mutex_t* mutex, unsigned timeout) 161 | { 162 | EM_ASSERT(mutex != NULL); 163 | 164 | if (ctask == NULL) 165 | return EMERR_OK; 166 | 167 | EM_DISABLE_TASK(); 168 | 169 | if (mutex->coun == 0) { 170 | mutex->ptask = ctask; 171 | mutex->coun++; 172 | rt_em_list_add_tail(&ctask->mutex_lock_list, &mutex->lock_list); 173 | rt_em_synhr_pri_task(mutex->ptask); 174 | EM_ENABLE_TASK(); 175 | return EMERR_OK; 176 | } else if (mutex->ptask == ctask) { 177 | if (mutex->coun != EM_MAX_UNSIGNED_VALUE) 178 | mutex->coun++; 179 | EM_ENABLE_TASK(); 180 | return EMERR_OK; 181 | } else if (timeout == 0) { 182 | EM_ENABLE_TASK(); 183 | return EMERR_TIMEOUT; 184 | } 185 | 186 | EM_ASSERT(rt_em_scheduler_is_enable()); 187 | 188 | ctask->error = EMERR_TIMEOUT; 189 | rt_em_add_wait_action(ctask, mutex, &mutex->wait_list, _S_WAIT_MUTEX, 190 | timeout); 191 | rt_em_scheduler(); 192 | 193 | EM_ENABLE_TASK(); 194 | 195 | return ctask->error; 196 | } 197 | //-------------------------------------------------------------- 198 | // Give 199 | //-------------------------------------------------------------- 200 | int em_mutex_give_ex(em_mutex_t* mutex, int f_all) 201 | { 202 | em_task_t *task; 203 | 204 | EM_ASSERT(mutex != NULL); 205 | 206 | if (ctask == NULL) 207 | return EMERR_OK; 208 | 209 | EM_DISABLE_TASK(); 210 | 211 | if (mutex->coun == 0 || mutex->ptask != ctask) { 212 | EM_ENABLE_TASK(); 213 | return EMERR_OTHER_ERR; 214 | } 215 | 216 | if (f_all) 217 | mutex->coun = 0; 218 | else if (mutex->coun) 219 | mutex->coun--; 220 | if (mutex->coun == 0) { 221 | rt_em_list_remove_entry(&mutex->lock_list); 222 | rt_em_synhr_pri_task(mutex->ptask); 223 | mutex->ptask = NULL; 224 | // Checking tasks in list 225 | if (rt_em_is_list_empty(&mutex->wait_list) == 0) { 226 | task = rt_em_get_task_by_task_list(mutex->wait_list.next); 227 | rt_em_complete_wait_action(task, EMERR_OK); 228 | // Now mutex belongs to this task 229 | mutex->ptask = task; 230 | mutex->coun++; 231 | rt_em_list_add_tail(&task->mutex_lock_list, &mutex->lock_list); 232 | rt_em_synhr_pri_task(mutex->ptask); 233 | } 234 | rt_em_scheduler(); 235 | } 236 | 237 | EM_ENABLE_TASK(); 238 | 239 | return EMERR_OK; 240 | } 241 | -------------------------------------------------------------------------------- /src/em_mutex.h: -------------------------------------------------------------------------------- 1 | // 2 | // Author: Shipaev Ivan Vladimirovich 3 | // iva_n_@mail.ru 4 | 5 | #ifndef _EM_MUTEX_H_ 6 | #define _EM_MUTEX_H_ 7 | 8 | typedef struct _em_mutex_t 9 | { 10 | em_list_t init_list; 11 | em_list_t wait_list; 12 | em_list_t lock_list; 13 | em_task_t* ptask; 14 | unsigned coun; 15 | unsigned pri; 16 | } em_mutex_t; 17 | 18 | 19 | void em_mutex_init(em_mutex_t* mutex); 20 | void em_mutex_deinit(em_mutex_t* mutex); 21 | em_mutex_t* em_mutex_new(void); 22 | void em_mutex_delete(em_mutex_t* mutex); 23 | int em_mutex_take(em_mutex_t* mutex, unsigned timeout); 24 | int em_mutex_give_ex(em_mutex_t* mutex, int f_all); 25 | static inline int em_mutex_give(em_mutex_t* mutex) 26 | { 27 | return em_mutex_give_ex(mutex, 0); 28 | } 29 | 30 | #ifdef _EM_TASK_PRIVATE_ 31 | em_list_t* rt_em_get_mutex_init_list(void); 32 | static inline em_mutex_t* rt_em_get_mutex_by_init_list(em_list_t* list) 33 | { 34 | return rt_em_get_struct_by_field(list, em_mutex_t, init_list); 35 | } 36 | static inline em_mutex_t* rt_em_get_mutex_by_lock_list(em_list_t* list) 37 | { 38 | return rt_em_get_struct_by_field(list, em_mutex_t, lock_list); 39 | } 40 | void rt_em_synhr_pri_mutex(em_mutex_t* mutex); 41 | #endif /* _EM_TASK_PRIVATE_ */ 42 | 43 | #endif /* _EM_MUTEX_H_ */ 44 | -------------------------------------------------------------------------------- /src/em_queue.c: -------------------------------------------------------------------------------- 1 | // 2 | // Author: Shipaev Ivan Vladimirovich 3 | // iva_n_@mail.ru 4 | 5 | #define _EM_TASK_PRIVATE_ 6 | #include "task_include.h" 7 | 8 | static __EM_LIST_INIT(queue_init_list); 9 | 10 | //--------------------------------------------------------------- 11 | static int __do_post_msg(em_queue_t *queue, void *msg, enum queue_mode mode) 12 | { 13 | if (queue->num_block >= queue->max_block) 14 | return 0; 15 | if (mode & QUEUE_MODE_TAIL) { 16 | memcpy(queue->buf + queue->tail, msg, queue->size_block); 17 | queue->tail += queue->size_block; 18 | if (queue->tail >= queue->len_buf) 19 | queue->tail = 0; 20 | } else { 21 | if (queue->head == 0) 22 | queue->head = queue->len_buf; 23 | queue->head -= queue->size_block; 24 | memcpy(queue->buf + queue->head, msg, queue->size_block); 25 | } 26 | queue->num_block++; 27 | return 1; 28 | } 29 | //--------------------------------------------------------------- 30 | static int __do_fetch_msg(em_queue_t *queue, void *msg, enum queue_mode mode) 31 | { 32 | unsigned tail; 33 | if (queue->num_block == 0) 34 | return 0; 35 | if (mode & QUEUE_MODE_HEAD) { 36 | memcpy(msg, queue->buf + queue->head, queue->size_block); 37 | if ((mode & QUEUE_MODE_NO_DELETE) == 0) { 38 | queue->head += queue->size_block; 39 | if (queue->head >= queue->len_buf) 40 | queue->head = 0; 41 | queue->num_block--; 42 | } 43 | } else { 44 | tail = queue->tail; 45 | if (tail == 0) 46 | tail = queue->len_buf; 47 | tail -= queue->size_block; 48 | memcpy(msg, queue->buf + tail, queue->size_block); 49 | if ((mode & QUEUE_MODE_NO_DELETE) == 0) { 50 | queue->tail = tail; 51 | queue->num_block--; 52 | } 53 | } 54 | return 1; 55 | } 56 | //-------------------------------------------------------------- 57 | // Get queue initialization list 58 | //-------------------------------------------------------------- 59 | em_list_t* rt_em_get_queue_init_list(void) 60 | { 61 | return &queue_init_list; 62 | } 63 | //-------------------------------------------------------------- 64 | // Initialization 65 | //-------------------------------------------------------------- 66 | void em_queue_init(em_queue_t* queue, unsigned size_block, unsigned nblock, 67 | unsigned char* buf) 68 | { 69 | EM_ASSERT(queue != NULL); 70 | 71 | EM_DISABLE_TASK(); 72 | 73 | queue->head = 0; 74 | queue->tail = 0; 75 | queue->num_block = 0; 76 | queue->size_block = size_block; 77 | queue->max_block = nblock; 78 | queue->len_buf = size_block * nblock; 79 | queue->buf = buf; 80 | rt_em_list_clear(&queue->wait_fetch_list); 81 | rt_em_list_clear(&queue->wait_post_list); 82 | rt_em_list_add_tail(&queue_init_list, &queue->init_list); 83 | 84 | EM_ENABLE_TASK(); 85 | } 86 | //-------------------------------------------------------------- 87 | // De-initialization 88 | //-------------------------------------------------------------- 89 | void em_queue_deinit(em_queue_t* queue) 90 | { 91 | em_task_t* task; 92 | 93 | EM_ASSERT(queue != NULL); 94 | 95 | EM_DISABLE_TASK(); 96 | 97 | // Checking tasks in list 98 | while (rt_em_is_list_empty(&queue->wait_post_list) == 0) { 99 | task = rt_em_get_task_by_task_list(queue->wait_post_list.next); 100 | rt_em_complete_wait_action(task, EMERR_DEINIT); 101 | } 102 | // Checking tasks in list 103 | while (rt_em_is_list_empty(&queue->wait_fetch_list) == 0) { 104 | task = rt_em_get_task_by_task_list(queue->wait_fetch_list.next); 105 | rt_em_complete_wait_action(task, EMERR_DEINIT); 106 | } 107 | rt_em_list_remove_entry(&queue->init_list); 108 | rt_em_scheduler(); 109 | 110 | EM_ENABLE_TASK(); 111 | } 112 | //-------------------------------------------------------------- 113 | // Create 114 | //-------------------------------------------------------------- 115 | em_queue_t* em_queue_new(unsigned size_block, unsigned max_block) 116 | { 117 | unsigned char* buf; 118 | em_queue_t *queue = em_malloc(sizeof(em_queue_t)); 119 | if (queue == NULL) 120 | return NULL; 121 | 122 | buf = em_malloc(size_block * max_block); 123 | if (buf == NULL) { 124 | em_free(queue); 125 | return NULL; 126 | } 127 | 128 | em_queue_init(queue, size_block, max_block, buf); 129 | return queue; 130 | } 131 | //-------------------------------------------------------------- 132 | // Delete 133 | //-------------------------------------------------------------- 134 | void em_queue_delete(em_queue_t* queue) 135 | { 136 | EM_ASSERT(queue != NULL); 137 | 138 | em_queue_deinit(queue); 139 | em_free(queue->buf); 140 | em_free(queue); 141 | } 142 | //--------------------------------------------------------------- 143 | // Post message 144 | //--------------------------------------------------------------- 145 | int em_queue_post(em_queue_t *queue, void *msg, unsigned timeout, 146 | enum queue_mode mode) 147 | { 148 | em_task_t *task; 149 | 150 | EM_ASSERT(queue != NULL); 151 | 152 | if (mode & QUEUE_MODE_HEAD) 153 | mode &= ~(QUEUE_MODE_TAIL); 154 | else 155 | mode |= QUEUE_MODE_TAIL; 156 | 157 | EM_DISABLE_TASK(); 158 | 159 | if (__do_post_msg(queue, msg, mode)) { 160 | if (rt_em_is_list_empty(&queue->wait_fetch_list) == 0) { 161 | task = rt_em_get_task_by_task_list(queue->wait_fetch_list.next); 162 | __do_fetch_msg(queue, task->msg.msg, task->msg.mode); 163 | rt_em_complete_wait_action(task, EMERR_OK); 164 | rt_em_scheduler(); 165 | } 166 | EM_ENABLE_TASK(); 167 | return EMERR_OK; 168 | } else if (timeout == 0) { 169 | EM_ENABLE_TASK(); 170 | return EMERR_TIMEOUT; 171 | } 172 | 173 | EM_ASSERT(rt_em_scheduler_is_enable()); 174 | 175 | // TASK 176 | ctask->msg.msg = msg; 177 | ctask->msg.mode = mode; 178 | ctask->error = EMERR_TIMEOUT; 179 | rt_em_add_wait_action(ctask, queue, &queue->wait_post_list, 180 | _S_WAIT_QUEUE_POST, timeout); 181 | rt_em_scheduler(); 182 | 183 | EM_ENABLE_TASK(); 184 | 185 | return ctask->error; 186 | } 187 | //--------------------------------------------------------------- 188 | // Fetch message 189 | //--------------------------------------------------------------- 190 | int em_queue_fetch(em_queue_t* queue, void* msg, unsigned timeout, 191 | enum queue_mode mode) 192 | { 193 | EM_ASSERT(queue != NULL); 194 | 195 | em_task_t *task; 196 | 197 | if (mode & QUEUE_MODE_TAIL) 198 | mode &= ~(QUEUE_MODE_HEAD); 199 | else 200 | mode |= QUEUE_MODE_HEAD; 201 | 202 | EM_DISABLE_TASK(); 203 | 204 | if (__do_fetch_msg(queue, msg, mode)) { 205 | if (rt_em_is_list_empty(&queue->wait_post_list) == 0) { 206 | task = rt_em_get_task_by_task_list(queue->wait_post_list.next); 207 | __do_post_msg(queue, task->msg.msg, task->msg.mode); 208 | rt_em_complete_wait_action(task, EMERR_OK); 209 | rt_em_scheduler(); 210 | } 211 | EM_ENABLE_TASK(); 212 | return EMERR_OK; 213 | } else if (timeout == 0) { 214 | EM_ENABLE_TASK(); 215 | return EMERR_TIMEOUT; 216 | } 217 | 218 | EM_ASSERT(rt_em_scheduler_is_enable()); 219 | 220 | // TASK 221 | ctask->msg.msg = msg; 222 | ctask->msg.mode = mode; 223 | ctask->error = EMERR_TIMEOUT; 224 | rt_em_add_wait_action(ctask, queue, &queue->wait_fetch_list, 225 | _S_WAIT_QUEUE_FETCH, timeout); 226 | rt_em_scheduler(); 227 | 228 | EM_ENABLE_TASK(); 229 | 230 | return ctask->error; 231 | } 232 | -------------------------------------------------------------------------------- /src/em_queue.h: -------------------------------------------------------------------------------- 1 | // 2 | // Author: Shipaev Ivan Vladimirovich 3 | // iva_n_@mail.ru 4 | 5 | #ifndef _EM_QUEUE_H_ 6 | #define _EM_QUEUE_H_ 7 | 8 | enum queue_mode 9 | { 10 | QUEUE_MODE_DEFAULT = 0, // Post in tail, fetch in head 11 | QUEUE_MODE_HEAD = (1 << 0), // Post/fetch in head 12 | QUEUE_MODE_TAIL = (1 << 1), // Post/fetch in tail 13 | QUEUE_MODE_NO_DELETE = (1 << 2), // Fetching without deleting 14 | }; 15 | 16 | typedef struct _em_queue_t 17 | { 18 | em_list_t init_list; 19 | em_list_t wait_fetch_list; 20 | em_list_t wait_post_list; 21 | unsigned head; 22 | unsigned tail; 23 | unsigned num_block; 24 | unsigned size_block; 25 | unsigned max_block; 26 | unsigned len_buf; 27 | unsigned char* buf; 28 | } em_queue_t; 29 | 30 | void em_queue_init(em_queue_t* queue, unsigned size_block, unsigned nblock, 31 | unsigned char* buf); 32 | void em_queue_deinit(em_queue_t* queue); 33 | em_queue_t* em_queue_new(unsigned size_block, unsigned nblock); 34 | void em_queue_delete(em_queue_t *queue); 35 | int em_queue_post(em_queue_t *queue, void *msg, unsigned timeout, 36 | enum queue_mode mode); 37 | int em_queue_fetch(em_queue_t* queue, void* msg, unsigned timeout, 38 | enum queue_mode mode); 39 | //-------------------------------------------------------------- 40 | // These functions can be called both in tasks and in ISR 41 | //-------------------------------------------------------------- 42 | static inline int em_queue_try_post(em_queue_t *queue, void *msg, enum queue_mode mode) 43 | { 44 | return em_queue_post(queue, msg, 0, mode); 45 | } 46 | static inline int em_queue_try_fetch(em_queue_t* queue, void* msg, enum queue_mode mode) 47 | { 48 | return em_queue_fetch(queue, msg, 0, mode); 49 | } 50 | 51 | #ifdef _EM_TASK_PRIVATE_ 52 | em_list_t* rt_em_get_queue_init_list(void); 53 | static inline em_queue_t* rt_em_get_queue_by_init_list(em_list_t* list) 54 | { 55 | return rt_em_get_struct_by_field(list, em_queue_t, init_list); 56 | } 57 | #endif /* _EM_TASK_PRIVATE_ */ 58 | 59 | #endif /* _EM_QUEUE_H_ */ 60 | -------------------------------------------------------------------------------- /src/em_sem.c: -------------------------------------------------------------------------------- 1 | // 2 | // Author: Shipaev Ivan Vladimirovich 3 | // iva_n_@mail.ru 4 | 5 | #define _EM_TASK_PRIVATE_ 6 | #include "task_include.h" 7 | 8 | static __EM_LIST_INIT(sem_init_list); 9 | 10 | //-------------------------------------------------------------- 11 | // Get semaphore initialization list 12 | //-------------------------------------------------------------- 13 | em_list_t* rt_em_get_sem_init_list(void) 14 | { 15 | return &sem_init_list; 16 | } 17 | //-------------------------------------------------------------- 18 | // Initialization 19 | //-------------------------------------------------------------- 20 | void em_sem_init(em_sem_t* sem, unsigned startcount, unsigned maxcount) 21 | { 22 | EM_ASSERT(sem != NULL); 23 | EM_ASSERT(startcount <= maxcount); 24 | 25 | EM_DISABLE_TASK(); 26 | 27 | sem->count = startcount; 28 | sem->maxcount = maxcount; 29 | rt_em_list_clear(&sem->wait_list); 30 | rt_em_list_add_tail(&sem_init_list, &sem->init_list); 31 | 32 | EM_ENABLE_TASK(); 33 | } 34 | //-------------------------------------------------------------- 35 | // De-initialization 36 | //-------------------------------------------------------------- 37 | void em_sem_deinit(em_sem_t* sem) 38 | { 39 | em_task_t* task; 40 | 41 | EM_ASSERT(sem != NULL); 42 | 43 | EM_DISABLE_TASK(); 44 | 45 | // Checking tasks in list 46 | while (rt_em_is_list_empty(&sem->wait_list) == 0) { 47 | task = rt_em_get_task_by_task_list(sem->wait_list.next); 48 | rt_em_complete_wait_action(task, EMERR_DEINIT); 49 | } 50 | rt_em_list_remove_entry(&sem->init_list); 51 | rt_em_scheduler(); 52 | 53 | EM_ENABLE_TASK(); 54 | } 55 | //-------------------------------------------------------------- 56 | // Create 57 | //-------------------------------------------------------------- 58 | em_sem_t* em_sem_new(unsigned startcount, unsigned maxcount) 59 | { 60 | em_sem_t* sem; 61 | 62 | sem = em_malloc(sizeof(em_sem_t)); 63 | 64 | if (sem) 65 | em_sem_init(sem, startcount, maxcount); 66 | 67 | return sem; 68 | } 69 | //-------------------------------------------------------------- 70 | // Delete 71 | //-------------------------------------------------------------- 72 | void em_sem_delete(em_sem_t* sem) 73 | { 74 | EM_ASSERT(sem != NULL); 75 | 76 | em_sem_deinit(sem); 77 | em_free(sem); 78 | } 79 | //-------------------------------------------------------------- 80 | // Take 81 | //-------------------------------------------------------------- 82 | int em_sem_take(em_sem_t* sem, unsigned timeout) 83 | { 84 | EM_ASSERT(sem != NULL); 85 | 86 | EM_DISABLE_TASK(); 87 | 88 | if (sem->count) { 89 | sem->count--; 90 | EM_ENABLE_TASK(); 91 | return EMERR_OK; 92 | } else if (timeout == 0) { 93 | EM_ENABLE_TASK(); 94 | return EMERR_TIMEOUT; 95 | } 96 | 97 | EM_ASSERT(rt_em_scheduler_is_enable()); 98 | 99 | // TASK 100 | ctask->error = EMERR_TIMEOUT; 101 | rt_em_add_wait_action(ctask, sem, &sem->wait_list, _S_WAIT_SEM, timeout); 102 | rt_em_scheduler(); 103 | 104 | EM_ENABLE_TASK(); 105 | 106 | return ctask->error; 107 | } 108 | //-------------------------------------------------------------- 109 | // Give 110 | //-------------------------------------------------------------- 111 | int em_sem_give(em_sem_t* sem) 112 | { 113 | EM_ASSERT(sem != NULL); 114 | 115 | em_task_t *task; 116 | 117 | EM_DISABLE_TASK(); 118 | 119 | if (sem->count < sem->maxcount) { 120 | if (rt_em_is_list_empty(&sem->wait_list)) 121 | sem->count++; 122 | else { 123 | task = rt_em_get_task_by_task_list(sem->wait_list.next); 124 | rt_em_complete_wait_action(task, EMERR_OK); 125 | rt_em_scheduler(); 126 | } 127 | } 128 | 129 | EM_ENABLE_TASK(); 130 | 131 | return EMERR_OK; 132 | } 133 | -------------------------------------------------------------------------------- /src/em_sem.h: -------------------------------------------------------------------------------- 1 | // 2 | // Author: Shipaev Ivan Vladimirovich 3 | // iva_n_@mail.ru 4 | 5 | #ifndef _EM_SEM_H_ 6 | #define _EM_SEM_H_ 7 | 8 | typedef struct _em_sem_t 9 | { 10 | em_list_t init_list; 11 | em_list_t wait_list; // Waiting tasks list 12 | unsigned count; // Current count 13 | unsigned maxcount; // Max count 14 | } em_sem_t; 15 | 16 | void em_sem_init(em_sem_t* sem, unsigned startcount, unsigned maxcount); 17 | void em_sem_deinit(em_sem_t* sem); 18 | em_sem_t* em_sem_new(unsigned startcount, unsigned maxcount); 19 | void em_sem_delete(em_sem_t* sem); 20 | int em_sem_take(em_sem_t* sem, unsigned timeout); 21 | //-------------------------------------------------------------- 22 | // These functions can be called both in tasks and in ISR 23 | //-------------------------------------------------------------- 24 | static inline int em_sem_try_take(em_sem_t* sem) 25 | { 26 | return em_sem_take(sem, 0); 27 | } 28 | int em_sem_give(em_sem_t* sem); 29 | 30 | #ifdef _EM_TASK_PRIVATE_ 31 | em_list_t* rt_em_get_sem_init_list(void); 32 | static inline em_sem_t* rt_em_get_sem_by_init_list(em_list_t* list) 33 | { 34 | return rt_em_get_struct_by_field(list, em_sem_t, init_list); 35 | } 36 | #endif /* _EM_TASK_PRIVATE_ */ 37 | 38 | #endif /* _EM_SEM_H_ */ 39 | -------------------------------------------------------------------------------- /src/em_task.c: -------------------------------------------------------------------------------- 1 | // 2 | // Author: Shipaev Ivan Vladimirovich 3 | // iva_n_@mail.ru 4 | 5 | #define _EM_TASK_ 6 | #define _EM_TASK_PRIVATE_ 7 | #include "task_include.h" 8 | #define EM_YIELD_FLAG (1 << 0) 9 | #define EM_DELAY_FLAG (1 << 1) 10 | //-------------------------------------------------------------- 11 | static __EM_LIST_INIT(task_init_list); 12 | static __EM_LIST_INIT(task_start_list); 13 | static __EM_LIST_INIT(task_wait_list); 14 | static __EM_LIST_INIT(task_deleting_list); 15 | static em_list_t task_ready_list[cfgNUM_PRI]; // Array of priority queues of tasks ready for execution 16 | static unsigned task_mask_pri = 0; // Mask of priorities tasks ready for execution 17 | static em_event_t ev_sys[1]; // System event for yield() and delay() 18 | static unsigned counter_scheduler_disable = 0x7fffffff; 19 | static volatile struct // System timer 20 | { 21 | em_systick_t ms; 22 | em_systick_t sec; 23 | em_systick_t min; 24 | em_systick_t hour; 25 | } sys_timer; 26 | em_task_t *ctask = NULL; // Pointer to current task 27 | //-------------------------------------------------------------- 28 | inline em_task_t* rt_em_get_task_by_wait_list(em_list_t* list) 29 | { 30 | return rt_em_get_struct_by_field(list, em_task_t, wait_list); 31 | } 32 | //-------------------------------------------------------------- 33 | static void __delete_procedure(void) 34 | { 35 | em_task_t* task = NULL; 36 | 37 | do { 38 | task = NULL; 39 | 40 | EM_DISABLE_TASK(); 41 | 42 | if (rt_em_is_list_empty(&task_deleting_list) == 0) { 43 | task = rt_em_get_task_by_task_list(task_deleting_list.next); 44 | rt_em_list_remove_entry(&task->task_list); 45 | rt_em_list_remove_entry(&task->init_list); 46 | } 47 | 48 | EM_ENABLE_TASK(); 49 | 50 | if (task) { 51 | em_free(task->sp_start); 52 | em_free(task); 53 | } 54 | } while (task); 55 | } 56 | //-------------------------------------------------------------- 57 | static void FuncIdleTask(void* par) 58 | { 59 | (void) par; 60 | 61 | while (1) { 62 | #if (cfgUSE_IDLE_HOOK==1) 63 | extern void em_idle_hook(void); 64 | em_idle_hook(); 65 | #endif /*cfgUSE_IDLE_HOOK*/ 66 | __delete_procedure(); 67 | em_event_set(ev_sys, EM_YIELD_FLAG); 68 | // Note: Add Sleeping ... 69 | } 70 | } 71 | //-------------------------------------------------------------- 72 | // Add task in waiting list 73 | //-------------------------------------------------------------- 74 | static void __add_task_wait_list(em_task_t* task, unsigned timeout) 75 | { 76 | em_list_t* list; 77 | em_task_t* t_task; 78 | 79 | list = task_wait_list.next; 80 | while (list != &task_wait_list) { 81 | t_task = rt_em_get_task_by_wait_list(list); 82 | if (timeout >= t_task->timeout) 83 | timeout -= t_task->timeout; 84 | else { 85 | t_task->timeout -= timeout; 86 | break; 87 | } 88 | list = list->next; 89 | } 90 | task->timeout = timeout; 91 | rt_em_list_add_tail(list, &task->wait_list); 92 | } 93 | //-------------------------------------------------------------- 94 | // Delete task from waiting list 95 | //-------------------------------------------------------------- 96 | static void __del_task_wait_list(em_task_t* task) 97 | { 98 | em_task_t* t_task; 99 | 100 | if (rt_em_is_list_empty(&task->wait_list) == 0) { 101 | if (task->wait_list.next != &task_wait_list) { 102 | t_task = rt_em_get_task_by_wait_list(task->wait_list.next); 103 | t_task->timeout += task->timeout; 104 | } 105 | rt_em_list_remove_entry(&task->wait_list); 106 | } 107 | } 108 | //-------------------------------------------------------------- 109 | // Add task in waiting action list with timeout 110 | //-------------------------------------------------------------- 111 | void rt_em_add_wait_action(em_task_t* task, void* wait_object, em_list_t *list, 112 | unsigned state, unsigned timeout) 113 | { 114 | __del_task_wait_list(task); 115 | if (timeout != EM_TIM_INFINITY) 116 | __add_task_wait_list(task, timeout); 117 | rt_em_list_remove_entry(&task->task_list); 118 | rt_em_list_add_tail(list, &task->task_list); 119 | task->state = state; 120 | task->wait_object = wait_object; 121 | if (rt_em_is_list_empty(&task_ready_list[task->pri])) 122 | task_mask_pri &= ~(1 << task->pri); 123 | if (state == _S_WAIT_MUTEX) 124 | rt_em_synhr_pri_mutex((em_mutex_t*)wait_object); 125 | } 126 | //-------------------------------------------------------------- 127 | // Complete waiting action 128 | //-------------------------------------------------------------- 129 | void rt_em_complete_wait_action(em_task_t* task, int error) 130 | { 131 | unsigned state = task->state; 132 | __del_task_wait_list(task); 133 | rt_em_list_remove_entry(&task->task_list); 134 | rt_em_list_add_tail(&task_ready_list[task->pri], &task->task_list); 135 | task->state = _S_REDY; 136 | task->error = error; 137 | task_mask_pri |= (1 << task->pri); 138 | if (state == _S_WAIT_MUTEX) 139 | rt_em_synhr_pri_mutex((em_mutex_t*)task->wait_object); 140 | } 141 | //------------------------------------------------------------- 142 | // Switch Context 143 | //------------------------------------------------------------- 144 | void rt_em_switch_context(void) 145 | { 146 | unsigned task_pri_redy; 147 | 148 | #if cfgTEST_SP_SWITCH_TASK 149 | extern void rt_em_port_test_sp_switch_task(void); 150 | rt_em_port_test_sp_switch_task(); 151 | #endif /* cfgTEST_SP_SWITCH_TASK */ 152 | 153 | task_pri_redy = rt_em_find_first_bit(task_mask_pri); 154 | ctask = rt_em_get_task_by_task_list(task_ready_list[task_pri_redy].next); 155 | rt_em_list_jump_head(&task_ready_list[task_pri_redy]); 156 | } 157 | //-------------------------------------------------------------- 158 | //-------------------------------------------------------------- 159 | // Scheduler 160 | //-------------------------------------------------------------- 161 | //-------------------------------------------------------------- 162 | // Switch context if needed with round robin flag 163 | //------------------------------------------------------------- 164 | static void __scheduler_ex(int froundrobin) 165 | { 166 | unsigned task_pri_redy; 167 | if (counter_scheduler_disable == 0) { 168 | task_pri_redy = rt_em_find_first_bit(task_mask_pri); 169 | if (task_pri_redy > ctask->pri) 170 | rt_em_port_request_switch_context(); 171 | else if (ctask->state != _S_REDY) 172 | rt_em_port_request_switch_context(); 173 | else if (froundrobin) { 174 | if (ctask->task_list.next != ctask->task_list.prev) 175 | rt_em_port_request_switch_context(); 176 | } 177 | } 178 | } 179 | //-------------------------------------------------------------- 180 | // Switch context if needed without round robin 181 | //-------------------------------------------------------------- 182 | void rt_em_scheduler(void) 183 | { 184 | __scheduler_ex(0); 185 | } 186 | //-------------------------------------------------------------- 187 | // Is schedule enable 188 | //-------------------------------------------------------------- 189 | int rt_em_scheduler_is_enable(void) 190 | { 191 | return !counter_scheduler_disable; 192 | } 193 | //-------------------------------------------------------------- 194 | // Initialization kernel 195 | //-------------------------------------------------------------- 196 | static void em_idle_task_init(void) 197 | { 198 | #if cfgSTATIC_SYSTEM_TASK 199 | em_task_t *task; 200 | unsigned *sp_start; 201 | unsigned sp_size; 202 | 203 | extern void em_get_idle_task(em_task_t **pptask, unsigned **ppsp_buf, unsigned * ppsp_size); 204 | em_get_idle_task(&task, &sp_start, &sp_size); 205 | em_task_init(task, "IdleTask", 0, sp_start, sp_size, NULL, Func_idle_task, 1); 206 | ctask = task; 207 | #else 208 | ctask = em_task_new("IdleTask", 0, cfgSIZE_STACK_IDLE_TASK, NULL, FuncIdleTask, 1); 209 | #endif 210 | } 211 | //-------------------------------------------------------------- 212 | void em_kernel_init(void) 213 | { 214 | em_mem_init(); 215 | 216 | for (int i = 0; i < cfgNUM_PRI; i++) 217 | rt_em_list_clear(&task_ready_list[i]); 218 | em_event_init(ev_sys); 219 | 220 | em_idle_task_init(); 221 | 222 | #if (cfgUSE_TIMER_TASK) 223 | em_timer_module_init(); 224 | #endif 225 | } 226 | //-------------------------------------------------------------- 227 | // Start kernel 228 | //-------------------------------------------------------------- 229 | void em_kernel_start(void) 230 | { 231 | counter_scheduler_disable = 0; 232 | rt_em_port_start_first_task(); 233 | } 234 | //-------------------------------------------------------------- 235 | // Disable scheduler 236 | //-------------------------------------------------------------- 237 | void em_scheduler_disable(void) 238 | { 239 | EM_DISABLE_TASK(); 240 | 241 | counter_scheduler_disable++; 242 | 243 | EM_ENABLE_TASK(); 244 | } 245 | //-------------------------------------------------------------- 246 | // Enable scheduler 247 | //-------------------------------------------------------------- 248 | void em_scheduler_enable(void) 249 | { 250 | EM_DISABLE_TASK(); 251 | 252 | if (counter_scheduler_disable) 253 | counter_scheduler_disable--; 254 | rt_em_scheduler(); 255 | 256 | EM_ENABLE_TASK(); 257 | } 258 | //-------------------------------------------------------------- 259 | //-------------------------------------------------------------- 260 | // TASK 261 | //------------------------------------------------------------- 262 | //-------------------------------------------------------------- 263 | // Function exit for task 264 | //-------------------------------------------------------------- 265 | static void __em_task_exit(void) 266 | { 267 | em_mutex_t* mutex; 268 | 269 | // Unlock mutexes 270 | do { 271 | mutex = NULL; 272 | 273 | EM_DISABLE_TASK(); 274 | 275 | if (rt_em_is_list_empty(&ctask->mutex_lock_list) == 0) 276 | mutex = rt_em_get_mutex_by_lock_list((&ctask->mutex_lock_list)->next); 277 | 278 | EM_ENABLE_TASK(); 279 | 280 | if (mutex) 281 | em_mutex_give_ex(mutex, 1); 282 | } while (mutex); 283 | 284 | EM_DISABLE_TASK(); 285 | 286 | rt_em_add_wait_action(ctask, NULL, &task_deleting_list, _S_DELETING, EM_TIM_INFINITY); 287 | rt_em_scheduler(); 288 | 289 | EM_ENABLE_TASK(); 290 | 291 | while (1); 292 | } 293 | //-------------------------------------------------------------- 294 | // Start task 295 | //-------------------------------------------------------------- 296 | void em_task_start(em_task_t* task) 297 | { 298 | EM_ASSERT(task != NULL); 299 | 300 | EM_DISABLE_TASK(); 301 | 302 | if (task->state == _S_INIT) { 303 | rt_em_complete_wait_action(task, EMERR_OK); 304 | rt_em_scheduler(); 305 | } 306 | 307 | EM_ENABLE_TASK(); 308 | } 309 | //-------------------------------------------------------------- 310 | // Initialization 311 | //-------------------------------------------------------------- 312 | void em_task_init(em_task_t* task, // Pointer to task UCB 313 | const char* name, // Name 314 | unsigned pri, // Priority 315 | unsigned* sp_start, // Start SP 316 | unsigned sp_size, // Size SP 317 | void* par, // Pointer to parameter 318 | void (*start_func)(void*), // Point of entry 319 | int fstart // Starting flag 320 | ) 321 | { 322 | EM_ASSERT(task != NULL); 323 | EM_ASSERT(sp_start != NULL); 324 | EM_ASSERT(start_func != NULL); 325 | 326 | #if 1 327 | // NOTE: Can be deleted 328 | if (ctask == NULL) 329 | ctask = task; 330 | #endif 331 | 332 | pri = EM_MIN(pri, (cfgNUM_PRI - 1)); 333 | rt_em_list_clear(&task->task_list); 334 | rt_em_list_clear(&task->wait_list); 335 | rt_em_list_clear(&task->mutex_lock_list); 336 | em_strlcpy(task->name, name, cfgLEN_TASK_NAME); 337 | 338 | task->sp = rt_em_port_init_stack(sp_start, sp_size, start_func, par, 339 | __em_task_exit); 340 | task->sp_start = sp_start; 341 | task->sp_size = sp_size; 342 | task->par = par; 343 | task->start_func = start_func; 344 | task->error = EMERR_OK; 345 | task->pri = pri; 346 | task->base_pri = pri; 347 | task->state = _S_INIT; 348 | 349 | EM_DISABLE_TASK(); 350 | 351 | rt_em_list_add_tail(&task_init_list, &task->init_list); 352 | rt_em_add_wait_action(task, NULL, &task_start_list, _S_INIT, 353 | EM_TIM_INFINITY); 354 | 355 | EM_ENABLE_TASK(); 356 | 357 | if (fstart) 358 | em_task_start(task); 359 | } 360 | //-------------------------------------------------------------- 361 | // Create 362 | //-------------------------------------------------------------- 363 | em_task_t* em_task_new(const char* name, // Name 364 | unsigned pri, // Priority 365 | unsigned sp_size, // Size SP 366 | void* par, // Pointer to parameter 367 | void (*start_func)(void*), // Point of entry 368 | int fstart // Starting flag 369 | ) 370 | { 371 | unsigned* sp_start; 372 | em_task_t* task = em_malloc(sizeof(em_task_t)); 373 | 374 | if (task == NULL) 375 | return NULL; 376 | sp_start = em_malloc(sp_size * sizeof(unsigned)); 377 | if (sp_start == NULL) { 378 | em_free(task); 379 | return NULL; 380 | } 381 | 382 | em_task_init(task, name, pri, sp_start, sp_size, par, start_func, fstart); 383 | return task; 384 | } 385 | //-------------------------------------------------------------- 386 | // Get priority 387 | //-------------------------------------------------------------- 388 | unsigned em_task_get_pri(em_task_t* task) 389 | { 390 | unsigned pri; 391 | 392 | EM_ASSERT(task != NULL); 393 | 394 | EM_DISABLE_TASK(); 395 | 396 | pri = task->pri; 397 | 398 | EM_ENABLE_TASK(); 399 | 400 | return pri; 401 | } 402 | //-------------------------------------------------------------- 403 | // Set priority 404 | //-------------------------------------------------------------- 405 | void rt_em_task_set_pri(em_task_t* task, unsigned pri) 406 | { 407 | if (task->state == _S_REDY) { 408 | rt_em_list_remove_entry(&task->task_list); 409 | if (rt_em_is_list_empty(&task_ready_list[task->pri])) 410 | task_mask_pri &= ~(1 << task->pri); 411 | task->pri = pri; 412 | rt_em_list_add_tail(&task_ready_list[task->pri], &task->task_list); 413 | task_mask_pri |= (1 << task->pri); 414 | } 415 | else 416 | task->pri = pri; 417 | } 418 | void em_task_set_pri(em_task_t* task, unsigned pri) 419 | { 420 | EM_ASSERT(task != NULL); 421 | EM_ASSERT(ctask != NULL); 422 | 423 | EM_DISABLE_TASK(); 424 | 425 | rt_em_task_set_pri(task, pri); 426 | task->base_pri = pri; 427 | if (ctask != task && task->pri > ctask->pri) 428 | rt_em_scheduler(); 429 | 430 | EM_ENABLE_TASK(); 431 | } 432 | //-------------------------------------------------------------- 433 | // Testing SP 434 | //-------------------------------------------------------------- 435 | void em_test_sp(void) 436 | { 437 | em_scheduler_disable(); 438 | 439 | rt_em_port_test_sp(&task_init_list); 440 | 441 | em_scheduler_enable(); 442 | } 443 | //-------------------------------------------------------------- 444 | // Yield 445 | //-------------------------------------------------------------- 446 | void em_yield(void) 447 | { 448 | em_event_wait(ev_sys, EM_EVENT_MODE_OR | EM_EVENT_MODE_CLEAR, 449 | EM_YIELD_FLAG, 1, NULL); 450 | } 451 | //-------------------------------------------------------------- 452 | // Delay 453 | //-------------------------------------------------------------- 454 | void em_delay(unsigned timeout) 455 | { 456 | em_event_wait(ev_sys, EM_EVENT_MODE_OR | EM_EVENT_MODE_CLEAR, 457 | EM_DELAY_FLAG, timeout, NULL); 458 | } 459 | //-------------------------------------------------------------- 460 | //-------------------------------------------------------------- 461 | // Tick 462 | //-------------------------------------------------------------- 463 | //-------------------------------------------------------------- 464 | static void __poll_task_wait_list(void) 465 | { 466 | em_task_t * task; 467 | 468 | if (rt_em_is_list_empty(&task_wait_list) == 0) { 469 | task = rt_em_get_task_by_wait_list(task_wait_list.next); 470 | if (task->timeout == 0 || --task->timeout == 0) { 471 | // finish waiting this task 472 | rt_em_complete_wait_action(task, EMERR_TIMEOUT); 473 | // finish waiting other tasks with timeout == 0 474 | while (rt_em_is_list_empty(&task_wait_list) == 0) { 475 | task = rt_em_get_task_by_wait_list(task_wait_list.next); 476 | if (task->timeout) 477 | break; 478 | rt_em_complete_wait_action(task, EMERR_TIMEOUT); 479 | } 480 | } 481 | } 482 | __scheduler_ex(1); 483 | } 484 | 485 | //-------------------------------------------------------------- 486 | static void __sys_tic(void) 487 | { 488 | static uint16_t count_ms = 0; 489 | static uint8_t count_sec = 0; 490 | static uint8_t count_min = 0; 491 | sys_timer.ms++; 492 | if (++count_ms >= 1000) { // sec 493 | count_ms = 0; 494 | sys_timer.sec++; 495 | if (++count_sec >= 60) { // min 496 | count_sec = 0; 497 | sys_timer.min++; 498 | if (++count_min >= 24) { // hour 499 | count_min = 0; 500 | sys_timer.hour++; 501 | } 502 | } 503 | } 504 | } 505 | //-------------------------------------------------------------- 506 | void rt_em_isr_system_tic(void) 507 | { 508 | EM_DISABLE_TASK(); 509 | 510 | __sys_tic(); 511 | __poll_task_wait_list(); 512 | #if (cfgUSE_TIMER_TASK) 513 | rt_timer_poll_wait_list(); 514 | #endif /* cfgUSE_TIMER_TASK */ 515 | 516 | #if (cfgUSE_SYSTIC_HOOK) 517 | extern void EM_SYS_TIC_HOOK(void); 518 | EM_SYS_TIC_HOOK(); 519 | #endif /* cfgUSE_SYSTIC_HOOK */ 520 | 521 | EM_ENABLE_TASK(); 522 | } 523 | //-------------------------------------------------------------- 524 | em_systick_t GetSysTic(void) 525 | { 526 | return sys_timer.ms; 527 | } 528 | //-------------------------------------------------------------- 529 | em_systick_t SubSysTic(em_systick_t tick) 530 | { 531 | return GetSysTic() - tick; 532 | } 533 | //-------------------------------------------------------------- 534 | // Sec 535 | //-------------------------------------------------------------- 536 | em_systick_t GetSysTicSec(void) 537 | { 538 | return sys_timer.sec; 539 | } 540 | //-------------------------------------------------------------- 541 | em_systick_t SubSysTicSec(em_systick_t tick) 542 | { 543 | return GetSysTicSec() - tick; 544 | } 545 | //-------------------------------------------------------------- 546 | // Errno 547 | //-------------------------------------------------------------- 548 | int *em_errno(void) 549 | { 550 | return &ctask->error; 551 | } 552 | //-------------------------------------------------------------- 553 | // Utils 554 | //-------------------------------------------------------------- 555 | unsigned em_strlcpy(char *s1, const char *s2, unsigned size) 556 | { 557 | unsigned i; 558 | if (size == 0) 559 | return 0; 560 | for (i = 0; (i < size - 1) && (*s2 != 0); i++) 561 | *s1++ = *s2++; 562 | *s1 = 0; 563 | return i; 564 | } 565 | //-------------------------------------------------------------- 566 | // Assert 567 | //-------------------------------------------------------------- 568 | #if (cfgUSE_ASSERT) 569 | void __em_assert_func(char* file, unsigned line) 570 | { 571 | EM_PRINTF("assert: %s - %d\r\n", file, line); 572 | EM_DISABLE_TASK(); 573 | EM_DISABLE_ISR(); 574 | while (1); 575 | } 576 | #endif 577 | -------------------------------------------------------------------------------- /src/em_task.h: -------------------------------------------------------------------------------- 1 | // 2 | // Author: Shipaev Ivan Vladimirovich 3 | // iva_n_@mail.ru 4 | 5 | #ifndef _EM_TASK_H_ 6 | #define _EM_TASK_H_ 7 | 8 | // State in task 9 | enum 10 | { 11 | _S_INIT, 12 | _S_SUSPEND, 13 | _S_REDY, 14 | _S_DELETING, 15 | _S_WAIT, 16 | _S_WAIT_EVENT, 17 | _S_WAIT_SEM, 18 | _S_WAIT_MUTEX, 19 | _S_WAIT_QUEUE_POST, 20 | _S_WAIT_QUEUE_FETCH, 21 | }; 22 | 23 | // Error 24 | enum { 25 | EMERR_OK = 0, 26 | EMERR_TIMEOUT = -1, 27 | EMERR_DEINIT = -2, 28 | EMERR_OTHER_ERR = -3, 29 | }; 30 | 31 | typedef uint32_t em_systick_t; 32 | //-------------------------------------------------------------- 33 | // Scheduler 34 | //-------------------------------------------------------------- 35 | void em_kernel_init(void); 36 | void em_kernel_start(void); 37 | void em_scheduler_disable(void); 38 | void em_scheduler_enable(void); 39 | //-------------------------------------------------------------- 40 | // Task UCB 41 | //-------------------------------------------------------------- 42 | typedef struct _em_task_t 43 | { 44 | unsigned* sp; // Pointer to SP 45 | unsigned* sp_start; // Start SP 46 | unsigned sp_size; // Size SP 47 | void* par; // Pointer to parameter 48 | void (*start_func) (void*); // Point of entry 49 | em_list_t init_list; 50 | em_list_t task_list; // Task List 51 | em_list_t mutex_lock_list; // Mutex Lock List 52 | em_list_t wait_list; // Waiting List 53 | unsigned timeout; // Timeout 54 | int error; // Error return 55 | char name[cfgLEN_TASK_NAME]; // Task Name 56 | struct 57 | { 58 | unsigned pri :8; // Priority 59 | unsigned base_pri :8; // Base priority 60 | unsigned state :8; // State 61 | unsigned rezerv :8; 62 | }; 63 | union 64 | { 65 | // For events 66 | struct 67 | { 68 | unsigned flags; // Flags 69 | unsigned mode; // Mode 70 | } event; 71 | // For queue 72 | struct 73 | { 74 | void* msg; // Message 75 | unsigned mode; // Mode 76 | } msg; 77 | }; 78 | void* wait_object; // Waiting object (mutex, event ...) 79 | } em_task_t; 80 | 81 | void em_task_start(em_task_t* task); 82 | void em_task_init(em_task_t* task, // Pointer to task UCB 83 | const char* name, // Name 84 | unsigned pri, // Priority 85 | unsigned* sp_start, // Start SP 86 | unsigned sp_size, // Size SP 87 | void* par, // Pointer to parameter 88 | void (*start_func)(void*), // Point of entry 89 | int fstart // Starting flag 90 | ); 91 | em_task_t* em_task_new(const char* name, // Name 92 | unsigned pri, // Priority 93 | unsigned sp_size, // Size SP 94 | void* par, // Pointer to parameter 95 | void (*start_func)(void*), // Point of entry 96 | int fstart // Starting flag 97 | ); 98 | unsigned em_task_get_pri(em_task_t* task); 99 | void em_task_set_pri(em_task_t* task, unsigned pri); 100 | void em_test_sp(void); 101 | void em_yield(void); 102 | void em_delay(unsigned timeout); 103 | //-------------------------------------------------------------- 104 | // Systems Tick 105 | // These functions can be called both in tasks and in ISR 106 | //-------------------------------------------------------------- 107 | // msec 108 | em_systick_t GetSysTic(void); 109 | em_systick_t SubSysTic(em_systick_t tick); 110 | // sec 111 | em_systick_t GetSysTicSec(void); 112 | em_systick_t SubSysTicSec(em_systick_t tick); 113 | //-------------------------------------------------------------- 114 | // Errno 115 | //-------------------------------------------------------------- 116 | int *em_errno(void); 117 | #define errno *em_errno() 118 | //-------------------------------------------------------------- 119 | // Utils 120 | //-------------------------------------------------------------- 121 | unsigned em_strlcpy(char *s1, const char *s2, unsigned size); 122 | 123 | #ifdef _EM_TASK_PRIVATE_ 124 | #ifndef _EM_TASK_ 125 | #define _EM_TASK_ 126 | extern em_task_t *ctask; // Current task 127 | #endif /* _EM_TASK_ */ 128 | 129 | static inline em_task_t* rt_em_get_task_by_task_list(em_list_t* list) 130 | { 131 | return rt_em_get_struct_by_field(list, em_task_t, task_list); 132 | } 133 | void rt_em_add_wait_action(em_task_t* task, void* wait_object, em_list_t *list, unsigned state, unsigned timeout); 134 | void rt_em_complete_wait_action(em_task_t* task, int error); 135 | void rt_em_task_set_pri(em_task_t* task, unsigned pri); 136 | void rt_em_scheduler(); 137 | int rt_em_scheduler_is_enable(void); 138 | void rt_em_switch_context(void); 139 | void rt_em_isr_system_tic(void); 140 | 141 | #endif /* _EM_TASK_PRIVATE_ */ 142 | 143 | #endif /* _EM_TASK_H_ */ 144 | 145 | -------------------------------------------------------------------------------- /src/em_timer_task.c: -------------------------------------------------------------------------------- 1 | #define _TIMER_TASK_ 2 | #define _EM_TASK_PRIVATE_ 3 | #include "task_include.h" 4 | #include "em_timer_task.h" 5 | 6 | #if (cfgUSE_TIMER_TASK) 7 | 8 | #define EM_TIMER_FLAG (1 << 0) 9 | 10 | static __EM_LIST_INIT(timer_wait_list); 11 | static __EM_LIST_INIT(timer_ready_list); 12 | static em_event_t timer_event[1]; 13 | 14 | //-------------------------------------------------------------- 15 | static inline em_timer_t* rt_em_get_timer_by_timer_list(em_list_t* list) 16 | { 17 | return rt_em_get_struct_by_field(list, em_timer_t, timer_list); 18 | } 19 | //-------------------------------------------------------------- 20 | static void __del_timer_wait_list(em_timer_t* timer) 21 | { 22 | em_timer_t* t_timer; 23 | 24 | if (rt_em_is_list_empty(&timer->timer_list) == 0) { 25 | if (timer->timer_list.next != &timer_wait_list) { 26 | t_timer = rt_em_get_timer_by_timer_list(timer->timer_list.next); 27 | t_timer->timeout += timer->timeout; 28 | } 29 | rt_em_list_remove_entry(&timer->timer_list); 30 | } 31 | } 32 | //-------------------------------------------------------------- 33 | static int __add_timer_wait_list(em_timer_t* timer, unsigned timeout) 34 | { 35 | em_list_t* list; 36 | em_timer_t* t_timer; 37 | 38 | if (timeout == 0) { 39 | timer->timeout = 0; 40 | rt_em_list_add_tail(&timer_ready_list, &timer->timer_list); 41 | return 1; 42 | } 43 | 44 | list = timer_wait_list.next; 45 | while (list != &timer_wait_list) { 46 | t_timer = rt_em_get_timer_by_timer_list(list); 47 | if (timeout >= t_timer->timeout) 48 | timeout -= t_timer->timeout; 49 | else { 50 | t_timer->timeout -= timeout; 51 | break; 52 | } 53 | list = list->next; 54 | } 55 | timer->timeout = timeout; 56 | rt_em_list_add_tail(list, &timer->timer_list); 57 | return 0; 58 | } 59 | //-------------------------------------------------------------- 60 | static int rt_em_timer_restart(em_timer_t* timer, unsigned timeout, 61 | enum em_timer_type type, void (*func)(void *), void *par) 62 | { 63 | if (type == EM_TIMER_REUSE && timeout == 0) 64 | timeout = 1; 65 | timer->alltimeout = timeout; 66 | timer->type = type; 67 | timer->func = func; 68 | timer->par = par; 69 | __del_timer_wait_list(timer); 70 | return __add_timer_wait_list(timer, timeout); 71 | } 72 | //-------------------------------------------------------------- 73 | // Poll wait list. Need to call into ISR every 1 ms. 74 | //-------------------------------------------------------------- 75 | void rt_timer_poll_wait_list(void) 76 | { 77 | em_timer_t* timer; 78 | 79 | if (rt_em_is_list_empty(&timer_wait_list) == 0) { 80 | timer = rt_em_get_timer_by_timer_list(timer_wait_list.next); 81 | if (timer->timeout == 0 || --timer->timeout == 0) { 82 | // finish waiting this timer 83 | rt_em_list_remove_entry(&timer->timer_list); 84 | rt_em_list_add_tail(&timer_ready_list, &timer->timer_list); 85 | // finish waiting other timers with timeout == 0 86 | while (rt_em_is_list_empty(&timer_wait_list) == 0) { 87 | timer = rt_em_get_timer_by_timer_list(timer_wait_list.next); 88 | if (timer->timeout) 89 | break; 90 | rt_em_list_remove_entry(&timer->timer_list); 91 | rt_em_list_add_tail(&timer_ready_list, &timer->timer_list); 92 | } 93 | rt_em_event_set(timer_event, EM_TIMER_FLAG); 94 | } 95 | } 96 | } 97 | //-------------------------------------------------------------- 98 | // Task Timer 99 | //-------------------------------------------------------------- 100 | static void FuncTimerTask(void* par) 101 | { 102 | em_timer_t* timer; 103 | void (*func)(void *); 104 | 105 | while (1) { 106 | em_event_wait(timer_event, EM_EVENT_MODE_OR | EM_EVENT_MODE_CLEAR, EM_TIMER_FLAG, EM_TIM_INFINITY, NULL); 107 | do { 108 | timer = NULL; 109 | func = NULL; 110 | 111 | EM_DISABLE_TASK(); 112 | 113 | if (rt_em_is_list_empty(&timer_ready_list) == 0) { 114 | timer = rt_em_get_timer_by_timer_list(timer_ready_list.next); 115 | rt_em_list_remove_entry(&timer->timer_list); 116 | func = timer->func; 117 | par = timer->par; 118 | if (timer->type == EM_TIMER_REUSE) 119 | rt_em_timer_restart(timer, timer->alltimeout, timer->type, 120 | timer->func, timer->par); 121 | } 122 | 123 | EM_ENABLE_TASK(); 124 | 125 | if (func) 126 | func(par); 127 | } while (timer); 128 | } 129 | } 130 | //-------------------------------------------------------------- 131 | // Initialization module 132 | //-------------------------------------------------------------- 133 | void em_timer_module_init(void) 134 | { 135 | em_event_init(timer_event); 136 | 137 | #if (cfgSTATIC_TIMER_TASK) 138 | C_em_task *task; 139 | unsigned *sp_start; 140 | unsigned sp_size; 141 | 142 | extern void em_get_timer_task(em_task_t **pptask, unsigned **ppsp_buf, unsigned * ppsp_size); 143 | em_get_timer_task(&task, &sp_start, &sp_size); 144 | em_task_init(task, "TimerTask", cfgPRI_TIMER_TASK, sp_start, sp_size, NULL, FuncTimerTask, 1); 145 | #else 146 | em_task_new("TimerTask", cfgPRI_TIMER_TASK, cfgSIZE_STACK_TIMER_TASK, NULL, FuncTimerTask, 1); 147 | #endif 148 | } 149 | //-------------------------------------------------------------- 150 | // Initialization 151 | //-------------------------------------------------------------- 152 | void em_timer_init(em_timer_t* timer) 153 | { 154 | EM_ASSERT(timer != NULL); 155 | 156 | memset(timer, 0, sizeof(em_timer_t)); 157 | rt_em_list_clear(&timer->timer_list); 158 | } 159 | //-------------------------------------------------------------- 160 | // Start 161 | //-------------------------------------------------------------- 162 | void em_timer_start(em_timer_t* timer, unsigned timeout, 163 | enum em_timer_type type, void (*func)(void *), void *par) 164 | { 165 | EM_ASSERT(timer != NULL); 166 | 167 | EM_DISABLE_TASK(); 168 | 169 | int rc = rt_em_timer_restart(timer, timeout, type, func, par); 170 | 171 | EM_ENABLE_TASK(); 172 | 173 | if (rc) 174 | em_event_set(timer_event, EM_TIMER_FLAG); 175 | } 176 | //-------------------------------------------------------------- 177 | // Restart 178 | //-------------------------------------------------------------- 179 | void em_timer_restart(em_timer_t* timer) 180 | { 181 | EM_ASSERT(timer != NULL); 182 | 183 | EM_DISABLE_TASK(); 184 | 185 | int rc = rt_em_timer_restart(timer, timer->alltimeout, timer->type, timer->func, timer->par); 186 | 187 | EM_ENABLE_TASK(); 188 | 189 | if (rc) 190 | em_event_set(timer_event, EM_TIMER_FLAG); 191 | } 192 | //-------------------------------------------------------------- 193 | // Stop 194 | //-------------------------------------------------------------- 195 | void em_timer_stop(em_timer_t* timer) 196 | { 197 | EM_ASSERT(timer != NULL); 198 | 199 | EM_DISABLE_TASK(); 200 | 201 | __del_timer_wait_list(timer); 202 | 203 | EM_ENABLE_TASK(); 204 | } 205 | 206 | #endif 207 | -------------------------------------------------------------------------------- /src/em_timer_task.h: -------------------------------------------------------------------------------- 1 | // 2 | // Author: Shipaev Ivan Vladimirovich 3 | // iva_n_@mail.ru 4 | 5 | #ifndef _TIMER_TASK_H_ 6 | #define _TIMER_TASK_H_ 7 | 8 | #if (cfgUSE_TIMER_TASK) 9 | 10 | enum em_timer_type 11 | { 12 | EM_TIMER_SINGLE = 0, 13 | EM_TIMER_REUSE = 1, 14 | }; 15 | 16 | typedef struct _em_timer_t 17 | { 18 | em_list_t timer_list; 19 | unsigned alltimeout; 20 | unsigned timeout; 21 | enum em_timer_type type; 22 | void (*func)(void *par); 23 | void *par; 24 | } em_timer_t; 25 | 26 | void em_timer_module_init (void); 27 | void em_timer_init(em_timer_t* timer); 28 | void em_timer_start(em_timer_t* timer, unsigned timeout, 29 | enum em_timer_type type, void (*func)(void *), void *par); 30 | void em_timer_restart(em_timer_t* timer); 31 | void em_timer_stop(em_timer_t* timer); 32 | 33 | #ifdef _EM_TASK_PRIVATE_ 34 | void rt_timer_poll_wait_list(void); 35 | #endif /* _EM_TASK_PRIVATE_ */ 36 | 37 | #endif /* cfgUSE_TIMER_TASK */ 38 | 39 | #endif /* _TIMER_TASK_H_ */ 40 | -------------------------------------------------------------------------------- /src/task_include.h: -------------------------------------------------------------------------------- 1 | // 2 | // Author: Shipaev Ivan Vladimirovich 3 | // iva_n_@mail.ru 4 | 5 | #ifndef _EM_TASK_INLCUDE_H_ 6 | #define _EM_TASK_INLCUDE_H_ 7 | 8 | #include 9 | #include 10 | #include 11 | #include "em_config_task.h" 12 | #include "em_list.h" 13 | #include "em_port.h" 14 | #include "em_task.h" 15 | #include "em_heap.h" 16 | #include "em_event.h" 17 | #include "em_mutex.h" 18 | #include "em_sem.h" 19 | #include "em_queue.h" 20 | #include "em_timer_task.h" 21 | 22 | #endif /* _EM_TASK_INLCUDE_H_ */ 23 | --------------------------------------------------------------------------------