├── .gitattributes ├── AK-mOS ├── task_list.cpp ├── Inc │ ├── os_prio.h │ ├── os_mem.h │ ├── os_cpu.h │ ├── os_kernel.h │ ├── os_task.h │ ├── os_timer.h │ ├── os_msg.h │ ├── os_log.h │ └── os_list.h ├── task_list.h ├── os_cfg.h └── Src │ ├── os_prio.c │ ├── os_kernel.c │ ├── os_cpu.c │ ├── os_list.c │ ├── os_msg.c │ ├── os_mem.c │ ├── os_timer.c │ └── os_task.c └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /AK-mOS/task_list.cpp: -------------------------------------------------------------------------------- 1 | #include "task_list.h" 2 | 3 | const task_t app_task_table[] = { 4 | /*************************************************************************/ 5 | /* TASK */ 6 | /* TASK_ID task_func arg prio msg_queue_size stk_size */ 7 | /*************************************************************************/ 8 | {TASK_1_ID, task_1, NULL, 0, 8, 100}, 9 | {TASK_2_ID, task_2, NULL, 0, 8, 100}, 10 | {TASK_3_ID, task_3, NULL, 0, 8, 100}, 11 | }; 12 | -------------------------------------------------------------------------------- /AK-mOS/Inc/os_prio.h: -------------------------------------------------------------------------------- 1 | /* 2 | * os_prio.h 3 | * 4 | * Created on: Jun 26, 2024 5 | * Author: giahu 6 | */ 7 | 8 | #ifndef OS_PRIO_H 9 | #define OS_PRIO_H 10 | 11 | #ifdef __cplusplus 12 | extern "C" 13 | { 14 | #endif 15 | 16 | #include 17 | #include 18 | #include "os_cfg.h" 19 | 20 | #define OS_PRIO_TBL_SIZE (((OS_CFG_PRIO_MAX - 1u) / (8u)) + 1u) 21 | 22 | void os_prio_init(void); 23 | void os_prio_insert(uint32_t prio); 24 | void os_prio_remove(uint32_t prio); 25 | uint32_t os_prio_get_highest(void); 26 | uint32_t os_prio_get_curr(void); 27 | 28 | #ifdef __cplusplus 29 | } 30 | #endif 31 | #endif /* OS_PRIO_H */ 32 | -------------------------------------------------------------------------------- /AK-mOS/Inc/os_mem.h: -------------------------------------------------------------------------------- 1 | /* 2 | * os_mem.h 3 | * 4 | * Created on: Jun 26, 2024 5 | * Author: giahu 6 | */ 7 | 8 | #ifndef OS_MEM_H 9 | #define OS_MEM_H 10 | 11 | #ifdef __cplusplus 12 | extern "C" 13 | { 14 | #endif 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | typedef enum 21 | { 22 | MEM_STATE_FREE = 0, 23 | MEM_STATE_BUSY 24 | } mem_state_t; 25 | 26 | typedef struct mem_blk_header mem_blk_header_t; 27 | 28 | struct mem_blk_header 29 | { 30 | size_t size; 31 | mem_state_t state; 32 | struct mem_blk_header *next_ptr; 33 | }; 34 | 35 | void *os_mem_malloc(size_t size); 36 | void os_mem_free(void *p_addr); 37 | 38 | #ifdef __cplusplus 39 | } 40 | #endif 41 | #endif /* OS_MEM_H */ 42 | -------------------------------------------------------------------------------- /AK-mOS/Inc/os_cpu.h: -------------------------------------------------------------------------------- 1 | #ifndef OS_CPU_H 2 | #define OS_CPU_H 3 | 4 | #include "stm32l1xx.h" 5 | #include "core_cm3.h" 6 | #include "core_cmFunc.h" 7 | 8 | #define DISABLE_INTERRUPTS { __asm inline("CPSID I \n"); } 9 | #define ENABLE_INTERRUPTS { __asm inline("CPSIE I \n"); } 10 | 11 | 12 | #define os_cpu_SVCHandler SVC_Handler 13 | #define os_cpu_PendSVHandler PendSV_Handler 14 | #define os_cpu_SysTickHandler SysTick_Handler 15 | 16 | 17 | /* Make PendSV and SysTick the lowest priority interrupts. */ 18 | #define os_cpu_setup_PendSV() (*(uint32_t volatile *)0xE000ED20 |= (0xFFU << 16)) 19 | #define os_cpu_trigger_PendSV() (*(uint32_t volatile *)0xE000ED04 = (1U << 28)) 20 | 21 | extern void os_cpu_systick_init_freq(uint32_t cpu_freq); 22 | 23 | #endif -------------------------------------------------------------------------------- /AK-mOS/task_list.h: -------------------------------------------------------------------------------- 1 | #ifndef __TASK_LIST_H__ 2 | #define __TASK_LIST_H__ 3 | 4 | #include "os_task.h" 5 | 6 | extern const task_t app_task_table[]; 7 | 8 | /*****************************************************************************/ 9 | /* DECLARE: Task ID 10 | * 11 | */ 12 | /*****************************************************************************/ 13 | enum 14 | { 15 | /* SYSTEM TASKS */ 16 | 17 | /* APP TASKS */ 18 | TASK_1_ID, 19 | TASK_2_ID, 20 | TASK_3_ID, 21 | 22 | /* EOT task ID (Size of task table)*/ 23 | TASK_EOT_ID, 24 | }; 25 | 26 | /*****************************************************************************/ 27 | /* DECLARE: Task function 28 | */ 29 | /*****************************************************************************/ 30 | /* APP TASKS */ 31 | extern void task_1(void *p_arg); 32 | extern void task_2(void *p_arg); 33 | extern void task_3(void *p_arg); 34 | #endif //__TASK_LIST_H__ 35 | -------------------------------------------------------------------------------- /AK-mOS/Inc/os_kernel.h: -------------------------------------------------------------------------------- 1 | /* 2 | * os_kernel.h 3 | * 4 | * Created on: Jun 26, 2024 5 | * Author: giahu 6 | * 7 | * THE KERNEL IS A PRE-DEFINE KERNEL THAT ALL THE TASKS HAVE TO CREATE 8 | * BEFORE KERNEL STARTS 9 | */ 10 | 11 | #ifndef OS_KERNEL_H 12 | #define OS_KERNEL_H 13 | 14 | #ifdef __cplusplus 15 | extern "C" 16 | { 17 | #endif 18 | 19 | #include "os_cfg.h" 20 | #include "os_log.h" 21 | #include 22 | #include 23 | #include 24 | 25 | #if OS_CFG_PRIO_MAX > 255u || OS_CFG_PRIO_MAX < 0u 26 | #error OS_CFG_PRIO_MAX have to be between 0-255 27 | #endif 28 | 29 | #define OS_TRUE ((uint8_t)1) 30 | #define OS_FALSE ((uint8_t)0) 31 | 32 | #define os_assert(exp, err) ((exp) ? (void)0 : LOG_ASSERT("%s", err)) 33 | 34 | extern void os_critical_enter(void); 35 | extern void os_critical_exit(void); 36 | 37 | extern void os_init(void); 38 | extern void os_run(void); 39 | 40 | #define ENTER_CRITICAL() os_critical_enter() 41 | #define EXIT_CRITICAL() os_critical_exit() 42 | 43 | #ifdef __cplusplus 44 | } 45 | #endif 46 | #endif /* OS_KERNEL_H */ 47 | -------------------------------------------------------------------------------- /AK-mOS/os_cfg.h: -------------------------------------------------------------------------------- 1 | /* 2 | * os_cfg.h 3 | * 4 | * Created on: Jun 26, 2024 5 | * Author: giahu 6 | */ 7 | 8 | #ifndef OS_CFG_H 9 | #define OS_CFG_H 10 | 11 | #ifdef __cplusplus 12 | extern "C" 13 | { 14 | #endif 15 | #include "system.h" 16 | #include 17 | 18 | /* Kernel common config */ 19 | #define OS_CFG_HEAP_SIZE ((size_t)1024 * 3u) 20 | #define OS_CFG_PRIO_MAX (10) 21 | #define OS_CFG_DELAY_MAX ((uint32_t)0xffffffffUL) 22 | 23 | /* Task config */ 24 | #define OS_CFG_TASK_STK_SIZE_MIN ((size_t)17u) // (Min > 64 byte) In stack, equal to x 4 bytes 25 | #define OS_CFG_TASK_STACK_FILL_BYTE (0x5Au) 26 | #define OS_CFG_TASK_MSG_Q_SIZE_NORMAL (8u) 27 | 28 | /* Messages config */ 29 | #define OS_CFG_MSG_POOL_SIZE (32u) 30 | 31 | /* Timers config */ 32 | #define OS_CFG_TIMER_POOL_SIZE (8u) /* Max num of timer */ 33 | #define OS_CFG_TIMER_TASK_PRI (0u) /* Recommend as high as possible */ 34 | 35 | /* Log config */ 36 | #define OS_CFG_USE_LOG (1u) 37 | 38 | /* Command line interface config */ 39 | #define OS_CFG_USE_CLI (0u) 40 | 41 | #if (OS_CFG_USE_LOG || OS_CFG_USE_CLI) == 1 42 | /* Your print method here */ 43 | #define USER_PRINT(fmt, ...) SYS_PRINT((const char*)fmt, ##__VA_ARGS__) 44 | #else 45 | #define USER_PRINT(fmt, ...) ((void*)0) 46 | #endif 47 | 48 | #ifdef __cplusplus 49 | } 50 | #endif 51 | #endif /* OS_CFG_H */ -------------------------------------------------------------------------------- /AK-mOS/Inc/os_task.h: -------------------------------------------------------------------------------- 1 | /* 2 | * os_task.h 3 | * 4 | * Created on: Jun 26, 2024 5 | * Author: giahu 6 | */ 7 | 8 | #ifndef OS_TASK_H 9 | #define OS_TASK_H 10 | 11 | #ifdef __cplusplus 12 | extern "C" 13 | { 14 | #endif 15 | 16 | #include 17 | #include 18 | #include "os_cfg.h" 19 | 20 | #include "os_msg.h" 21 | 22 | 23 | /* Task states */ 24 | typedef enum 25 | { 26 | TASK_STATE_RUNNING = 0, 27 | TASK_STATE_READY, 28 | TASK_STATE_DELAYED, 29 | TASK_STATE_SUSPENDED, 30 | TASK_STATE_SUSPENDED_ON_MSG, 31 | TASK_STATE_DELAYED_ON_MSG 32 | } task_state_t; 33 | 34 | typedef struct task_tcb *task_handle_t; /*Reference (pointer) of TCB*/ 35 | typedef void (*task_func_t)(void *p_arg); 36 | typedef uint8_t task_id_t; 37 | 38 | typedef struct 39 | { 40 | // task_handle_t * const p_tsk_handle; 41 | task_id_t id; 42 | task_func_t pf_task; 43 | void *p_arg; 44 | uint8_t prio; 45 | size_t queue_size; 46 | size_t stack_size; 47 | } task_t; 48 | 49 | uint32_t os_task_get_tick(void); 50 | 51 | void os_task_create_list(task_t *task_tbl, uint8_t size); 52 | 53 | uint8_t os_task_increment_tick(void); 54 | 55 | void os_task_delay(const uint32_t tick_to_delay); 56 | 57 | void os_task_start(void); 58 | 59 | void os_task_post_msg_dynamic(uint8_t des_task_id, int32_t sig, void *p_content, uint8_t msg_size); 60 | 61 | void os_task_post_msg_pure(uint8_t des_task_id, int32_t sig); 62 | 63 | msg_t *os_task_wait_for_msg(uint32_t time_out); 64 | 65 | #ifdef __cplusplus 66 | } 67 | #endif 68 | #endif /* OS_TASK_H */ -------------------------------------------------------------------------------- /AK-mOS/Src/os_prio.c: -------------------------------------------------------------------------------- 1 | #include "os_prio.h" 2 | static uint32_t prio_curr; 3 | static uint8_t prio_tbl[OS_PRIO_TBL_SIZE]; 4 | 5 | void os_prio_init() 6 | { 7 | uint8_t i; 8 | for (i = 0u; i < OS_PRIO_TBL_SIZE; i++) 9 | { 10 | prio_tbl[i] = 0u; 11 | } 12 | /* OS_CFG_PRIO_MAX-1 is the lowest priority level and that is idle task's prio */ 13 | os_prio_insert(OS_CFG_PRIO_MAX - 1); 14 | } 15 | 16 | void os_prio_insert(uint32_t prio) 17 | { 18 | uint8_t bit; 19 | uint8_t row; 20 | 21 | row = (uint32_t)(prio / (8u)); 22 | bit = (uint8_t)prio & ((8u) - 1u); 23 | prio_tbl[row] |= (uint8_t)1u << (((8u) - 1u) - bit); 24 | } 25 | 26 | void os_prio_remove(uint32_t prio) 27 | { 28 | uint8_t bit; 29 | uint8_t row; 30 | 31 | row = (uint32_t)(prio / (8u)); 32 | bit = (uint8_t)prio & ((8u) - 1u); 33 | prio_tbl[row] &= ~((uint8_t)1u << (((8u) - 1u) - bit)); 34 | } 35 | 36 | uint32_t os_prio_get_highest(void) 37 | { 38 | uint8_t *p_tbl; 39 | uint32_t prio; 40 | 41 | prio = 0u; 42 | p_tbl = &prio_tbl[0]; 43 | while (*p_tbl == 0u) 44 | { /* Search the bitmap table for the highest priority */ 45 | prio += (8u); /* Compute the step of each CPU_DATA entry */ 46 | p_tbl++; 47 | } 48 | 49 | uint8_t bit = (uint8_t)prio & ((8u) - 1u); 50 | while (!(*p_tbl & ((uint8_t)1u << (((8u) - 1u) - bit)))) 51 | { 52 | prio++; 53 | bit = (uint8_t)prio & ((8u) - 1u); 54 | } 55 | return (prio); 56 | } 57 | 58 | uint32_t os_prio_get_curr(void) 59 | { 60 | return prio_curr; 61 | } -------------------------------------------------------------------------------- /AK-mOS/Inc/os_timer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * os_timer.h 3 | * 4 | * Created on: Dec 6, 2024 5 | * Author: giahu 6 | */ 7 | 8 | #ifndef OS_TIMER_H 9 | #define OS_TIMER_H 10 | 11 | #ifdef __cplusplus 12 | extern "C" 13 | { 14 | #endif 15 | #include "os_list.h" 16 | #include 17 | #include 18 | #include 19 | 20 | typedef struct timer os_timer_t; 21 | typedef struct timer_pool timer_pool_t; 22 | typedef uint8_t timer_id_t; 23 | typedef void (*timer_cb)(); 24 | 25 | typedef enum 26 | { 27 | TIMER_ONE_SHOT, 28 | TIMER_PERIODIC 29 | } timer_type_t; 30 | 31 | struct timer 32 | { 33 | os_timer_t *next; 34 | timer_id_t id; /* Maybe for debugging */ 35 | list_item_t timer_list_item; /* Value of this item plays as time stamp to trigger timer*/ 36 | 37 | int32_t sig; /* Timer signal*/ 38 | uint8_t des_task_id; 39 | timer_cb func_cb; /* Callback funtion runs on timer task, !!! keep it short and simple as in interrupt*/ 40 | 41 | uint32_t period; /* In case one-shot timer, this field equals 0 */ 42 | }; 43 | 44 | void os_timer_init(void); /* Runs on kernel init */ 45 | 46 | void os_timer_processing(); /* Runs on timer task */ 47 | 48 | /* These APIs run on other tasks, where they are calling*/ 49 | os_timer_t *os_timer_create(timer_id_t id, int32_t sig, timer_cb func_cb, uint8_t des_task_id, uint32_t period, timer_type_t type); 50 | 51 | void os_timer_start(os_timer_t *p_timer, uint32_t tick_to_wait); 52 | void os_timer_reset(os_timer_t *p_timer); 53 | void os_timer_remove(os_timer_t *p_timer); 54 | 55 | #ifdef __cplusplus 56 | } 57 | #endif 58 | #endif /* OS_TIMER_H */ 59 | -------------------------------------------------------------------------------- /AK-mOS/Inc/os_msg.h: -------------------------------------------------------------------------------- 1 | /* 2 | * os_msg.h 3 | * 4 | * Created on: Jun 26, 2024 5 | * Author: giahu 6 | */ 7 | 8 | #ifndef OS_MSG_H 9 | #define OS_MSG_H 10 | 11 | #ifdef __cplusplus 12 | extern "C" 13 | { 14 | #endif 15 | 16 | #include "os_cfg.h" 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | typedef struct msg msg_t; 23 | typedef struct msg_queue msg_queue_t; 24 | typedef struct msg_pool msg_pool_t; 25 | 26 | typedef enum 27 | { 28 | MSG_TYPE_PURE = 0, 29 | MSG_TYPE_DYNAMIC 30 | } msg_type_t; 31 | 32 | struct msg 33 | { 34 | msg_t *next; 35 | 36 | uint8_t size; 37 | int32_t sig; 38 | uint8_t *content_ptr; 39 | 40 | msg_type_t type; 41 | 42 | /* task header */ 43 | uint8_t src_task_id; 44 | uint8_t des_task_id; 45 | }; 46 | 47 | struct msg_queue 48 | { 49 | msg_t *head_ptr; 50 | msg_t *tail_ptr; 51 | uint8_t size_max; 52 | uint8_t size_curr; 53 | }; 54 | 55 | void os_msg_init(void); 56 | 57 | void os_msg_free(msg_t *p_msg); 58 | 59 | void os_msg_queue_init(msg_queue_t *p_msg_q, uint8_t size); 60 | 61 | void os_msg_queue_put_dynamic(msg_queue_t *p_msg_q, int32_t sig, void *p_content, uint8_t size); 62 | 63 | void os_msg_queue_put_pure(msg_queue_t *p_msg_q, int32_t sig); 64 | 65 | msg_t *os_msg_queue_get(msg_queue_t *p_msg_q); 66 | 67 | void *os_msg_get_dynamic_data(msg_t *p_msg, uint8_t *p_msg_size); 68 | 69 | msg_t *os_msg_queue_get_pure(msg_queue_t *p_msg_q); 70 | 71 | int32_t os_msg_get_pure_data(msg_t *p_msg); 72 | 73 | 74 | #ifdef __cplusplus 75 | } 76 | #endif 77 | #endif /* OS_MSG_H */ 78 | -------------------------------------------------------------------------------- /AK-mOS/Src/os_kernel.c: -------------------------------------------------------------------------------- 1 | #include "os_kernel.h" 2 | 3 | #include "os_cpu.h" 4 | #include "os_msg.h" 5 | #include "os_timer.h" 6 | #include "os_prio.h" 7 | #include "os_task.h" 8 | #include "os_log.h" 9 | #include "task_list.h" 10 | 11 | static uint16_t critical_nesting_count = (uint16_t)0u; 12 | 13 | void os_critical_enter(void) 14 | { 15 | DISABLE_INTERRUPTS 16 | critical_nesting_count++; 17 | } 18 | 19 | void os_critical_exit(void) 20 | { 21 | os_assert(critical_nesting_count, "NESTING CRITICAL UNBALANCED"); 22 | critical_nesting_count--; 23 | if (critical_nesting_count == 0) 24 | { 25 | ENABLE_INTERRUPTS 26 | } 27 | } 28 | 29 | static void 30 | os_start_first_task(void) 31 | { 32 | __asm volatile( 33 | " ldr r0, =0xE000ED08 \n" /* Use the NVIC offset register to locate the stack. */ 34 | " ldr r0, [r0] \n" 35 | " ldr r0, [r0] \n" 36 | " msr msp, r0 \n" /* Set the msp back to the start of the stack. */ 37 | " cpsie i \n" /* Globally enable interrupts. */ 38 | " cpsie f \n" 39 | " dsb \n" 40 | " isb \n" 41 | " svc 0 \n" /* System call to start first task. */ 42 | " nop \n" 43 | " .ltorg \n" 44 | ); 45 | } 46 | 47 | void os_init(void) 48 | { 49 | if (TASK_EOT_ID < 1u) 50 | { 51 | LOG_ERROR("OS_ERR_NO_TASK_AVAILABLE - Entering while loop"); 52 | DISABLE_INTERRUPTS 53 | while(1); 54 | } 55 | os_prio_init(); 56 | os_msg_init(); 57 | os_timer_init(); 58 | } 59 | 60 | void os_run(void) 61 | { 62 | os_task_start(); 63 | os_cpu_systick_init_freq(SystemCoreClock); 64 | os_cpu_setup_PendSV(); 65 | os_start_first_task(); 66 | } 67 | -------------------------------------------------------------------------------- /AK-mOS/Inc/os_log.h: -------------------------------------------------------------------------------- 1 | #ifndef OS_LOG_H 2 | #define OS_LOG_H 3 | 4 | #include 5 | #include "os_cfg.h" 6 | 7 | #define KNRM "\x1B[0m" 8 | #define KRED "\x1B[31m" 9 | #define KGRN "\x1B[32m" 10 | #define KYEL "\x1B[33m" 11 | #define KBLU "\x1B[34m" 12 | #define KMAG "\x1B[35m" 13 | #define KCYN "\x1B[36m" 14 | #define KWHT "\x1B[37m" 15 | 16 | #define LOG_DBG_EN (1u) 17 | #define LOG_WARN_EN (1u) 18 | #define LOG_PRINT_EN (1u) 19 | #define LOG_ERROR_EN (1u) 20 | #define LOG_ASSERT_EN (1u) 21 | #define LOG_SIG_EN (1u) 22 | 23 | #if ( LOG_DBG_EN & OS_CFG_USE_LOG ) == 1 24 | #define LOG_DBG(fmt, ...) USER_PRINT(KBLU "[DEBUG: %s:%d] " KYEL fmt KNRM "\r\n", (uint8_t *)__FILE__, __LINE__, ##__VA_ARGS__) 25 | #else 26 | #define LOG_DBG(fmt, ...) ((void*)0) 27 | #endif 28 | 29 | #if ( LOG_WARN_EN & OS_CFG_USE_LOG ) == 1 30 | #define LOG_WARN(fmt, ...) USER_PRINT(KYEL "[WARN: %s:%d] " KNRM fmt KNRM "\r\n", (uint8_t *)__FILE__, __LINE__, ##__VA_ARGS__) 31 | #else 32 | #define LOG_WARN(fmt, ...) ((void*)0) 33 | #endif 34 | 35 | #if ( LOG_PRINT_EN & OS_CFG_USE_LOG ) == 1 36 | #define LOG_PRINT(fmt, ...) USER_PRINT("[PRINTLN] " fmt "\r\n", ##__VA_ARGS__) 37 | #else 38 | #define LOG_PRINT(fmt, ...) ((void*)0) 39 | #endif 40 | 41 | #if ( LOG_ERROR_EN & OS_CFG_USE_LOG ) == 1 42 | #define LOG_ERROR(fmt, ...) USER_PRINT(KRED "[ERROR: %s:%d] " fmt KNRM "\r\n", (uint8_t *)__FILE__, __LINE__, ##__VA_ARGS__) 43 | #else 44 | #define LOG_ERROR(fmt, ...) ((void*)0) 45 | #endif 46 | 47 | #if ( LOG_ASSERT_EN & OS_CFG_USE_LOG ) == 1 48 | #define LOG_ASSERT(fmt, ...) USER_PRINT(KRED "[ASSERT FAILED: %s:%d] " fmt KNRM "\r\n", (uint8_t *)__FILE__, __LINE__, ##__VA_ARGS__) 49 | #else 50 | #define LOG_ASSERT(fmt, ...) ((void*)0) 51 | #endif 52 | 53 | #if ( LOG_SIG_EN & OS_CFG_USE_LOG ) == 1 54 | #define LOG_SIG(fmt, ...) USER_PRINT(KGRN "[SIGNAL: %s:%d] " KMAG fmt KNRM "\r\n", (uint8_t *)__FILE__, __LINE__, ##__VA_ARGS__) 55 | #else 56 | #define LOG_SIG(fmt, ...) ((void*)0) 57 | #endif 58 | 59 | #endif /* OS_LOG_H */ -------------------------------------------------------------------------------- /AK-mOS/Inc/os_list.h: -------------------------------------------------------------------------------- 1 | /* 2 | * os_list.h 3 | * 4 | * Created on: Jun 26, 2024 5 | * Author: giahu 6 | */ 7 | 8 | #ifndef OS_LIST_H 9 | #define OS_LIST_H 10 | 11 | #ifdef __cplusplus 12 | extern "C" 13 | { 14 | #endif 15 | 16 | #include 17 | #include 18 | #include "os_kernel.h" 19 | 20 | typedef struct list list_t; 21 | typedef struct list_item list_item_t; 22 | 23 | struct list_item 24 | { 25 | struct list_item *next_ptr; /* Pointer to NextItem*/ 26 | struct list_item *prev_ptr; /* Pointer to PrevItem*/ 27 | uint32_t value; /* Value of this item*/ 28 | void *owner_ptr; /*Owner of this item (TCB usually)*/ 29 | struct list *list_ptr; /* Pointer to the list in which this list item is placed (if any). */ 30 | }; 31 | 32 | struct list 33 | { 34 | struct list_item *curr_item_ptr; /* Used to walk through the list in round-robin case */ 35 | struct list_item end_item; /* Used to mark the end of list */ 36 | uint16_t num_of_items; 37 | }; 38 | 39 | #define list_item_set_owner(p_list_item, p_owner) ((p_list_item)->owner_ptr = (void *)(p_owner)) 40 | #define list_item_get_owner(p_list_item) ((p_list_item)->owner_ptr) 41 | #define list_item_set_value(p_list_item, val) ((p_list_item)->value = (uint32_t)(val)) 42 | #define list_item_get_value(p_list_item) ((p_list_item)->value) 43 | #define list_item_get_list_contain(p_list_item) ((p_list_item)->list_ptr) 44 | 45 | #define list_get_head_item_value(p_list) ((((p_list)->end_item).next_ptr)->value) 46 | #define list_get_head_item(p_list) (((p_list)->end_item).next_ptr) 47 | #define list_get_owner_of_head_item(p_list) (list_item_get_owner(((p_list)->end_item).next_ptr)) 48 | #define list_get_end_item(p_list) ((p_list)->end_item) 49 | #define list_get_num_item(p_list) (((p_list)->num_of_items)) 50 | #define list_is_empty(p_list) (((p_list)->num_of_items == (uint8_t)0) ? OS_TRUE : OS_FALSE) 51 | 52 | void *list_get_owner_of_next_item(list_t *const p_list); 53 | 54 | void os_list_init(list_t *const p_list); 55 | void os_list_item_init(list_item_t *const p_list_item); 56 | list_item_t *list_item_get_next(list_item_t *p_list_item); 57 | list_item_t *list_item_get_prev(list_item_t *p_list_item); 58 | void os_list_insert_end(list_t *const p_list, list_item_t *const p_list_item); 59 | void os_list_insert(list_t *const p_list, list_item_t *const p_list_item); 60 | uint16_t os_list_remove(list_item_t *const p_list_item); 61 | 62 | #ifdef __cplusplus 63 | } 64 | #endif 65 | #endif /* OS_LIST_H */ 66 | -------------------------------------------------------------------------------- /AK-mOS/Src/os_cpu.c: -------------------------------------------------------------------------------- 1 | #include "os_cpu.h" 2 | #include "os_task.h" 3 | #include "os_kernel.h" 4 | 5 | 6 | #include "stm32l1xx.h" 7 | #include "stm32l1xx_conf.h" 8 | #include "system_stm32l1xx.h" 9 | #include "core_cm3.h" 10 | #include "core_cmFunc.h" 11 | 12 | /*Passing SystemCoreClock to init tick at every 1ms*/ 13 | void os_cpu_systick_init_freq(uint32_t cpu_freq) 14 | { 15 | volatile uint32_t ticks = cpu_freq / 1000; 16 | NVIC_InitTypeDef NVIC_InitStructure; 17 | 18 | NVIC_InitStructure.NVIC_IRQChannel = SysTick_IRQn; 19 | NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; 20 | NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; 21 | NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 22 | 23 | SysTick->LOAD = ticks - 1; /* set reload register */ 24 | 25 | NVIC_Init(&NVIC_InitStructure); 26 | NVIC_SetPriority(SysTick_IRQn, 1); 27 | 28 | SysTick->VAL = 0; /* Load the SysTick Counter Value */ 29 | SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | 30 | SysTick_CTRL_TICKINT_Msk | 31 | SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */ 32 | } 33 | 34 | #ifdef __cplusplus 35 | extern "C" 36 | { 37 | #endif 38 | void os_cpu_SVCHandler(void) 39 | { 40 | __asm volatile( 41 | "CPSID I \n" // Prevent interruption during context switch 42 | "LDR R1, =tcb_curr_ptr \n" // get pointer to TCB current 43 | "LDR R1, [R1] \n" // get TCB current = pointer to StkPtr 44 | "LDR R0, [R1] \n" // get StkPtr 45 | "LDMIA R0!, {R4-R11} \n" // 46 | "MSR PSP, R0 \n" // 47 | "ORR LR, #0xD \n" // LR = 0xFFFFFFFD return to threadmode 48 | "CPSIE I \n" // 49 | "BX LR \n" // 50 | ); 51 | } 52 | #ifdef __cplusplus 53 | } 54 | #endif 55 | 56 | #ifdef __cplusplus 57 | extern "C" 58 | { 59 | #endif 60 | 61 | #if 1 62 | void os_cpu_PendSVHandler(void) 63 | { 64 | __asm volatile( 65 | //"CPSID I \n" //Prevent interruption during context switch 66 | "MRS R0, PSP \n" // PSP is process stack pointer 67 | "CBZ R0, OS_CPU_PendSVHandler_nosave \n" // Skip register save the first time 68 | 69 | "SUBS R0, R0, #0x20 \n" // Save remaining regs r4-11 on process stack 70 | "STM R0, {R4-R11} \n" // 71 | 72 | "LDR R1, =tcb_curr_ptr \n" // OSTCBCur->OSTCBStkPtr = SP; 73 | "LDR R1, [R1]\n" // 74 | "STR R0, [R1] \n" // R0 is SP of process being switched out 75 | 76 | /* At this point, entire context of process has been saved */ 77 | 78 | "OS_CPU_PendSVHandler_nosave: \n" // 79 | "LDR R0, =tcb_curr_ptr \n" // OSTCBCur = OSTCBHighRdy; 80 | "LDR R1, =tcb_high_rdy_ptr \n" // 81 | "LDR R2, [R1] \n" // 82 | "STR R2, [R0] \n" // 83 | 84 | "LDR R0, [R2] \n" // R0 is new process SP; SP = OSTCBHighRdy->OSTCBStkPtr; 85 | "LDM R0, {R4-R11} \n" // Restore r4-11 from new process stack 86 | "ADDS R0, R0, #0x20 \n" // 87 | "MSR PSP, R0 \n" // Load PSP with new process SP 88 | "ORR LR, LR, #0x04 \n" // Ensure exception return uses process stack 89 | //"CPSIE I \n" // 90 | "BX LR \n" // Exception return will restore remaining context 91 | ); 92 | } 93 | #endif 94 | 95 | #ifdef __cplusplus 96 | } 97 | #endif 98 | 99 | #ifdef __cplusplus 100 | extern "C" 101 | { 102 | #endif 103 | void os_cpu_SysTickHandler() 104 | { 105 | DISABLE_INTERRUPTS 106 | /* Increment the RTOS tick. */ 107 | if (os_task_increment_tick() == OS_TRUE) 108 | { 109 | /* A context switch is required. Context switching is performed in 110 | * the PendSV interrupt. Pend the PendSV interrupt. */ 111 | os_cpu_trigger_PendSV(); 112 | } 113 | ENABLE_INTERRUPTS 114 | } 115 | 116 | #ifdef __cplusplus 117 | } 118 | #endif 119 | -------------------------------------------------------------------------------- /AK-mOS/Src/os_list.c: -------------------------------------------------------------------------------- 1 | #include "os_cfg.h" 2 | #include "os_list.h" 3 | 4 | void os_list_init(list_t *const p_list) 5 | { 6 | p_list->end_item.value = OS_CFG_DELAY_MAX; 7 | 8 | /* End item points to itself when list is empty */ 9 | p_list->end_item.next_ptr = (list_item_t *)&(p_list->end_item); 10 | p_list->end_item.prev_ptr = (list_item_t *)&(p_list->end_item); 11 | 12 | p_list->num_of_items = (uint16_t)0U; 13 | } 14 | 15 | void os_list_item_init(list_item_t *const p_list_item) 16 | { 17 | p_list_item->list_ptr = NULL; /* The list is more important, all the members of item will be set later */ 18 | } 19 | 20 | void os_list_insert_end(list_t *const p_list, list_item_t *const p_list_item) 21 | { 22 | if (list_get_num_item(p_list) == 0u) 23 | { 24 | p_list_item->next_ptr = &(p_list->end_item); 25 | p_list_item->prev_ptr = &(p_list->end_item); 26 | 27 | p_list->end_item.next_ptr = p_list_item; 28 | p_list->end_item.prev_ptr = p_list_item; 29 | 30 | p_list->curr_item_ptr = p_list_item; 31 | } 32 | else 33 | { 34 | list_item_t *const p_last_item = p_list->end_item.prev_ptr; 35 | 36 | p_last_item->next_ptr = p_list_item; 37 | p_list_item->prev_ptr = p_last_item; 38 | 39 | p_list_item->next_ptr = &(p_list->end_item); 40 | p_list->end_item.prev_ptr = p_list_item; 41 | } 42 | 43 | /* Remember which list the item is in. */ 44 | p_list_item->list_ptr = p_list; 45 | 46 | (p_list->num_of_items)++; 47 | } 48 | 49 | list_item_t *list_item_get_next(list_item_t *p_list_item) 50 | { 51 | if ((p_list_item)->next_ptr != &(list_item_get_list_contain(p_list_item)->end_item)) 52 | return (p_list_item)->next_ptr; 53 | else 54 | return (p_list_item)->next_ptr->next_ptr; 55 | } 56 | list_item_t *list_item_get_prev(list_item_t *p_list_item) 57 | { 58 | if ((p_list_item)->prev_ptr != &(list_item_get_list_contain(p_list_item)->end_item)) 59 | return (p_list_item)->prev_ptr; 60 | else 61 | return (p_list_item)->prev_ptr->prev_ptr; 62 | } 63 | 64 | void os_list_insert(list_t *const p_list, list_item_t *const p_list_item) 65 | { 66 | if (list_get_num_item(p_list) == 0u) 67 | os_list_insert_end(p_list, p_list_item); 68 | else 69 | { 70 | list_item_t *p_iterator; 71 | const uint32_t value_to_insert = p_list_item->value; 72 | if (value_to_insert == OS_CFG_DELAY_MAX) 73 | { 74 | p_iterator = p_list->end_item.prev_ptr; 75 | } 76 | else 77 | { 78 | for (p_iterator = (list_item_t *)&(p_list->end_item); p_iterator->next_ptr->value <= value_to_insert; p_iterator = p_iterator->next_ptr) 79 | { 80 | /* Iterate through list */ 81 | } 82 | } 83 | p_list_item->next_ptr = p_iterator->next_ptr; 84 | p_list_item->next_ptr->prev_ptr = p_list_item; 85 | p_list_item->prev_ptr = p_iterator; 86 | p_iterator->next_ptr = p_list_item; 87 | 88 | /* Remember which list the item is in. This allows fast removal of the 89 | * item later. */ 90 | p_list_item->list_ptr = p_list; 91 | 92 | (p_list->num_of_items)++; 93 | } 94 | } 95 | 96 | uint16_t os_list_remove(list_item_t *const p_list_item) 97 | { 98 | list_t *const p_list = p_list_item->list_ptr; 99 | 100 | p_list_item->next_ptr->prev_ptr = p_list_item->prev_ptr; 101 | p_list_item->prev_ptr->next_ptr = p_list_item->next_ptr; 102 | 103 | /* Update curr item to the previous */ 104 | if (p_list->curr_item_ptr == p_list_item) 105 | { 106 | p_list->curr_item_ptr = p_list_item->prev_ptr; 107 | } 108 | else 109 | { 110 | // mtCOVERAGE_TEST_MARKER(); 111 | } 112 | 113 | p_list_item->list_ptr = NULL; 114 | (p_list->num_of_items)--; 115 | 116 | return p_list->num_of_items; 117 | } 118 | 119 | void *list_get_owner_of_next_item(list_t *const p_list) 120 | { 121 | list_t *const p_const_list = (p_list); 122 | /* Increment the index to the next item and return the item, ensuring */ 123 | /* we don't return the marker used at the end of the list. */ 124 | (p_const_list)->curr_item_ptr = (p_const_list)->curr_item_ptr->next_ptr; 125 | 126 | if ((void *)(p_const_list)->curr_item_ptr == (void *)&((p_const_list)->end_item)) 127 | { 128 | (p_const_list)->curr_item_ptr = (p_const_list)->curr_item_ptr->next_ptr; 129 | } 130 | 131 | return (p_const_list)->curr_item_ptr->owner_ptr; 132 | } -------------------------------------------------------------------------------- /AK-mOS/Src/os_msg.c: -------------------------------------------------------------------------------- 1 | #include "os_msg.h" 2 | #include "os_mem.h" 3 | #include "os_kernel.h" 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | static msg_t msg_pool[OS_CFG_MSG_POOL_SIZE]; 10 | static msg_t *free_list_msg_pool; 11 | static uint8_t msg_pool_used; 12 | 13 | static void msg_pool_init(void) 14 | { 15 | ENTER_CRITICAL(); 16 | uint8_t index; 17 | 18 | free_list_msg_pool = (msg_t *)msg_pool; 19 | 20 | for (index = 0; index < OS_CFG_MSG_POOL_SIZE; index++) 21 | { 22 | if (index == (OS_CFG_MSG_POOL_SIZE - 1)) 23 | { 24 | msg_pool[index].next = NULL; 25 | } 26 | else 27 | { 28 | msg_pool[index].next = (msg_t *)&msg_pool[index + 1]; 29 | } 30 | } 31 | 32 | msg_pool_used = 0; 33 | 34 | EXIT_CRITICAL(); 35 | } 36 | void os_msg_init(void) 37 | { 38 | msg_pool_init(); 39 | } 40 | 41 | void os_msg_free(msg_t *p_msg) 42 | { 43 | ENTER_CRITICAL(); 44 | 45 | p_msg->next = free_list_msg_pool; 46 | free_list_msg_pool = p_msg; 47 | if (p_msg->type == MSG_TYPE_DYNAMIC) 48 | { 49 | os_mem_free(p_msg->content_ptr); 50 | } 51 | msg_pool_used--; 52 | 53 | EXIT_CRITICAL(); 54 | } 55 | 56 | void os_msg_queue_init(msg_queue_t *p_msg_q, 57 | uint8_t size) 58 | { 59 | p_msg_q->head_ptr = NULL; 60 | p_msg_q->tail_ptr = NULL; 61 | p_msg_q->size_max = size; 62 | p_msg_q->size_curr = 0u; 63 | } 64 | 65 | void os_msg_queue_put_dynamic(msg_queue_t *p_msg_q, 66 | int32_t sig, 67 | void *p_content, 68 | uint8_t size) 69 | { 70 | ENTER_CRITICAL(); 71 | msg_t *p_msg; 72 | msg_t *p_msg_tail; 73 | if (p_msg_q->size_curr >= p_msg_q->size_max) 74 | { 75 | // OSUniversalError = OS_ERR_MSG_QUEUE_IS_FULL; 76 | os_assert(0, "OS_ERR_MSG_QUEUE_IS_FULL"); 77 | EXIT_CRITICAL(); 78 | return; 79 | } 80 | if (msg_pool_used >= OS_CFG_MSG_POOL_SIZE) 81 | { 82 | // OSUniversalError = OS_ERR_MSG_POOL_IS_FULL; 83 | os_assert(0, "OS_ERR_MSG_POOL_IS_FULL"); 84 | EXIT_CRITICAL(); 85 | return; 86 | } 87 | 88 | p_msg = free_list_msg_pool; 89 | free_list_msg_pool = p_msg->next; 90 | msg_pool_used++; 91 | 92 | if (p_msg_q->size_curr == 0u) /* Is this first message placed in the queue? */ 93 | { 94 | p_msg_q->head_ptr = p_msg; /* Yes */ 95 | p_msg_q->tail_ptr = p_msg; 96 | p_msg_q->size_curr = 1u; 97 | p_msg->next = NULL; 98 | } 99 | else 100 | { 101 | p_msg_tail = p_msg_q->tail_ptr; 102 | p_msg_tail->next = p_msg; 103 | p_msg_q->tail_ptr = p_msg; 104 | p_msg->next = NULL; 105 | 106 | p_msg_q->size_curr++; 107 | } 108 | 109 | p_msg->type = MSG_TYPE_DYNAMIC; 110 | p_msg->sig = sig; 111 | p_msg->size = size; 112 | p_msg->content_ptr = (uint8_t *)os_mem_malloc(size); 113 | memcpy(p_msg->content_ptr, p_content, size); 114 | 115 | EXIT_CRITICAL(); 116 | } 117 | 118 | void os_msg_queue_put_pure(msg_queue_t *p_msg_q, int32_t sig) 119 | { 120 | ENTER_CRITICAL(); 121 | msg_t *p_msg; 122 | msg_t *p_msg_tail; 123 | if (p_msg_q->size_curr >= p_msg_q->size_max) 124 | { 125 | // OSUniversalError = OS_ERR_MSG_QUEUE_IS_FULL; 126 | os_assert(0, "OS_ERR_MSG_QUEUE_IS_FULL"); 127 | EXIT_CRITICAL(); 128 | return; 129 | } 130 | if (msg_pool_used >= OS_CFG_MSG_POOL_SIZE) 131 | { 132 | /* This states that u forget to free msg somewhere.*/ 133 | // OSUniversalError = OS_ERR_MSG_POOL_IS_FULL; 134 | os_assert(0, "OS_ERR_MSG_POOL_IS_FULL"); 135 | EXIT_CRITICAL(); 136 | return; 137 | } 138 | 139 | p_msg = free_list_msg_pool; 140 | free_list_msg_pool = p_msg->next; 141 | msg_pool_used++; 142 | 143 | if (p_msg_q->size_curr == 0u) /* Is this first message placed in the queue? */ 144 | { 145 | p_msg_q->head_ptr = p_msg; /* Yes */ 146 | p_msg_q->tail_ptr = p_msg; 147 | p_msg_q->size_curr = 1u; 148 | p_msg->next = NULL; 149 | } 150 | else 151 | { 152 | p_msg_tail = p_msg_q->tail_ptr; 153 | p_msg_tail->next = p_msg; 154 | p_msg_q->tail_ptr = p_msg; 155 | p_msg->next = NULL; 156 | 157 | p_msg_q->size_curr++; 158 | } 159 | 160 | p_msg->type = MSG_TYPE_PURE; 161 | p_msg->sig = sig; 162 | 163 | EXIT_CRITICAL(); 164 | } 165 | 166 | msg_t *os_msg_queue_get(msg_queue_t *p_msg_q) 167 | { 168 | msg_t *p_msg; 169 | 170 | if (p_msg_q->size_curr == 0u) 171 | { 172 | // OSUniversalError = OS_ERR_MSG_QUEUE_IS_EMPTY; 173 | // os_assert(0); 174 | return NULL; 175 | } 176 | 177 | p_msg = p_msg_q->head_ptr; 178 | 179 | p_msg_q->head_ptr = p_msg->next; 180 | 181 | if (p_msg_q->size_curr == 1u) /* Are there any more messages in the queue? */ 182 | { 183 | p_msg_q->head_ptr = NULL; 184 | p_msg_q->tail_ptr = NULL; 185 | p_msg_q->size_curr = 0u; 186 | } 187 | else 188 | { 189 | p_msg_q->size_curr--; /* Yes, One less message in the queue */ 190 | } 191 | 192 | return (p_msg); 193 | } 194 | 195 | void *os_msg_get_dynamic_data(msg_t *p_msg, 196 | uint8_t *p_msg_size) 197 | { 198 | *p_msg_size = p_msg->size; 199 | return p_msg->content_ptr; 200 | } 201 | 202 | msg_t *os_msg_queue_get_pure(msg_queue_t *p_msg_q) 203 | { 204 | msg_t *p_msg; 205 | 206 | if (p_msg_q->size_curr == 0u) 207 | { 208 | // OSUniversalError = OS_ERR_MSG_QUEUE_IS_EMPTY; 209 | // os_assert(0); 210 | return NULL; 211 | } 212 | 213 | p_msg = p_msg_q->head_ptr; 214 | 215 | p_msg_q->head_ptr = p_msg->next; 216 | 217 | if (p_msg_q->size_curr == 1u) /* Are there any more messages in the queue? */ 218 | { 219 | p_msg_q->head_ptr = NULL; 220 | p_msg_q->tail_ptr = NULL; 221 | p_msg_q->size_curr = 0u; 222 | } 223 | else 224 | { 225 | p_msg_q->size_curr--; /* Yes, One less message in the queue */ 226 | } 227 | 228 | return (p_msg); 229 | } 230 | 231 | int32_t os_msg_get_pure_data(msg_t *p_msg) 232 | { 233 | return p_msg->sig; 234 | } -------------------------------------------------------------------------------- /AK-mOS/Src/os_mem.c: -------------------------------------------------------------------------------- 1 | /* 2 | ********************************************************************************************************* 3 | * MEMORY MANAGEMENT 4 | * 5 | * File : os_mem.c 6 | * Version : none 7 | * Author : JiaHui 8 | ********************************************************************************************************* 9 | */ 10 | 11 | #include "os_cfg.h" 12 | #include "os_mem.h" 13 | #include "os_kernel.h" 14 | #include 15 | #include 16 | 17 | 18 | #if 1 19 | #define ALIGNMENT ((size_t)4u) // must be a power of 2 20 | 21 | #define mem_align(size) (size_t)(((size) + (ALIGNMENT - 1)) & ~(ALIGNMENT - 1)) 22 | 23 | #define MIN_SIZE_TO_SPLIT ((size_t)8u) // In byte 24 | 25 | #define SIZE_OF_BLOCK_HEADER ((size_t)mem_align(sizeof(mem_blk_header_t))) 26 | 27 | static uint8_t mem_heap[OS_CFG_HEAP_SIZE]; 28 | static mem_blk_header_t mem_blk_start; 29 | static mem_blk_header_t *mem_blk_end_ptr = NULL; 30 | 31 | static uint32_t byte_available = 0; 32 | 33 | 34 | static void os_mem_heap_init(void) 35 | { 36 | uint32_t total_heap_size = OS_CFG_HEAP_SIZE; 37 | uint32_t heap_addr = (uint32_t)mem_heap; 38 | if ((heap_addr & (ALIGNMENT - 1)) != 0) /* If address of heap memory is not alligned */ 39 | { 40 | heap_addr += (ALIGNMENT - 1); 41 | heap_addr &= ALIGNMENT; 42 | total_heap_size -= heap_addr - (uint32_t)mem_heap; /* Recalculate size of heap memory */ 43 | } 44 | 45 | mem_blk_end_ptr = (mem_blk_header_t *)(heap_addr); /* Address of first block */ 46 | mem_blk_end_ptr->size = total_heap_size - SIZE_OF_BLOCK_HEADER; 47 | mem_blk_end_ptr->state = MEM_STATE_FREE; 48 | mem_blk_end_ptr->next_ptr = NULL; 49 | 50 | mem_blk_start.size = 0; 51 | mem_blk_start.next_ptr = mem_blk_end_ptr; 52 | 53 | byte_available = total_heap_size - SIZE_OF_BLOCK_HEADER; 54 | } 55 | 56 | void *os_mem_malloc(size_t size) 57 | { 58 | uint8_t *p_return = NULL; 59 | if (mem_blk_end_ptr == NULL) 60 | { 61 | os_mem_heap_init(); 62 | } 63 | size = mem_align(size); 64 | if (size == 0 || size > byte_available) 65 | { 66 | os_assert(0, "OS_ERR_MEM_INVALID_SIZE"); 67 | return p_return; // Invalid size 68 | } 69 | 70 | else 71 | { 72 | mem_blk_header_t *p_block = &mem_blk_start; 73 | p_block = p_block->next_ptr; 74 | while (p_block != mem_blk_end_ptr) 75 | { 76 | if (p_block->size < size || p_block->state == MEM_STATE_BUSY) 77 | { 78 | p_block = p_block->next_ptr; 79 | } 80 | else 81 | break; 82 | } 83 | if (p_block != NULL) 84 | { 85 | if (p_block == mem_blk_end_ptr && p_block->size < size) 86 | { 87 | os_assert(0, "OS_ERR_MEM_NO_BLOCK"); 88 | return (void *)p_return; // No block available 89 | } 90 | 91 | if ((p_block->size - size) > MIN_SIZE_TO_SPLIT) 92 | { 93 | p_return = ((uint8_t *)p_block + SIZE_OF_BLOCK_HEADER); 94 | 95 | mem_blk_header_t *p_new_block = (mem_blk_header_t *)(((uint8_t *)p_block) + SIZE_OF_BLOCK_HEADER + size); 96 | p_new_block->size = p_block->size - size - SIZE_OF_BLOCK_HEADER; 97 | p_new_block->state = MEM_STATE_FREE; 98 | p_new_block->next_ptr = p_block->next_ptr; 99 | if (p_new_block->next_ptr == NULL) 100 | { 101 | mem_blk_end_ptr = p_new_block; 102 | } 103 | 104 | p_block->size = size; 105 | p_block->state = MEM_STATE_BUSY; 106 | p_block->next_ptr = p_new_block; 107 | // p_block = p_block->next_ptr; 108 | 109 | byte_available -= (size + SIZE_OF_BLOCK_HEADER); 110 | } 111 | 112 | else 113 | { 114 | p_return = ((uint8_t *)p_block + SIZE_OF_BLOCK_HEADER); 115 | p_block->state = MEM_STATE_BUSY; 116 | byte_available -= p_block->size; 117 | } 118 | return (void *)p_return; 119 | } 120 | else 121 | { 122 | os_assert(0, "OS_ERR_MEM_BLOCK_NULL"); 123 | /* MEM_FAULT (p_block null) */ 124 | } 125 | } 126 | return (void *) p_return; 127 | } 128 | 129 | void os_mem_free(void *p_addr) 130 | { 131 | if (mem_blk_end_ptr == NULL) 132 | { 133 | os_mem_heap_init(); 134 | } 135 | if (((uint8_t *)p_addr) > ((uint8_t *)mem_blk_end_ptr + SIZE_OF_BLOCK_HEADER + mem_blk_end_ptr->size)) 136 | { 137 | os_assert(0, "OS_ERR_MEM_INVALID_ADDRESS"); 138 | return; // Invalid address 139 | } 140 | 141 | if ((size_t)(((uint8_t *)p_addr) - SIZE_OF_BLOCK_HEADER) < (size_t)mem_blk_start.next_ptr) 142 | { 143 | os_assert(0, "OS_ERR_MEM_INVALID_ADDRESS"); 144 | return; // Invalid address 145 | } 146 | else 147 | { 148 | mem_blk_header_t *p_block = (mem_blk_header_t *)((uint8_t *)p_addr - SIZE_OF_BLOCK_HEADER); 149 | if (p_block->state == MEM_STATE_FREE) 150 | { 151 | return; 152 | } 153 | mem_blk_header_t *p_block_temp = &mem_blk_start; 154 | mem_blk_header_t *p_prev_block = p_block_temp; 155 | 156 | while (p_block_temp != mem_blk_end_ptr && (uint8_t *)p_block_temp != (uint8_t *)p_block) 157 | { 158 | p_prev_block = p_block_temp; 159 | p_block_temp = p_block_temp->next_ptr; 160 | } 161 | if (p_block_temp != NULL) 162 | { 163 | byte_available += p_block_temp->size; 164 | 165 | p_block_temp->state = MEM_STATE_FREE; 166 | 167 | // Merge the next block 168 | if (p_block_temp->next_ptr != NULL && p_block_temp->next_ptr->state == MEM_STATE_FREE) 169 | { 170 | byte_available += SIZE_OF_BLOCK_HEADER; 171 | 172 | p_block_temp->size += p_block_temp->next_ptr->size + SIZE_OF_BLOCK_HEADER; 173 | p_block_temp->next_ptr = p_block_temp->next_ptr->next_ptr; 174 | if (p_block_temp->next_ptr == NULL) 175 | { 176 | mem_blk_end_ptr = p_block_temp; 177 | } 178 | } 179 | 180 | // Merge the prev block 181 | if (p_prev_block->state == MEM_STATE_FREE && (uint8_t *)p_prev_block != (uint8_t*)&mem_blk_start) 182 | { 183 | byte_available += SIZE_OF_BLOCK_HEADER; 184 | 185 | p_prev_block->size += p_block_temp->size + SIZE_OF_BLOCK_HEADER; 186 | p_prev_block->next_ptr = p_block_temp->next_ptr; 187 | } 188 | } 189 | else 190 | { 191 | os_assert(0, "OS_ERR_MEM_INVALID_ADDRESS"); 192 | return; // Invalid address 193 | } 194 | } 195 | return; 196 | } 197 | 198 | #else 199 | void *os_mem_malloc(size_t size) 200 | { 201 | uint32_t * p_return = malloc(size); 202 | if(p_return != NULL )SYS_PRINT("Addr of block is: 0x%08x\t\tSize: %d\n", (uint32_t *)p_return, size); 203 | else SYS_PRINT("Malloc failed\n"); 204 | return p_return; 205 | } 206 | 207 | void os_mem_free(void * p_addr) 208 | { 209 | free(p_addr); 210 | return; 211 | } 212 | #endif 213 | -------------------------------------------------------------------------------- /AK-mOS/Src/os_timer.c: -------------------------------------------------------------------------------- 1 | #include "os_kernel.h" 2 | #include "os_timer.h" 3 | #include "os_task.h" 4 | #include "os_msg.h" 5 | #include "task_list.h" 6 | #include "os_list.h" 7 | 8 | #define REF_TASK_TIMER_ID ((task_id_t)TASK_EOT_ID + 1u) 9 | 10 | static os_timer_t timer_pool[OS_CFG_TIMER_POOL_SIZE]; 11 | static os_timer_t *free_list_timer_pool; 12 | static uint8_t timer_pool_used; 13 | 14 | static uint32_t timer_counter; 15 | 16 | static list_t timer_list_1; 17 | static list_t timer_list_2; 18 | 19 | static list_t *volatile timer_list_ptr; /* Current */ 20 | static list_t *volatile overflow_timer_list_ptr; 21 | 22 | static volatile uint32_t next_tick_to_unblock_timer = (uint32_t)OS_CFG_DELAY_MAX; 23 | 24 | static void timer_pool_init() 25 | { 26 | uint8_t index; 27 | 28 | free_list_timer_pool = (os_timer_t *)timer_pool; 29 | 30 | for (index = 0; index < OS_CFG_TIMER_POOL_SIZE; index++) 31 | { 32 | if (index == (OS_CFG_TIMER_POOL_SIZE - 1)) 33 | { 34 | timer_pool[index].next = NULL; 35 | } 36 | else 37 | { 38 | timer_pool[index].next = (os_timer_t *)&timer_pool[index + 1]; 39 | } 40 | } 41 | 42 | timer_pool_used = 0; 43 | } 44 | 45 | static void init_timer_lists(void) 46 | { 47 | /* Initialize lists */ 48 | os_list_init(&timer_list_1); 49 | os_list_init(&timer_list_2); 50 | timer_list_ptr = &timer_list_1; 51 | overflow_timer_list_ptr = &timer_list_2; 52 | /********************/ 53 | } 54 | 55 | static void timer_switch_lists() 56 | { 57 | list_t *p_list_temp; 58 | p_list_temp = timer_list_ptr; 59 | timer_list_ptr = overflow_timer_list_ptr; 60 | overflow_timer_list_ptr = p_list_temp; 61 | 62 | if (list_is_empty(timer_list_ptr) == OS_TRUE) 63 | { 64 | next_tick_to_unblock_timer = OS_CFG_DELAY_MAX; 65 | } 66 | else 67 | { 68 | next_tick_to_unblock_timer = 0u; 69 | } 70 | } 71 | static void add_timer_to_list(os_timer_t *p_timer) 72 | { 73 | ENTER_CRITICAL(); 74 | { 75 | const uint32_t const_tick = os_task_get_tick(); 76 | uint32_t tick_to_trigger = list_item_get_value(&(p_timer->timer_list_item)); 77 | if (tick_to_trigger < const_tick) 78 | { 79 | /* Wake time has overflowed. Place this item in the overflow 80 | * list. */ 81 | os_list_insert(overflow_timer_list_ptr, &(p_timer->timer_list_item)); 82 | } 83 | else 84 | { 85 | /* The wake time has not overflowed, so the current block list 86 | * is used. */ 87 | os_list_insert(timer_list_ptr, &(p_timer->timer_list_item)); 88 | } 89 | } 90 | EXIT_CRITICAL(); 91 | } 92 | static void update_next_tick_to_unblock() 93 | { 94 | os_timer_t *p_timer; 95 | uint32_t item_value; 96 | if (list_is_empty(timer_list_ptr) == OS_TRUE) 97 | { 98 | next_tick_to_unblock_timer = OS_CFG_DELAY_MAX; 99 | } 100 | else 101 | { 102 | p_timer = list_get_owner_of_head_item(timer_list_ptr); 103 | item_value = list_item_get_value(&(p_timer->timer_list_item)); 104 | if (item_value < next_tick_to_unblock_timer) 105 | { 106 | next_tick_to_unblock_timer = item_value; 107 | } 108 | } 109 | } 110 | 111 | os_timer_t *os_timer_create(timer_id_t id, int32_t sig, timer_cb func_cb, uint8_t des_task_id, uint32_t period, timer_type_t type) 112 | { 113 | /*It is important to set value for timer_list_item, because it holds time stamp*/ 114 | if (des_task_id > (TASK_EOT_ID - 1U)) 115 | { 116 | // OSUniversalError = OS_ERR_DES_TASK_ID_INVALID; 117 | os_assert(0, "OS_ERR_DES_TASK_ID_INVALID"); 118 | return NULL; 119 | } 120 | if (des_task_id == REF_TASK_TIMER_ID) 121 | { 122 | // OSUniversalError = OS_ERR_CAN_NOT_SET_DES_TO_ITSELF; 123 | os_assert(0, "OS_ERR_CAN_NOT_SET_DES_TO_ITSELF"); 124 | return NULL; 125 | } 126 | if (timer_pool_used >= OS_CFG_TIMER_POOL_SIZE) 127 | { 128 | // OSUniversalError = OS_ERR_TIMER_POOL_IS_FULL; 129 | os_assert(0, "OS_ERR_TIMER_POOL_IS_FULL"); 130 | return NULL; 131 | } 132 | if (period == 0u && type == TIMER_PERIODIC) 133 | { 134 | // OSUniversalError = OS_ERR_TIMER_NOT_ACECPT_ZERO_PERIOD; 135 | os_assert(0, "OS_ERR_TIMER_NOT_ACECPT_ZERO_PERIOD"); 136 | return NULL; 137 | } 138 | os_timer_t *p_timer; 139 | p_timer = free_list_timer_pool; 140 | free_list_timer_pool = p_timer->next; 141 | timer_pool_used++; 142 | 143 | p_timer->id = id; 144 | p_timer->sig = sig; 145 | p_timer->func_cb = func_cb; 146 | p_timer->des_task_id = des_task_id; 147 | 148 | switch (type) 149 | { 150 | case TIMER_ONE_SHOT: 151 | /* code */ 152 | p_timer->period = 0; 153 | break; 154 | case TIMER_PERIODIC: 155 | p_timer->period = period; 156 | break; 157 | default: 158 | break; 159 | } 160 | /* Make connection */ 161 | os_list_item_init(&(p_timer->timer_list_item)); 162 | list_item_set_owner(&(p_timer->timer_list_item), (void *)p_timer); 163 | 164 | // list_item_set_value(&(p_timer->timer_list_item), period + os_task_get_tick()); 165 | // add_timer_to_list(p_timer); 166 | // update_next_tick_to_unblock(); 167 | // os_task_post_msg_pure(OS_CFG_TIMER_TASK_ID, TIMER_CMD_UPDATE); 168 | return p_timer; 169 | } 170 | void os_timer_remove(os_timer_t *p_timer) 171 | { 172 | ENTER_CRITICAL(); 173 | 174 | p_timer->next = free_list_timer_pool; 175 | free_list_timer_pool = p_timer; 176 | timer_pool_used--; 177 | 178 | if (list_item_get_list_contain(&(p_timer->timer_list_item)) != NULL) 179 | os_list_remove(&(p_timer->timer_list_item)); 180 | 181 | EXIT_CRITICAL(); 182 | } 183 | 184 | void os_timer_init(void) 185 | { 186 | timer_pool_init(); 187 | init_timer_lists(); 188 | next_tick_to_unblock_timer = OS_CFG_DELAY_MAX; 189 | /*TODO: Create a task for timer here, or maybe in os_task.c and call os_timer_processing*/ 190 | } 191 | void os_timer_processing() 192 | { 193 | msg_t *p_msg; 194 | os_timer_t *p_timer; 195 | uint32_t item_value; 196 | static uint32_t last_time = (uint32_t)0U; 197 | uint32_t time_now = os_task_get_tick(); 198 | if (time_now < last_time) 199 | { 200 | /* Overflown */ 201 | timer_switch_lists(); 202 | } 203 | if (time_now >= next_tick_to_unblock_timer) 204 | { 205 | for (;;) 206 | { 207 | if (list_is_empty(timer_list_ptr) == OS_TRUE) 208 | { 209 | next_tick_to_unblock_timer = OS_CFG_DELAY_MAX; 210 | break; 211 | } 212 | else 213 | { 214 | p_timer = list_get_owner_of_head_item(timer_list_ptr); 215 | item_value = list_item_get_value(&(p_timer->timer_list_item)); 216 | if (item_value > time_now) 217 | { 218 | /* Stop condition */ 219 | next_tick_to_unblock_timer = item_value; 220 | break; 221 | } 222 | os_list_remove(&(p_timer->timer_list_item)); 223 | 224 | if (p_timer->func_cb != NULL) 225 | p_timer->func_cb(); 226 | else 227 | os_task_post_msg_pure(p_timer->des_task_id, p_timer->sig); 228 | if (p_timer->period != 0) 229 | { 230 | list_item_set_value(&(p_timer->timer_list_item), p_timer->period + time_now); 231 | add_timer_to_list(p_timer); 232 | } 233 | else 234 | os_timer_remove(p_timer); /* One shot */ 235 | update_next_tick_to_unblock(); 236 | } 237 | } 238 | } 239 | last_time = time_now; 240 | p_msg = os_task_wait_for_msg(next_tick_to_unblock_timer - time_now); 241 | if (p_msg != NULL) 242 | os_msg_free(p_msg); 243 | } 244 | 245 | void os_timer_start(os_timer_t *p_timer, uint32_t tick_to_wait) 246 | { 247 | uint32_t time_now = os_task_get_tick(); 248 | 249 | list_item_set_value(&(p_timer->timer_list_item), tick_to_wait + time_now); 250 | 251 | add_timer_to_list(p_timer); 252 | update_next_tick_to_unblock(); 253 | os_task_post_msg_pure(REF_TASK_TIMER_ID, 0); // Dummy signal 254 | } 255 | 256 | void os_timer_reset(os_timer_t *p_timer) 257 | { 258 | if (list_item_get_list_contain(&(p_timer->timer_list_item)) == NULL) 259 | { 260 | // OSUniversalError = OS_ERR_TIMER_IS_NOT_RUNNING; 261 | os_assert(0, "OS_ERR_TIMER_IS_NOT_RUNNING"); 262 | return; 263 | } 264 | uint32_t time_now = os_task_get_tick(); 265 | os_list_remove(&(p_timer->timer_list_item)); 266 | if (p_timer->period != 0) 267 | { 268 | list_item_set_value(&(p_timer->timer_list_item), p_timer->period + time_now); 269 | add_timer_to_list(p_timer); 270 | } 271 | else 272 | os_timer_remove(p_timer); /* One shot */ 273 | update_next_tick_to_unblock(); 274 | os_task_post_msg_pure(REF_TASK_TIMER_ID, 0); // Dummy signal 275 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AK-mOS - The simple RTOS on AK base kit 2 | ![ak-embedded-software-logo](https://github.com/user-attachments/assets/950faf1e-97a8-4c08-8ec5-7a07cee47c2b) 3 | 4 | 5 | 6 | AK-mOS is a mini embedded operating system developed based on [freeRTOS](https://github.com/FreeRTOS/FreeRTOS-Kernel) which has the following features: 7 | - Preemptive scheduling 8 | - Round-robin scheduling 9 | - Inter-task communiation 10 | - Software timer 11 | 12 | 13 | ## Sample application using AK-mOS 14 | - [Runner game](https://github.com/snoopy3921/Runner-game) 15 | 16 | ![image3](https://github.com/user-attachments/assets/4b952e29-58d7-49d5-ae96-e84a738656ad) 17 | 18 | - [Leta](https://github.com/snoopy3921/Leta) 19 | 20 | ![P1210208](https://github.com/user-attachments/assets/1d0afc90-26ab-48f3-a28d-80354fe4e874) 21 | 22 | 23 | 24 | ## Port 25 | Kernel required tick interrupt and context switch (PendSV interrupt) to work properly. Both tick interrupt and context switch written for ARM Cortex-M3 only ([AK base kit](https://github.com/epcbtech/ak-base-kit-stm32l151) using Stm32L1). So it will also run fine on Stm32f1. 26 | 27 | In file os_cpu.h, change these header files to appropriate microcontroller (ARM-Cortex M3) 28 | ``` C 29 | #include "stm32l1xx.h" 30 | #include "core_cm3.h" 31 | #include "core_cmFunc.h" 32 | ``` 33 | For porting in the future, different "os_cpu" files are needed for different architectures. 34 | 35 | ## Getting started 36 | 37 | Add the kernel to project, and in application implement file (normally main.c or main.cpp), include these header files. 38 | ``` C 39 | #include "os_kernel.h" 40 | #include "os_mem.h" 41 | #include "os_task.h" 42 | #include "os_msg.h" 43 | #include "task_list.h" 44 | ``` 45 | ### 1. Configuration 46 | All config needed are included in os_cfg.h file with the simplicity of this OS, these are some important explanations: 47 | 48 | The memory management first acquires this amount of memory (In byte) and use it to alloc to which component need memory also retrieve memory back. 49 | ``` C 50 | #define OS_CFG_HEAP_SIZE ((size_t)1024 * 3u) 51 | ``` 52 | 53 | Tasks can have priority from 0 to OS_CFG_PRIO_MAX - 1 54 | ``` C 55 | #define OS_CFG_PRIO_MAX (30u) 56 | ``` 57 | 58 | Minimum stack size for tasks to run well. 59 | ``` C 60 | #define OS_CFG_TASK_STK_SIZE_MIN ((size_t)32u) // In stack, equal to x 4 bytes 61 | ``` 62 | 63 | Kernel has a pool to store messages, increase OS_CFG_MSG_POOL_SIZE if application use large amount of messages. 64 | 65 | ``` C 66 | #define OS_CFG_MSG_POOL_SIZE (16u) 67 | ``` 68 | ### 2. Task creation and using 69 | Tasks in AK-mOS are pre-created (because of lacking scheduler locker), so that to create tasks, require to create before kernel running. 70 | 71 | To create tasks, register task parameters in "task_list.h" and ""task_list.cpp": 72 | 73 | In task_list.h, declare task ID in enum, and task funtions. Declare taskID in enum in increasing order start with unsigned integer is important because this help kernel to manage tasks in task list array. 74 | At the end of task ID, don't change or remove TASK_EOT_ID, it informs kernel about number of tasks. 75 | ``` C 76 | /*****************************************************************************/ 77 | /* DECLARE: Internal Task ID 78 | * Note: Task id MUST be increasing order. 79 | */ 80 | /*****************************************************************************/ 81 | enum 82 | { 83 | /* SYSTEM TASKS */ 84 | 85 | /* APP TASKS */ 86 | TASK_BUTTONS_ID, 87 | TASK_2_ID, 88 | TASK_DISPLAY_ID, 89 | TASK_BUZZER_ID, 90 | 91 | /* EOT task ID (Size of task table)*/ 92 | TASK_EOT_ID, 93 | }; 94 | 95 | /*****************************************************************************/ 96 | /* DECLARE: Task function 97 | */ 98 | /*****************************************************************************/ 99 | /* APP TASKS */ 100 | extern void task_buttons(void *p_arg); 101 | extern void task_2(void *p_arg); 102 | extern void task_display(void *p_arg); 103 | extern void task_buzzer(void *p_arg); 104 | ``` 105 | 106 | In task_list.cpp, put parameters for each task in this order (task id, task_func, arg, prio, msg_queue_size, stk_size) 107 | - task id pick from enum task id in task_list.h 108 | - task_func also pick from task funtion from task_list.h 109 | - arg is the argument pass to funtions (not tested yet). 110 | - priority of task, the lower, the more important. 0 is the highest priority. 111 | - msg_queue_size is the size of queue message in task. For tasks that doesn't need to receive message(signal or data), just leave it zero. 112 | - stk_size is the size allocated for each task. Minimum stack size declared in os_cfg.h. 113 | - [**NOTE: With heavy task, increase it. If program doesn't run, increase it!!!**](https://stackoverflow.com/) 114 | 115 | ``` C 116 | const task_t app_task_table[] = { 117 | /*************************************************************************/ 118 | /* TASK */ 119 | /* TASK_ID task_func arg prio msg_queue_size stk_size */ 120 | /*************************************************************************/ 121 | {TASK_2_ID, task_2, NULL, 10, OS_CFG_TASK_MSG_Q_SIZE_NORMAL, 32}, 122 | {TASK_BUTTONS_ID, task_buttons, NULL, 0, OS_CFG_TASK_MSG_Q_SIZE_NORMAL, 50}, 123 | {TASK_DISPLAY_ID, task_display, NULL, 8, OS_CFG_TASK_MSG_Q_SIZE_NORMAL, 200}, 124 | {TASK_BUZZER_ID, task_buzzer, NULL, 5, OS_CFG_TASK_MSG_Q_SIZE_NORMAL, 50}, 125 | 126 | }; 127 | ``` 128 | A task looks like this: 129 | ``` C 130 | void task_2(void *p_arg) 131 | { 132 | for(;;) 133 | { 134 | os_task_delay(1000); 135 | } 136 | } 137 | ``` 138 | APIs: 139 | 140 | - Delay an amount of ticks (normally 1 tick = 1ms), pass OS_CFG_DELAY_MAX to block indefinitely till the task get an unblock event. 141 | ``` C 142 | void os_task_delay(const uint32_t tick_to_delay); 143 | ``` 144 | 145 | ### 3. Memory allocation and dealocation 146 | Using first-fit allocation that make the use of memory simple, effective and minimize memory fragmentaion, but it costs disadvantages, mainly on performance if the frequency alloc and free was pretty high. 147 | 148 | APIs: 149 | 150 | ``` C 151 | void *os_mem_malloc(size_t size); // In bytes 152 | 153 | void os_mem_free(void *p_addr); 154 | ``` 155 | These APIs are internally used in kernel to manage memmory of task and messages, but can also use in applcation if needed, of instead using APIs from "stdlib.h" (malloc and free) 156 | ### 3. Communication (messages) 157 | Kernel has one pool to store free messages. Firstly all the messages is kept in message pool. There are 2 types of msg: 158 | - Pure msg contains only signal type int16_t 159 | - Dynamic msg contains pointer to data block and size of that data block 160 | APIs: 161 | ``` C 162 | void os_task_post_msg_dynamic(uint8_t des_task_id, int32_t sig, void *p_content, uint8_t msg_size); 163 | 164 | void os_task_post_msg_pure(uint8_t des_task_id, int32_t sig); 165 | 166 | msg_t *os_task_wait_for_msg(uint32_t time_out); 167 | ``` 168 | **Recommendation using communicated APIs:** 169 | 170 | Post msg to another task, kernel doesn't support to post msg to self 171 | - Pure msg post 172 | ``` C 173 | #define AC_DISPLAY_BUTTON_MODE_PRESSED (1u) 174 | 175 | os_task_post_msg_pure (TASK_BUZZER_ID, AC_DISPLAY_BUTTON_MODE_PRESSED); 176 | ``` 177 | - Dynamic msg post 178 | ``` C 179 | time[3] = {23, 15, 30}; //hour, min, second 180 | 181 | os_task_post_msg_dynamic (TASK_DISPLAY_ID, 0, (void *) &time, sizeof(time)); 182 | ``` 183 | 184 | Task can wait for msg with timeout or indefinitely (as it delays indefinitely). Retrieving msg from "os_task_wait_for_msg", msg could be NULL (timeout expired) or success. 185 | After consuming msg. If you don't have intention to use it after. It is required to free msg to give msg back to msg pool and give memmory back to kernel (In case using dynamic msg). 186 | Call free msg with this API: 187 | ``` C 188 | void os_msg_free(msg_t *p_msg); 189 | ``` 190 | A task consumes msg looks like this: 191 | - Task wait for msg indefinitely 192 | ``` C 193 | void task_buzzer(void *p_arg) 194 | { 195 | int play = 0; 196 | msg_t * msg; 197 | for(;;) 198 | { 199 | msg = os_task_wait_for_msg (OS_CFG_DELAY_MAX); 200 | play = msg->sig; 201 | os_msg_free(msg); 202 | if(play) 203 | { 204 | /*Play tone*/ 205 | play = 0; 206 | } 207 | 208 | } 209 | } 210 | ``` 211 | - Task wait for msg with timeout 212 | ``` C 213 | void task_display(void *p_arg) 214 | { 215 | msg_t * msg; 216 | for(;;) 217 | { 218 | msg = os_task_wait_for_msg(1); // Wait for 1ms 219 | if(msg!= NULL) 220 | { 221 | if(msg->sig == 1) 222 | { 223 | //SYS_PRINT("BUTTON UP RECEIVED\n"); 224 | } 225 | else 226 | { 227 | //SYS_PRINT("BUTTON DOWN RECEIVED\n"); 228 | } 229 | os_msg_free(msg); 230 | } 231 | view_render.update(); 232 | } 233 | } 234 | ``` 235 | ```msg = os_task_wait_for_msg(0);``` Get msg whenever msg available with 0ms 236 | ### 6. Software timer 237 | Kernel has one pool to store free timers. Firstly all the timers are kept in timer pool. 238 | When kernel is initing, it automatically creates one more task for timer (as timer deamon in freeRTOS). The prio of that task configured in "os_cfg.h" 239 | Max num of timers is also configured in "os_cfg.h" 240 | 241 | ``` C 242 | #define OS_CFG_TIMER_POOL_SIZE (8u) /* Max num of timer */ 243 | #define OS_CFG_TIMER_TASK_PRI (0u) /* Recommend as high as possible */ 244 | 245 | ``` 246 | 247 | 248 | APIs: 249 | ``` C 250 | /* These APIs run on other tasks, where they are calling*/ 251 | os_timer_t *os_timer_create(timer_id_t id, int32_t sig, timer_cb func_cb, uint8_t des_task_id, uint32_t period, timer_type_t type); 252 | 253 | void os_timer_start(os_timer_t *p_timer, uint32_t tick_to_wait); 254 | void os_timer_reset(os_timer_t *p_timer); 255 | void os_timer_remove(os_timer_t *p_timer); 256 | ``` 257 | 258 | There are 2 types of timer 259 | ``` C 260 | typedef enum 261 | { 262 | TIMER_ONE_SHOT, 263 | TIMER_PERIODIC 264 | } timer_type_t; 265 | ``` 266 | - TIMER_ONE_SHOT executes 1 time and will be deleted after execution 267 | - TIMER_PERIODIC executes periodically till ``` os_timer_remove``` called. 268 | 269 | 270 | How to use: 271 | 272 | - Using timer to fire a signal to task 273 | ``` C 274 | void task_common(void *p_arg) 275 | { 276 | /* This api will create timer, but it can not be used yet. 277 | * Timer has id: TIMER_ID 278 | * Timer has signal: REFRESH_SIGNAL 279 | * Timer has no callback function: NULL 280 | * Destination task: TASK_DISPLAY_ID 281 | * Timer is periodical with period = 500 ticks 282 | */ 283 | os_timer_t * p_timer1 = os_timer_create(TIMER_ID, REFRESH_SIGNAL, NULL, TASK_DISPLAY_ID, 500, TIMER_PERIODIC); 284 | 285 | /* This api will make the timer that is created to run after 1000 ticks*/ 286 | os_timer_start(p_timer1, 1000); 287 | for(;;) 288 | { 289 | 290 | } 291 | } 292 | 293 | ``` 294 | - Using timer with callback 295 | ``` C 296 | static void blinky() 297 | { 298 | led_life_toggle(); 299 | } 300 | void task_common(void *p_arg) 301 | { 302 | /* This api will create timer, but it can not be used yet. 303 | * Because of using with callback, we can ommit destination task id and signal. 304 | * Timer is periodical with period = 500 ticks 305 | */ 306 | os_timer_t * p_timer1 = os_timer_create(TIMER_ID, 0, blinky, 0, 500, TIMER_PERIODIC); 307 | 308 | /* This api will make the timer that is created to run after 1000 ticks*/ 309 | os_timer_start(p_timer1, 1000); 310 | for(;;) 311 | { 312 | 313 | } 314 | } 315 | 316 | ``` 317 | ```Note:``` 318 | If timer has callback function, it will ignore destination task and signal attached to that task. So to make sending signal runs, make sure callback function = NULL. 319 | 320 | 321 | ### 5. Ending up in main file 322 | ``` C 323 | int main(void) 324 | { 325 | //Init system 326 | //Init drivers 327 | 328 | os_init(); 329 | 330 | os_task_create_list((task_t*)app_task_table, TASK_EOT_ID); 331 | 332 | os_run(); 333 | 334 | 335 | while(1) 336 | { 337 | //Hopefully this will never run ))))) 338 | } 339 | } 340 | ``` 341 | ### 6. Additional 342 | Using interrupt by "deferred interrupt handling". It is better to create a interrupt task with a high enough priority that wait for signal (msg) from interrupt. 343 | ``` C 344 | #ifdef __cplusplus 345 | extern "C" 346 | { 347 | #endif 348 | void EXTI0_IRQHandler(void) 349 | { 350 | ENTER_CRITICAL(); 351 | if (EXTI_GetITStatus(EXTI_Line0) != RESET) 352 | { 353 | os_task_post_msg_pure (TASK_BUTTON_INTERRUPT_ID, INTERRUPT_TRIGGER_SIGNAL); 354 | EXTI_ClearITPendingBit(EXTI_Line0); 355 | } 356 | EXIT_CRITICAL(); 357 | } 358 | #ifdef __cplusplus 359 | } 360 | #endif 361 | ``` 362 | **NOTE: If application is C++ function names are mangled by the compiler, so the linker cannot match the name in the vector table to the user-written ISR and falls back to the default "weak" handler, usually implemented as an empty infinite loop. The canonical way to avoid name mangling in C++ is to enclose the given function (ISR) into extern "C"{} block.** 363 | ## Notes 364 | ``` C 365 | SYS_PRINT(" THE END! "); 366 | ``` 367 | ## TODO: 368 | - Add more sample projects. 369 | - Trying to port to MIK32 (first russian microcontroller). 370 | -------------------------------------------------------------------------------- /AK-mOS/Src/os_task.c: -------------------------------------------------------------------------------- 1 | #include "os_task.h" 2 | #include "os_kernel.h" 3 | #include "os_list.h" 4 | #include "os_mem.h" 5 | #include "os_timer.h" 6 | #include "os_prio.h" 7 | #include "os_cpu.h" 8 | #include 9 | #include "task_list.h" 10 | 11 | /* For strict compliance with the Cortex-M spec the task start address should 12 | have bit-0 clear, as it is loaded into the PC on exit from an ISR. */ 13 | #define VALUE_START_ADDRESS_MASK ((uint32_t)0xfffffffeUL) 14 | 15 | /* Constants required to set up the initial stack. */ 16 | #define VALUE_INITIAL_XPSR (0x01000000) 17 | 18 | #define TASK_IDLE_ID ((task_id_t)TASK_EOT_ID) 19 | 20 | #define TASK_IDLE_PRI (OS_CFG_PRIO_MAX - 1u) 21 | 22 | #define TASK_TIMER_ID ((task_id_t)TASK_EOT_ID + 1u) 23 | 24 | #define TASK_TIMER_PRI ((uint8_t)OS_CFG_TIMER_TASK_PRI) 25 | 26 | #define TASK_TIMER_STK_SIZE (100u) 27 | 28 | 29 | typedef struct task_tcb task_tcb_t; 30 | 31 | #define SIZE_OF_TCB (sizeof(task_tcb_t)) 32 | 33 | 34 | static task_tcb_t *task_tcb_list[TASK_EOT_ID + 2u]; /*< Holds the list of task tcb. */ 35 | 36 | 37 | task_tcb_t *volatile tcb_curr_ptr = NULL; 38 | task_tcb_t *volatile tcb_high_rdy_ptr = NULL; 39 | 40 | static list_t rdy_task_list[OS_CFG_PRIO_MAX]; /*< Prioritised ready tasks. */ 41 | static list_t dly_task_list_1; /*< Delayed tasks. */ 42 | static list_t dly_task_list_2; /*< Delayed tasks (two lists are used - one for delays that have overflowed the current tick count. */ 43 | static list_t *volatile dly_task_list_ptr; /*< Points to the delayed task list currently being used. */ 44 | static list_t *volatile overflow_dly_task_list_ptr; /*< Points to the delayed task list currently being used to hold tasks that have overflowed the current tick count. */ 45 | static list_t suspended_task_list; /*< Tasks that are currently suspended. */ 46 | 47 | static volatile uint16_t num_of_tasks = (uint16_t)0U; 48 | static volatile uint32_t tick_count = (uint32_t)0u; 49 | static volatile uint32_t ticks_pended = (uint32_t)0U; 50 | static volatile uint32_t next_tick_to_unblock = (uint32_t)OS_CFG_DELAY_MAX; /* Initialised to portMAX_DELAY before the scheduler starts. */ 51 | 52 | static volatile uint8_t sched_is_running = (uint8_t)OS_FALSE; 53 | 54 | uint32_t os_task_get_tick(void) 55 | { 56 | return tick_count; 57 | } 58 | 59 | static void task_idle_func(void *p_arg) 60 | { 61 | for (;;) 62 | { 63 | } 64 | } 65 | 66 | static void task_timer_func(void *p_arg) 67 | { 68 | for (;;) 69 | { 70 | os_timer_processing(); 71 | } 72 | } 73 | 74 | struct task_tcb 75 | { 76 | volatile uint32_t *stk_ptr; /* Stack pointer, has to be the first member of TCB */ 77 | list_item_t state_list_item; /*Item in StateList include Ready, Blocked, Suspended List */ 78 | list_item_t event_list_item; /*Item in Event List */ 79 | uint32_t *stk_limit_ptr; /* Pointer used to set stack 'watermark' limit */ 80 | uint8_t prio; 81 | size_t stk_size; /* Size of task stack (in number of stack elements) */ 82 | uint32_t *stk_base_ptr; /* Pointer to base address of stack */ 83 | task_id_t id; 84 | msg_queue_t msg_queue; 85 | task_state_t state; /* States */ 86 | }; 87 | 88 | static void init_task_lists(void) 89 | { 90 | /* Initialize lists */ 91 | uint8_t prio; 92 | for (prio = 0; prio < OS_CFG_PRIO_MAX; prio++) 93 | { 94 | os_list_init(&(rdy_task_list[prio])); 95 | } 96 | os_list_init(&dly_task_list_1); 97 | os_list_init(&dly_task_list_2); 98 | os_list_init(&suspended_task_list); 99 | dly_task_list_ptr = &dly_task_list_1; 100 | overflow_dly_task_list_ptr = &dly_task_list_2; 101 | /********************/ 102 | } 103 | 104 | static void task_switch_delay_lists() 105 | { 106 | list_t *p_list_temp; 107 | p_list_temp = dly_task_list_ptr; 108 | dly_task_list_ptr = overflow_dly_task_list_ptr; 109 | overflow_dly_task_list_ptr = p_list_temp; 110 | 111 | if (list_is_empty(dly_task_list_ptr) == OS_TRUE) 112 | { 113 | /* The new current delayed list is empty. Set xNextTaskUnblockTime to 114 | * the maximum possible value so it is extremely unlikely that the 115 | * if( xTickCount >= xNextTaskUnblockTime ) test will pass until 116 | * there is an item in the delayed list. */ 117 | next_tick_to_unblock = OS_CFG_DELAY_MAX; 118 | } 119 | else 120 | { 121 | /* The new current delayed list is not empty, get the value of 122 | * the item at the head of the delayed list. This is the time at 123 | * which the task at the head of the delayed list should be removed 124 | * from the Blocked state. */ 125 | task_tcb_t *p_tcb = list_get_owner_of_head_item(dly_task_list_ptr); 126 | uint32_t item_value = list_item_get_value(&(p_tcb->state_list_item)); 127 | next_tick_to_unblock = item_value; 128 | } 129 | } 130 | 131 | static void add_new_task_to_rdy_list(task_tcb_t *p_tcb) 132 | { 133 | ENTER_CRITICAL(); 134 | { 135 | num_of_tasks++; 136 | if (num_of_tasks == 1) 137 | { 138 | init_task_lists(); 139 | tcb_curr_ptr = p_tcb; 140 | } 141 | else 142 | { 143 | if (tcb_curr_ptr->prio <= p_tcb->prio) 144 | { 145 | tcb_curr_ptr = p_tcb; 146 | } 147 | } 148 | os_list_insert_end(&(rdy_task_list[p_tcb->prio]), &((p_tcb)->state_list_item)); 149 | if (list_get_num_item(&(rdy_task_list[p_tcb->prio])) == 1u) 150 | { 151 | os_prio_insert(p_tcb->prio); 152 | } 153 | /*Save state*/ 154 | p_tcb->state = TASK_STATE_READY; 155 | } 156 | EXIT_CRITICAL(); 157 | } 158 | 159 | static void add_task_to_rdy_list(task_tcb_t *p_tcb) 160 | { 161 | os_list_insert_end(&(rdy_task_list[p_tcb->prio]), &((p_tcb)->state_list_item)); 162 | if (list_get_num_item(&(rdy_task_list[p_tcb->prio])) == 1u) 163 | { 164 | os_prio_insert(p_tcb->prio); 165 | } 166 | /*Save state*/ 167 | p_tcb->state = TASK_STATE_READY; 168 | } 169 | 170 | static void add_curr_task_to_delay_list(uint32_t tick_to_delay, uint8_t can_block_indefinitely) 171 | { 172 | uint32_t time_to_wake; 173 | const uint32_t const_tick = tick_count; 174 | if (os_list_remove(&(tcb_curr_ptr->state_list_item)) == 0u) 175 | { 176 | os_prio_remove(tcb_curr_ptr->prio); 177 | } 178 | if ((tick_to_delay == OS_CFG_DELAY_MAX) && (can_block_indefinitely != OS_FALSE)) 179 | { 180 | /* Add the task to the suspended task list instead of a delayed task 181 | * list to ensure it is not woken by a timing event. It will block 182 | * indefinitely. */ 183 | os_list_insert_end(&suspended_task_list, &(tcb_curr_ptr->state_list_item)); 184 | /*Save state*/ 185 | tcb_curr_ptr->state = TASK_STATE_SUSPENDED; 186 | } 187 | else 188 | { 189 | time_to_wake = const_tick + tick_to_delay; 190 | list_item_set_value(&(tcb_curr_ptr->state_list_item), time_to_wake); 191 | 192 | if (time_to_wake < const_tick) 193 | { 194 | /* Wake time has overflowed. Place this item in the overflow 195 | * list. */ 196 | os_list_insert(overflow_dly_task_list_ptr, &(tcb_curr_ptr->state_list_item)); 197 | } 198 | else 199 | { 200 | /* The wake time has not overflowed, so the current block list 201 | * is used. */ 202 | os_list_insert(dly_task_list_ptr, &(tcb_curr_ptr->state_list_item)); 203 | 204 | /*Update next tick to block is important in order scheduler not to miss this stamp 205 | Just update next tick to block in this branch because overflow delay is just the background list 206 | */ 207 | 208 | if (time_to_wake < next_tick_to_unblock) 209 | { 210 | next_tick_to_unblock = time_to_wake; 211 | } 212 | } 213 | /*Save state*/ 214 | tcb_curr_ptr->state = TASK_STATE_DELAYED; 215 | } 216 | uint8_t highest_prio = os_prio_get_highest(); 217 | tcb_high_rdy_ptr = list_get_owner_of_head_item(&(rdy_task_list[highest_prio])); 218 | 219 | /*Save state*/ 220 | tcb_high_rdy_ptr->state = TASK_STATE_RUNNING; 221 | } 222 | 223 | static task_tcb_t *os_task_create(task_id_t id, 224 | task_func_t pf_task, 225 | void *p_arg, 226 | uint8_t prio, 227 | size_t queue_size, 228 | size_t stack_size) 229 | { 230 | if (sched_is_running == OS_TRUE) 231 | { 232 | // OSUniversalError = OS_ERR_SCHED_IS_RUNNING; 233 | os_assert(0, "OS_ERR_SCHED_IS_RUNNING"); 234 | return NULL; 235 | } 236 | if (prio > (OS_CFG_PRIO_MAX - 1U)) 237 | { 238 | // OSUniversalError = OS_ERR_TCB_PRIO_INVALID; 239 | os_assert(0, "OS_ERR_TCB_PRIO_INVALID"); 240 | return NULL; 241 | } 242 | if (pf_task == NULL) 243 | { 244 | // OSUniversalError = OS_ERR_TCB_FUNC_INVALID; 245 | os_assert(0, "OS_ERR_TCB_FUNC_INVALID"); 246 | return NULL; 247 | } 248 | if (stack_size < OS_CFG_TASK_STK_SIZE_MIN) 249 | { 250 | // OSUniversalError = OS_ERR_TCB_STK_SIZE_INVALID; 251 | os_assert(0, "OS_ERR_TCB_STK_SIZE_INVALID"); 252 | return NULL; 253 | } 254 | 255 | 256 | task_tcb_t *p_new_tcb; 257 | uint32_t *p_stack; 258 | 259 | p_stack = os_mem_malloc(stack_size * sizeof(uint32_t)); 260 | if (p_stack != NULL) 261 | { 262 | p_new_tcb = (task_tcb_t *)os_mem_malloc(SIZE_OF_TCB); 263 | if (p_new_tcb != NULL) 264 | { 265 | memset((void *)p_new_tcb, 0x00, SIZE_OF_TCB); 266 | 267 | /*Save stack limit pointer*/ 268 | p_new_tcb->stk_limit_ptr = p_stack; 269 | } 270 | else 271 | { 272 | os_mem_free(p_stack); 273 | // OSUniversalError = OS_ERR_TCB_NOT_ENOUGH_MEM_ALLOC; 274 | os_assert(0, "OS_ERR_TCB_NOT_ENOUGH_MEM_ALLOC"); 275 | return NULL; 276 | } 277 | } 278 | else 279 | { 280 | // OSUniversalError = OS_ERR_TCB_NOT_ENOUGH_MEM_ALLOC; 281 | os_assert(0, "OS_ERR_TCB_NOT_ENOUGH_MEM_ALLOC"); 282 | return NULL; 283 | } 284 | 285 | /*Now TCB and stack are created*/ 286 | uint32_t *p_stack_ptr; 287 | 288 | /* Fill the stack with a known value to assist debugging. */ 289 | //( void ) memset( p_new_tcb->stk_limit_ptr, OS_CFG_TASK_STACK_FILL_BYTE, stack_size ); 290 | 291 | /*Init stack frame*/ 292 | p_stack_ptr = &p_stack[stack_size - (uint32_t)1]; 293 | p_stack_ptr = (uint32_t *)(((uint32_t)p_stack_ptr) & (~((uint32_t)0x007))); /* Allign byte */ 294 | // p_stack_ptr = ( p_stack + ( uint32_t )( ( uint32_t )( stack_size / 4 ) - (uint32_t) 1 ) ); 295 | *(--p_stack_ptr) = VALUE_INITIAL_XPSR; /*Add offset and assign value for xPSR */ 296 | *(--p_stack_ptr) = ((uint32_t)pf_task) & VALUE_START_ADDRESS_MASK; /* PC */ 297 | *(--p_stack_ptr) = (uint32_t)0x000000EU; /* LR */ 298 | p_stack_ptr -= 5; /* R12, R3, R2 and R1. */ 299 | *p_stack_ptr = (uint32_t)p_arg; /* R0 */ 300 | p_stack_ptr -= 8; /* R11, R10, R9, R8, R7, R6, R5 and R4. */ 301 | 302 | /*Save top of stack (Stack pointer)*/ 303 | p_new_tcb->stk_ptr = p_stack_ptr; 304 | 305 | /*Save stack size*/ 306 | p_new_tcb->stk_size = stack_size; 307 | 308 | /*Save ID*/ 309 | p_new_tcb->id = id; 310 | 311 | /*Save prio*/ 312 | p_new_tcb->prio = prio; 313 | // os_prio_insert(prio); 314 | 315 | os_msg_queue_init(&(p_new_tcb->msg_queue), queue_size); 316 | 317 | /* Init linked lists */ 318 | os_list_item_init(&(p_new_tcb->state_list_item)); 319 | os_list_item_init(&(p_new_tcb->event_list_item)); 320 | 321 | list_item_set_owner(&(p_new_tcb->state_list_item), (void *)p_new_tcb); 322 | list_item_set_owner(&(p_new_tcb->event_list_item), (void *)p_new_tcb); 323 | 324 | list_item_set_value(&(p_new_tcb->state_list_item), prio); 325 | 326 | add_new_task_to_rdy_list(p_new_tcb); 327 | 328 | return p_new_tcb; 329 | } 330 | 331 | void os_task_create_list(task_t *task_tbl, uint8_t size) 332 | { 333 | uint8_t idx = 0; 334 | task_tcb_t *p_tcb; 335 | while (idx < size) 336 | { 337 | p_tcb = os_task_create((task_id_t)task_tbl[idx].id, 338 | (task_func_t)task_tbl[idx].pf_task, 339 | (void *)task_tbl[idx].p_arg, 340 | (uint8_t)task_tbl[idx].prio, 341 | (size_t)task_tbl[idx].queue_size, 342 | (size_t)task_tbl[idx].stack_size); 343 | task_tcb_list[task_tbl[idx].id] = p_tcb; 344 | idx++; 345 | } 346 | p_tcb = os_task_create((task_id_t)TASK_TIMER_ID, 347 | (task_func_t)task_timer_func, 348 | (void *)NULL, 349 | (uint8_t)TASK_TIMER_PRI, 350 | (size_t)(OS_CFG_TASK_MSG_Q_SIZE_NORMAL), 351 | (size_t)TASK_TIMER_STK_SIZE); 352 | task_tcb_list[TASK_TIMER_ID] = p_tcb; 353 | 354 | p_tcb = os_task_create((task_id_t)TASK_IDLE_ID, 355 | (task_func_t)task_idle_func, 356 | (void *)NULL, 357 | (uint8_t)TASK_IDLE_PRI, 358 | (size_t)(0u), 359 | (size_t)OS_CFG_TASK_STK_SIZE_MIN); 360 | task_tcb_list[TASK_IDLE_ID] = p_tcb; 361 | } 362 | 363 | uint8_t os_task_increment_tick(void) 364 | { 365 | uint8_t is_switch_needed = OS_FALSE; 366 | task_tcb_t *p_tcb; 367 | uint32_t item_value; 368 | 369 | const uint32_t const_tick = tick_count + (uint32_t)1; 370 | 371 | /* Increment the RTOS tick, switching the delayed and overflowed 372 | * delayed lists if it wraps to 0. */ 373 | tick_count = const_tick; 374 | 375 | if (const_tick == (uint32_t)0U) /* Overflowed, switch delaylist*/ 376 | { 377 | task_switch_delay_lists(); 378 | } 379 | 380 | if (const_tick >= next_tick_to_unblock) 381 | { 382 | for (;;) 383 | { 384 | if (list_is_empty(dly_task_list_ptr) == OS_TRUE) 385 | { 386 | next_tick_to_unblock = OS_CFG_DELAY_MAX; 387 | break; 388 | } 389 | else 390 | { 391 | p_tcb = list_get_owner_of_head_item(dly_task_list_ptr); 392 | item_value = list_item_get_value(&(p_tcb->state_list_item)); 393 | if (item_value > const_tick) 394 | { 395 | /* Stop condition */ 396 | next_tick_to_unblock = item_value; 397 | break; 398 | } 399 | os_list_remove(&(p_tcb->state_list_item)); /*Remove from block state*/ 400 | 401 | /* Is the task waiting on an event also? If so remove 402 | * it from the event list. */ 403 | if (list_item_get_list_contain(&(p_tcb->event_list_item)) != NULL) 404 | { 405 | os_list_remove(&(p_tcb->event_list_item)); 406 | } 407 | add_task_to_rdy_list(p_tcb); 408 | if (p_tcb->prio < tcb_curr_ptr->prio) 409 | { 410 | tcb_high_rdy_ptr = p_tcb; 411 | is_switch_needed = OS_TRUE; 412 | } 413 | } 414 | } 415 | } 416 | 417 | uint8_t highest_prio = os_prio_get_highest(); 418 | if (list_get_num_item(&(rdy_task_list[highest_prio])) > 1u) 419 | { 420 | tcb_high_rdy_ptr = list_get_owner_of_next_item(&(rdy_task_list[highest_prio])); 421 | is_switch_needed = OS_TRUE; 422 | } 423 | /*Save state*/ 424 | if(is_switch_needed == OS_TRUE) tcb_high_rdy_ptr->state = TASK_STATE_RUNNING; 425 | 426 | return is_switch_needed; 427 | } 428 | 429 | void os_task_delay(const uint32_t tick_to_delay) 430 | { 431 | if (tick_to_delay > (uint32_t)0U) 432 | { 433 | ENTER_CRITICAL(); 434 | add_curr_task_to_delay_list(tick_to_delay, OS_FALSE); 435 | os_cpu_trigger_PendSV(); 436 | EXIT_CRITICAL(); 437 | } 438 | } 439 | 440 | void os_task_start(void) 441 | { 442 | tcb_high_rdy_ptr = list_get_owner_of_head_item(&(rdy_task_list[os_prio_get_highest()])); 443 | tcb_curr_ptr = tcb_high_rdy_ptr; 444 | tick_count = 0u; 445 | next_tick_to_unblock = OS_CFG_DELAY_MAX; 446 | sched_is_running = OS_TRUE; 447 | } 448 | 449 | void os_task_post_msg_dynamic(uint8_t des_task_id, int32_t sig, void *p_content, uint8_t msg_size) 450 | { 451 | ENTER_CRITICAL(); 452 | if (task_tcb_list[des_task_id] == tcb_curr_ptr) 453 | { 454 | // OSUniversalError = OS_ERR_TASK_POST_MSG_TO_ITSELF; 455 | os_assert(0, "OS_ERR_TASK_POST_MSG_TO_ITSELF"); 456 | EXIT_CRITICAL(); 457 | return; 458 | } 459 | 460 | switch (task_tcb_list[des_task_id]->state) 461 | { 462 | case TASK_STATE_SUSPENDED_ON_MSG: 463 | os_msg_queue_put_dynamic(&(task_tcb_list[des_task_id]->msg_queue), 464 | sig, 465 | p_content, 466 | msg_size); 467 | 468 | /* Is the task waiting on an event ? If so remove 469 | * it from the event list. */ 470 | if (list_item_get_list_contain(&(task_tcb_list[des_task_id]->event_list_item)) != NULL) 471 | { 472 | os_list_remove(&(task_tcb_list[des_task_id]->event_list_item)); 473 | } 474 | add_task_to_rdy_list(task_tcb_list[des_task_id]); 475 | if (task_tcb_list[des_task_id]->prio < tcb_curr_ptr->prio) 476 | { 477 | tcb_high_rdy_ptr = task_tcb_list[des_task_id]; 478 | 479 | /*Save state*/ 480 | tcb_high_rdy_ptr->state = TASK_STATE_RUNNING; 481 | 482 | os_cpu_trigger_PendSV(); 483 | } 484 | EXIT_CRITICAL(); 485 | break; 486 | case TASK_STATE_DELAYED_ON_MSG: 487 | os_msg_queue_put_dynamic(&(task_tcb_list[des_task_id]->msg_queue), 488 | sig, 489 | p_content, 490 | msg_size); 491 | /* Is the task waiting on an event ? If so remove 492 | * it from the event list. */ 493 | if (list_item_get_list_contain(&(task_tcb_list[des_task_id]->state_list_item)) != NULL) 494 | { 495 | os_list_remove(&(task_tcb_list[des_task_id]->state_list_item)); 496 | } 497 | 498 | add_task_to_rdy_list(task_tcb_list[des_task_id]); 499 | if (task_tcb_list[des_task_id]->prio < tcb_curr_ptr->prio) 500 | { 501 | tcb_high_rdy_ptr = task_tcb_list[des_task_id]; 502 | 503 | /*Save state*/ 504 | tcb_high_rdy_ptr->state = TASK_STATE_RUNNING; 505 | 506 | os_cpu_trigger_PendSV(); 507 | } 508 | EXIT_CRITICAL(); 509 | break; 510 | 511 | default: 512 | os_msg_queue_put_dynamic(&(task_tcb_list[des_task_id]->msg_queue), 513 | sig, 514 | p_content, 515 | msg_size); 516 | EXIT_CRITICAL(); 517 | break; 518 | } 519 | } 520 | 521 | void os_task_post_msg_pure(uint8_t des_task_id, int32_t sig) 522 | { 523 | ENTER_CRITICAL(); 524 | #if 0 /* Under testing */ 525 | if (task_tcb_list[des_task_id] == tcb_curr_ptr) 526 | { 527 | // OSUniversalError = OS_ERR_TASK_POST_MSG_TO_ITSELF; 528 | os_assert(0, "OS_ERR_TASK_POST_MSG_TO_ITSELF"); 529 | EXIT_CRITICAL(); 530 | return; 531 | } 532 | #endif 533 | switch (task_tcb_list[des_task_id]->state) 534 | { 535 | case TASK_STATE_SUSPENDED_ON_MSG: 536 | os_msg_queue_put_pure(&(task_tcb_list[des_task_id]->msg_queue), sig); 537 | /* Is the task waiting on an event ? If so remove 538 | * it from the event list. */ 539 | if (list_item_get_list_contain(&(task_tcb_list[des_task_id]->event_list_item)) != NULL) 540 | { 541 | os_list_remove(&(task_tcb_list[des_task_id]->event_list_item)); 542 | } 543 | add_task_to_rdy_list(task_tcb_list[des_task_id]); 544 | if (task_tcb_list[des_task_id]->prio < tcb_curr_ptr->prio) 545 | { 546 | tcb_high_rdy_ptr = task_tcb_list[des_task_id]; 547 | 548 | /*Save state*/ 549 | tcb_high_rdy_ptr->state = TASK_STATE_RUNNING; 550 | 551 | os_cpu_trigger_PendSV(); 552 | } 553 | EXIT_CRITICAL(); 554 | break; 555 | case TASK_STATE_DELAYED_ON_MSG: 556 | os_msg_queue_put_pure(&(task_tcb_list[des_task_id]->msg_queue), sig); 557 | /* Is the task waiting on an event ? If so remove 558 | * it from the event list. */ 559 | if (list_item_get_list_contain(&(task_tcb_list[des_task_id]->state_list_item)) != NULL) 560 | { 561 | os_list_remove(&(task_tcb_list[des_task_id]->state_list_item)); 562 | } 563 | 564 | /* Is the task waiting on an event also? If so remove 565 | * it from the event list. */ 566 | if (list_item_get_list_contain(&(task_tcb_list[des_task_id]->event_list_item)) != NULL) 567 | { 568 | os_list_remove(&(task_tcb_list[des_task_id]->event_list_item)); 569 | } 570 | 571 | add_task_to_rdy_list(task_tcb_list[des_task_id]); 572 | if (task_tcb_list[des_task_id]->prio < tcb_curr_ptr->prio) 573 | { 574 | tcb_high_rdy_ptr = task_tcb_list[des_task_id]; 575 | 576 | /*Save state*/ 577 | tcb_high_rdy_ptr->state = TASK_STATE_RUNNING; 578 | 579 | os_cpu_trigger_PendSV(); 580 | } 581 | EXIT_CRITICAL(); 582 | break; 583 | 584 | default: /*DELAYED, SUSPEND, RUNNING*/ 585 | os_msg_queue_put_pure(&(task_tcb_list[des_task_id]->msg_queue), sig); 586 | EXIT_CRITICAL(); 587 | break; 588 | } 589 | } 590 | 591 | msg_t *os_task_wait_for_msg(uint32_t time_out) 592 | { 593 | msg_t *p_msg = os_msg_queue_get(&(task_tcb_list[tcb_curr_ptr->id]->msg_queue)); 594 | if (time_out > (uint32_t)0U && p_msg == NULL) 595 | { 596 | ENTER_CRITICAL(); 597 | 598 | add_curr_task_to_delay_list(time_out, OS_TRUE); // Can block indefinitely 599 | if (time_out == OS_CFG_DELAY_MAX) 600 | { 601 | tcb_curr_ptr->state = TASK_STATE_SUSPENDED_ON_MSG; 602 | } 603 | else 604 | { 605 | tcb_curr_ptr->state = TASK_STATE_DELAYED_ON_MSG; 606 | } 607 | os_cpu_trigger_PendSV(); 608 | EXIT_CRITICAL(); 609 | 610 | p_msg = os_msg_queue_get(&(task_tcb_list[tcb_curr_ptr->id]->msg_queue)); 611 | return p_msg; 612 | } 613 | else 614 | { 615 | return p_msg; 616 | } 617 | } --------------------------------------------------------------------------------