4503 lines
120 KiB
C
Executable File
4503 lines
120 KiB
C
Executable File
/**
|
||
* @file k_kit.c
|
||
* @author LokLiang (lokliang@163.com)
|
||
* @brief 裸机版微内核
|
||
* @version 1.1.0
|
||
*
|
||
* @date 2023-01-01 添加 k_timer
|
||
* @date 2022-12-09
|
||
* @date 2021-01-13
|
||
*
|
||
* @copyright Copyright (c) 2022
|
||
*
|
||
* 可被任意实时内核继承
|
||
* 可管理任意数量的任务
|
||
* 8个任务优先级
|
||
* 允许任务 yield 和 sleep
|
||
* 极少的移植操作
|
||
* 所有接口访问线程安全
|
||
*
|
||
* 效率:在72MHz主频下
|
||
* k_work_submit -- 3uS
|
||
* work scheduler -- 4uS
|
||
* k_fifo_put/k_fifo_take -- 2.5uS
|
||
* k_queue_alloc/k_queue_put -- 2.5uS
|
||
* k_pipe_poll_write/k_pipe_poll_read -- 1uS
|
||
*
|
||
* 任务和时间管理
|
||
* -- 独立的任务队列
|
||
* -- 所有任务对象可自由创建和删除
|
||
* -- 拥有运行、就绪、延时、挂起四个状态
|
||
* -- 栈来自所在的工作队列
|
||
* -- 所有任务可挂到任意工作队列中
|
||
* -- 可设置8档优先级(0..7)
|
||
* -- 在运行过程中允许让出CPU使用权
|
||
*
|
||
* 软件定时器
|
||
* -- 独立的任务队列
|
||
* -- 与任务数据结构一致
|
||
* -- 所有定时器对象可自由创建和删除
|
||
* -- 拥有运行、就绪、延时、挂起四个状态
|
||
* -- 栈来自所在的软定时器队列
|
||
* -- 可设置8档优先级(0..7)
|
||
*
|
||
* 邮箱和邮件
|
||
* -- 邮箱和邮件的数据空间由堆管理,邮件数量不限
|
||
* -- 每个任务可创建和删除一个专属邮箱
|
||
* -- 收到邮件的任务被置到就绪状态
|
||
* -- 已提取的邮件在任务返回后被自动清理
|
||
* -- 依赖临界操作和堆管理,效率较低
|
||
*
|
||
* FIFO
|
||
* -- 队列和数据块的空间由堆管理,数量不限
|
||
* -- 专用的数据块
|
||
* -- 每个数据块长度不限
|
||
* -- 依赖临界操作和堆管理,效率较低
|
||
* -- 独立的对象,可脱离内核单独使用
|
||
*
|
||
* 队列
|
||
* -- 队列空间由堆管理,数量不限
|
||
* -- 数据块由队列管理,数据结构化,数量和长度在创建队列时指定,无内存碎片
|
||
* -- 临界时间短,效率较高
|
||
* -- 独立的对象,可脱离内核单独使用
|
||
*
|
||
* 管道
|
||
* -- 管道空间由堆管理,数量不限
|
||
* -- 允许两个线程同时读写数据流
|
||
* -- 代码简短,适合在内存中执行
|
||
* -- 不依赖临界操作和堆管理,通讯效率高
|
||
* -- 独立的对象,可脱离内核单独使用
|
||
*
|
||
* 堆
|
||
* -- 管理对象为任意的内存空间
|
||
* -- 申请的内存块管理数据长度为 sizeof(size_t) * 4
|
||
* -- 效率和速度较高
|
||
* -- 独立的对象,可脱离内核单独使用
|
||
*/
|
||
|
||
#include "k_kit.h"
|
||
|
||
#include <string.h>
|
||
#include <stdio.h>
|
||
|
||
/**
|
||
* @defgroup debug
|
||
* @{
|
||
*/
|
||
|
||
#ifndef CONFIG_K_KIT_LOG_ON
|
||
#define CONFIG_K_KIT_LOG_ON 0 /* 0: k_log_sched() 无效; 1: k_log_sched() 生效 */
|
||
#endif
|
||
|
||
#ifndef CONFIG_K_KIT_DBG_ON
|
||
#define CONFIG_K_KIT_DBG_ON 1 /* 允许 k_kit 打印错误日志 */
|
||
#endif
|
||
|
||
#ifndef CONFIG_K_KIT_DBG_COLOR_ON
|
||
#define CONFIG_K_KIT_DBG_COLOR_ON 1 /* 在打印的日志中添加颜色控制 */
|
||
#endif
|
||
|
||
#ifndef CONFIG_K_KIT_PRINT
|
||
#define CONFIG_K_KIT_PRINT printf /* 设置打印函数 */
|
||
#endif
|
||
|
||
#define _CONS_PRINT(FMT, ARG...) \
|
||
do \
|
||
{ \
|
||
if (CONFIG_K_KIT_DBG_ON) \
|
||
{ \
|
||
CONFIG_K_KIT_PRINT(FMT, ##ARG); \
|
||
} \
|
||
} while (0)
|
||
|
||
#if (CONFIG_K_KIT_DBG_COLOR_ON == 1)
|
||
#define _COLOR_R "\033[31m" /* 红 RED */
|
||
#define _COLOR_G "\033[32m" /* 绿 GREEN */
|
||
#define _COLOR_Y "\033[33m" /* 黄 YELLOW */
|
||
#define _COLOR_B "\033[34m" /* 蓝 BLUE */
|
||
#define _COLOR_P "\033[35m" /* 紫 PURPLE */
|
||
#define _COLOR_C "\033[36m" /* 青 CYAN */
|
||
#define _COLOR_RY "\033[41;33m" /* 红底黄字 */
|
||
#define _COLOR_END "\033[0m" /* 结束 */
|
||
#else
|
||
#define _COLOR_R "" /* 红 */
|
||
#define _COLOR_G "" /* 绿 */
|
||
#define _COLOR_Y "" /* 黄 */
|
||
#define _COLOR_B "" /* 蓝 */
|
||
#define _COLOR_P "" /* 紫 */
|
||
#define _COLOR_C "" /* 青 */
|
||
#define _COLOR_RY "" /* 红底黄字 */
|
||
#define _COLOR_END "" /* 结束 */
|
||
#endif
|
||
|
||
#define _DO_SYS_LOG(FLAG, FMT, ARG...) \
|
||
do \
|
||
{ \
|
||
if (FLAG) \
|
||
{ \
|
||
_CONS_PRINT(FMT, ##ARG); \
|
||
} \
|
||
} while (0)
|
||
|
||
#define _FILENAME(FILE) (strrchr(FILE, '/') ? (strrchr(FILE, '/') + 1) : (strrchr(FILE, '\\') ? (strrchr(FILE, '\\') + 1) : FILE))
|
||
|
||
#define _GEN_DOMAIN "[KIT] "
|
||
|
||
#define _SYS_LOG_COLOR(FLAG, INFO, COLOR, FMT, ...) _DO_SYS_LOG(FLAG, INFO "%s:%d \t%s -> " COLOR FMT _COLOR_END "\r\n", \
|
||
_FILENAME(__FILE__), __LINE__, __FUNCTION__, ##__VA_ARGS__)
|
||
|
||
#define _DBG_WRN(FMT, ...) _SYS_LOG_COLOR(CONFIG_K_KIT_DBG_ON, "[WRN] * " _GEN_DOMAIN, _COLOR_Y, FMT, ##__VA_ARGS__)
|
||
|
||
#define _ASSERT_FALSE(EXP, FMT, ...) \
|
||
do \
|
||
{ \
|
||
if (EXP) \
|
||
{ \
|
||
_CONS_PRINT("[ASS] # " _GEN_DOMAIN "%s:%d \t%s -> %s; ## " _COLOR_RY FMT _COLOR_END "\r\n", \
|
||
_FILENAME(__FILE__), __LINE__, __FUNCTION__, #EXP, ##__VA_ARGS__); \
|
||
do \
|
||
{ \
|
||
volatile int FLAG = 0; \
|
||
do \
|
||
{ \
|
||
} while (FLAG == 0); \
|
||
} while (0); \
|
||
} \
|
||
} while (0)
|
||
|
||
/**
|
||
* @} debug
|
||
*/
|
||
|
||
#define _SIGNED_MAX(N) ((int)((1u << (sizeof(N) * 8 - 1)) - 1))
|
||
|
||
#define _WORK ((k_work_handle_t *)work_handle->hdl)
|
||
#define _WORK_Q ((k_work_q_handle_t *)_WORK->work_q_handle->hdl)
|
||
#define _K_PORT (&s_kit_init_struct)
|
||
#define _K_CONTAINER_OF(PTR, TYPE, MEMBER) ((TYPE *)&((uint8_t *)PTR)[-(int)&((TYPE *)0)->MEMBER])
|
||
|
||
#define _TRUE true
|
||
#define _FALSE false
|
||
|
||
#define _K_DIS_INT() _k_interrupt_save()
|
||
#define _K_DIS_SCHED() _k_scheduler_disable()
|
||
|
||
#define _K_EN_INT() _k_interrupt_restore()
|
||
#define _K_EN_SCHED() _k_scheduler_enable()
|
||
|
||
#define _K_FIFO_FREE 0x83459321
|
||
#define _K_QUEUE_FREE 0x32478065
|
||
|
||
#define _SLIST_SET(Value1, Value2) (Value1 = (__list_node_t)Value2)
|
||
#define _SLIST_GET(Value) ((__slist_node_t *)(Value))
|
||
|
||
#define _DLIST_SET(Value1, Value2) (Value1 = (__list_node_t)Value2)
|
||
#define _DLIST_GET(Value) ((__dlist_node_t *)(Value))
|
||
|
||
#define _TEST_HANDLE(HANDLE, RETURN) \
|
||
if (HANDLE == NULL) \
|
||
{ \
|
||
_DBG_WRN(#HANDLE " nul"); \
|
||
RETURN; \
|
||
} \
|
||
if (*(void **)HANDLE == NULL) \
|
||
{ \
|
||
_DBG_WRN(#HANDLE " invalid"); \
|
||
RETURN; \
|
||
}
|
||
|
||
typedef void *__list_node_t;
|
||
|
||
typedef struct
|
||
{
|
||
__list_node_t next;
|
||
} __slist_node_t;
|
||
typedef struct
|
||
{
|
||
__list_node_t head;
|
||
__list_node_t tail;
|
||
} __slist_t;
|
||
|
||
typedef struct
|
||
{
|
||
__list_node_t next;
|
||
__list_node_t prev;
|
||
} __dlist_node_t;
|
||
typedef struct
|
||
{
|
||
__list_node_t head;
|
||
} __dlist_t;
|
||
|
||
typedef struct
|
||
{
|
||
__slist_t mbox_valid;
|
||
__slist_t mbox_idle;
|
||
} k_work_mb_list_t;
|
||
|
||
typedef struct
|
||
{
|
||
__slist_node_t state_node;
|
||
__slist_t *state_list;
|
||
__dlist_node_t event_node;
|
||
k_tick_t timeout;
|
||
k_work_fn work_route;
|
||
void *arg;
|
||
k_work_q_t *work_q_handle;
|
||
k_work_t *work_handle;
|
||
uint8_t priority;
|
||
uint8_t exec_flag;
|
||
uint8_t exec_repeat;
|
||
uint8_t delete_flag : 1; /* 表示任务正在运行时被关闭,当运行完毕后资源被回收 */
|
||
uint8_t obj_flag_type : 1; /* 0: 表示任务类型为 work; 1: 表示任务类型为 timer */
|
||
uint8_t obj_flag_periodic : 1; /* 任务类型为 timer 时有效,表示使用自动重装 */
|
||
uint8_t obj_flag_auto_del : 1; /* 任务类型为 timer 时有效,表示执行完成后自动删除对象 */
|
||
union
|
||
{
|
||
k_work_mb_list_t *mbox_list;
|
||
k_tick_t period;
|
||
} obj_data;
|
||
|
||
#if (CONFIG_K_KIT_LOG_ON)
|
||
const char *name;
|
||
#endif
|
||
} k_work_handle_t;
|
||
|
||
typedef struct
|
||
{
|
||
__dlist_t event_list;
|
||
__slist_t ready_list[8];
|
||
__slist_t delayed_list;
|
||
size_t priority_tab;
|
||
k_work_t *curr_work;
|
||
k_work_handle_t *yield_work;
|
||
k_work_handle_t *sleep_work;
|
||
k_work_handle_t *sleep_work_prev;
|
||
k_work_q_fn work_q_resume;
|
||
void *work_q_resume_arg;
|
||
k_work_fn hook_entry;
|
||
k_tick_t timeout_early;
|
||
volatile size_t resume_flag;
|
||
} k_work_q_handle_t;
|
||
|
||
typedef struct
|
||
{
|
||
union
|
||
{
|
||
__slist_node_t state_node;
|
||
k_work_t *work_handle;
|
||
} ctrl;
|
||
} k_work_mb_handle_t;
|
||
|
||
typedef struct
|
||
{
|
||
__slist_t list;
|
||
k_work_t *resume_work;
|
||
k_tick_t resume_delay;
|
||
} k_fifo_q_handle_t;
|
||
|
||
typedef struct
|
||
{
|
||
union
|
||
{
|
||
__slist_node_t state_node;
|
||
size_t free_flag;
|
||
} ctrl;
|
||
} k_fifo_handle_t;
|
||
|
||
typedef struct
|
||
{
|
||
__slist_t list_valid;
|
||
__slist_t list_idle;
|
||
size_t item_size;
|
||
k_work_t *resume_work;
|
||
k_tick_t resume_delay;
|
||
} k_queue_handle_t;
|
||
|
||
typedef struct
|
||
{
|
||
union
|
||
{
|
||
__slist_node_t state_node;
|
||
size_t free_flag;
|
||
} ctrl;
|
||
k_queue_t *queue_handle;
|
||
} k_queue_data_t;
|
||
|
||
typedef volatile size_t pipe_id_t;
|
||
|
||
typedef struct
|
||
{
|
||
size_t size; // 缓存总大小
|
||
pipe_id_t wid; // 已写进的下标
|
||
pipe_id_t rid; // 已读出的下标
|
||
k_work_t *resume_work;
|
||
k_tick_t resume_delay;
|
||
} k_pipe_handle_t;
|
||
|
||
static struct
|
||
{
|
||
size_t interrupt_call;
|
||
size_t interrupt_nest;
|
||
|
||
k_work_t *curr_hook;
|
||
k_work_t *curr_log;
|
||
|
||
#if (CONFIG_K_KIT_LOG_ON)
|
||
k_work_t *work_log[8];
|
||
uint8_t log_index;
|
||
uint8_t log_max;
|
||
#endif
|
||
} s_cm_kit;
|
||
|
||
static k_work_q_t work_q_hdl_main;
|
||
static k_timer_q_t timer_q_hdl_main;
|
||
k_work_q_t *default_work_q_hdl = &work_q_hdl_main;
|
||
k_timer_q_t *default_timer_q_hdl = &timer_q_hdl_main;
|
||
|
||
static k_init_t s_kit_init_struct;
|
||
|
||
static const uint8_t _tab_clz_8[] = {
|
||
7, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, // 0x00
|
||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0x10
|
||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0x20
|
||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0x30
|
||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x40
|
||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x50
|
||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x60
|
||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x70
|
||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x80
|
||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x90
|
||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xA0
|
||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xB0
|
||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xC0
|
||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xD0
|
||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xE0
|
||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xF0
|
||
};
|
||
|
||
static void _slist_init_list(__slist_t *list);
|
||
static void _slist_init_node(__slist_node_t *node);
|
||
static int _slist_insert_font(__slist_t *list, __slist_node_t *node);
|
||
static int _slist_insert_tail(__slist_t *list, __slist_node_t *node);
|
||
static int _slist_remove(__slist_t *list, __slist_node_t *node);
|
||
static int _slist_remove_next(__slist_t *list, __slist_node_t *prev_node, __slist_node_t *remove_node);
|
||
static int _slist_insert_next(__slist_t *list, __slist_node_t *tar_node, __slist_node_t *new_node);
|
||
static __slist_node_t *_slist_take_head(__slist_t *list);
|
||
static __slist_node_t *_slist_peek_head(__slist_t *list);
|
||
static __slist_node_t *_slist_peek_tail(__slist_t *list);
|
||
static __slist_node_t *_slist_peek_next(__slist_node_t *node);
|
||
static __slist_node_t *_slist_peek_prev(__slist_t *list, __slist_node_t *node);
|
||
static int _slist_is_pending(__slist_node_t *node);
|
||
|
||
static void _dlist_init_list(__dlist_t *list);
|
||
static void _dlist_init_node(__dlist_node_t *node);
|
||
static int _dlist_insert_tail(__dlist_t *list, __dlist_node_t *node);
|
||
static int _dlist_remove(__dlist_t *list, __dlist_node_t *node);
|
||
static __dlist_node_t *_dlist_take_head(__dlist_t *list);
|
||
static __dlist_node_t *_dlist_peek_head(__dlist_t *list);
|
||
static __dlist_node_t *_dlist_peek_tail(__dlist_t *list);
|
||
static __dlist_node_t *_dlist_peek_next(__dlist_t *list, __dlist_node_t *node);
|
||
static int _dlist_is_pending(__dlist_node_t *node);
|
||
|
||
static void _slist_init_list(__slist_t *list)
|
||
{
|
||
_SLIST_SET(list->head, 0);
|
||
_SLIST_SET(list->tail, 0);
|
||
}
|
||
|
||
static void _slist_init_node(__slist_node_t *node)
|
||
{
|
||
_SLIST_SET(node->next, 0);
|
||
}
|
||
|
||
static int _slist_insert_font(__slist_t *list, __slist_node_t *node)
|
||
{
|
||
__slist_node_t *head_node;
|
||
|
||
if (_SLIST_GET(node->next) != NULL)
|
||
{
|
||
return -1;
|
||
}
|
||
|
||
head_node = _SLIST_GET(list->head);
|
||
if (head_node)
|
||
{
|
||
_SLIST_SET(node->next, head_node);
|
||
}
|
||
else
|
||
{
|
||
_SLIST_SET(node->next, node);
|
||
_SLIST_SET(list->tail, node);
|
||
}
|
||
_SLIST_SET(list->head, node);
|
||
|
||
return 0;
|
||
}
|
||
|
||
static int _slist_insert_tail(__slist_t *list, __slist_node_t *node)
|
||
{
|
||
if (_SLIST_GET(node->next) != NULL)
|
||
{
|
||
return -1;
|
||
}
|
||
|
||
_SLIST_SET(node->next, node);
|
||
if (_SLIST_GET(list->head) == NULL)
|
||
{
|
||
_SLIST_SET(list->head, node);
|
||
}
|
||
else
|
||
{
|
||
__slist_node_t *tail_node = (__slist_node_t *)_SLIST_GET(list->tail);
|
||
|
||
_SLIST_SET(tail_node->next, node);
|
||
}
|
||
_SLIST_SET(list->tail, node);
|
||
|
||
return 0;
|
||
}
|
||
|
||
static int _slist_remove(__slist_t *list, __slist_node_t *node)
|
||
{
|
||
__slist_node_t *list_head;
|
||
__slist_node_t *node_next;
|
||
|
||
if (node == NULL || list == NULL)
|
||
{
|
||
return -1;
|
||
}
|
||
|
||
list_head = _SLIST_GET(list->head);
|
||
node_next = _SLIST_GET(node->next);
|
||
if (node_next == NULL || list_head == NULL)
|
||
{
|
||
return -1;
|
||
}
|
||
|
||
if (node == list_head) // node 是首个节点
|
||
{
|
||
if (node == _SLIST_GET(list->tail)) // node 是最后一个节点
|
||
{
|
||
_SLIST_SET(list->head, 0);
|
||
_SLIST_SET(list->tail, 0);
|
||
}
|
||
else
|
||
{
|
||
_SLIST_SET(list->head, node_next);
|
||
}
|
||
}
|
||
else // node 不是首个节点
|
||
{
|
||
__slist_node_t *prev_node = _slist_peek_prev(list, node);
|
||
if (prev_node == NULL)
|
||
{
|
||
return -1;
|
||
}
|
||
|
||
if (node == _SLIST_GET(list->tail)) // node 是最后一个节点
|
||
{
|
||
_SLIST_SET(list->tail, prev_node);
|
||
_SLIST_SET(prev_node->next, prev_node);
|
||
}
|
||
else
|
||
{
|
||
_SLIST_SET(prev_node->next, node_next);
|
||
}
|
||
}
|
||
|
||
_SLIST_SET(node->next, 0);
|
||
|
||
return 0;
|
||
}
|
||
|
||
static int _slist_remove_next(__slist_t *list, __slist_node_t *prev_node, __slist_node_t *remove_node)
|
||
{
|
||
__slist_node_t *list_head;
|
||
__slist_node_t *node_next;
|
||
|
||
if (remove_node == NULL || list == NULL)
|
||
{
|
||
return -1;
|
||
}
|
||
|
||
list_head = _SLIST_GET(list->head);
|
||
node_next = _SLIST_GET(remove_node->next);
|
||
if (node_next == NULL || list_head == NULL)
|
||
{
|
||
return -1;
|
||
}
|
||
|
||
if (remove_node == list_head) // remove_node 是首个节点
|
||
{
|
||
if (remove_node == _SLIST_GET(list->tail)) // remove_node 是最后一个节点
|
||
{
|
||
_SLIST_SET(list->head, 0);
|
||
_SLIST_SET(list->tail, 0);
|
||
}
|
||
else
|
||
{
|
||
_SLIST_SET(list->head, node_next);
|
||
}
|
||
}
|
||
else // remove_node 不是首个节点
|
||
{
|
||
if (prev_node == NULL)
|
||
{
|
||
prev_node = _slist_peek_prev(list, remove_node);
|
||
if (prev_node == NULL)
|
||
{
|
||
return -1;
|
||
}
|
||
}
|
||
|
||
if (remove_node == _SLIST_GET(list->tail)) // remove_node 是最后一个节点
|
||
{
|
||
_SLIST_SET(list->tail, prev_node);
|
||
_SLIST_SET(prev_node->next, prev_node);
|
||
}
|
||
else
|
||
{
|
||
_SLIST_SET(prev_node->next, node_next);
|
||
}
|
||
}
|
||
|
||
_SLIST_SET(remove_node->next, 0);
|
||
|
||
return 0;
|
||
}
|
||
|
||
static int _slist_insert_next(__slist_t *list, __slist_node_t *tar_node, __slist_node_t *new_node)
|
||
{
|
||
__slist_node_t *tar_node_next = _SLIST_GET(tar_node->next);
|
||
|
||
if (_SLIST_GET(list->head) == NULL || tar_node_next == NULL || _SLIST_GET(new_node->next) != NULL)
|
||
{
|
||
return -1;
|
||
}
|
||
|
||
if (tar_node == _SLIST_GET(list->tail)) // tar_node 是最后一个节点
|
||
{
|
||
_SLIST_SET(new_node->next, new_node);
|
||
_SLIST_SET(tar_node->next, new_node);
|
||
_SLIST_SET(list->tail, new_node);
|
||
}
|
||
else
|
||
{
|
||
_SLIST_SET(new_node->next, tar_node_next);
|
||
_SLIST_SET(tar_node->next, new_node);
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
static __slist_node_t *_slist_take_head(__slist_t *list)
|
||
{
|
||
__slist_node_t *ret = _SLIST_GET(list->head);
|
||
_slist_remove(list, ret);
|
||
return ret;
|
||
}
|
||
|
||
static __slist_node_t *_slist_peek_head(__slist_t *list)
|
||
{
|
||
return _SLIST_GET(list->head);
|
||
}
|
||
|
||
static __slist_node_t *_slist_peek_tail(__slist_t *list)
|
||
{
|
||
return _SLIST_GET(list->tail);
|
||
}
|
||
|
||
static __slist_node_t *_slist_peek_next(__slist_node_t *node)
|
||
{
|
||
__slist_node_t *next_node = _SLIST_GET(node->next);
|
||
if (next_node == node)
|
||
{
|
||
return NULL;
|
||
}
|
||
else
|
||
{
|
||
return next_node;
|
||
}
|
||
}
|
||
|
||
static __slist_node_t *_slist_peek_prev(__slist_t *list, __slist_node_t *node)
|
||
{
|
||
__slist_node_t *prev_node = NULL;
|
||
__slist_node_t *test_node = _SLIST_GET(list->head);
|
||
while (test_node && test_node != node && prev_node != test_node)
|
||
{
|
||
prev_node = test_node;
|
||
test_node = _SLIST_GET(test_node->next);
|
||
}
|
||
if (test_node == node)
|
||
{
|
||
return prev_node;
|
||
}
|
||
|
||
return NULL;
|
||
}
|
||
|
||
static int _slist_is_pending(__slist_node_t *node)
|
||
{
|
||
return (_SLIST_GET(node->next) != NULL);
|
||
}
|
||
|
||
static void _dlist_init_list(__dlist_t *list)
|
||
{
|
||
_DLIST_SET(list->head, 0);
|
||
}
|
||
|
||
static void _dlist_init_node(__dlist_node_t *node)
|
||
{
|
||
_DLIST_SET(node->next, 0);
|
||
_DLIST_SET(node->prev, 0);
|
||
}
|
||
|
||
static int _dlist_insert_tail(__dlist_t *list, __dlist_node_t *node)
|
||
{
|
||
__dlist_node_t *first_node;
|
||
|
||
if (_DLIST_GET(node->next) != NULL || _DLIST_GET(node->prev) != NULL)
|
||
{
|
||
return -1;
|
||
}
|
||
|
||
first_node = _DLIST_GET(list->head);
|
||
if (first_node == NULL)
|
||
{
|
||
/* 直接设置链头 */
|
||
_DLIST_SET(node->next, node);
|
||
_DLIST_SET(node->prev, node);
|
||
_DLIST_SET(list->head, node);
|
||
}
|
||
else
|
||
{
|
||
__dlist_node_t *first_node_prev = _DLIST_GET(first_node->prev);
|
||
|
||
_DLIST_SET(node->next, first_node);
|
||
_DLIST_SET(node->prev, first_node_prev);
|
||
_DLIST_SET(first_node_prev->next, node);
|
||
_DLIST_SET(first_node->prev, node);
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
static int _dlist_remove(__dlist_t *list, __dlist_node_t *node)
|
||
{
|
||
__dlist_node_t *first_node;
|
||
__dlist_node_t *node_next;
|
||
|
||
if (node == NULL || list == NULL)
|
||
{
|
||
return -1;
|
||
}
|
||
first_node = _DLIST_GET(list->head);
|
||
node_next = _DLIST_GET(node->next);
|
||
if (node_next == NULL || first_node == NULL)
|
||
{
|
||
return -1;
|
||
}
|
||
|
||
if (node_next == node) // 是最后一节点
|
||
{
|
||
_DLIST_SET(list->head, 0);
|
||
}
|
||
else // 不是最后一节点
|
||
{
|
||
__dlist_node_t *node_prev = _DLIST_GET(node->prev);
|
||
if (first_node == node)
|
||
{
|
||
_DLIST_SET(list->head, node_next); // 链头指向下一节点
|
||
}
|
||
_DLIST_SET(node_prev->next, node_next);
|
||
_DLIST_SET(node_next->prev, node_prev);
|
||
}
|
||
|
||
_DLIST_SET(node->next, 0);
|
||
_DLIST_SET(node->prev, 0);
|
||
|
||
return 0;
|
||
}
|
||
|
||
static __dlist_node_t *_dlist_take_head(__dlist_t *list)
|
||
{
|
||
__dlist_node_t *ret = _DLIST_GET(list->head);
|
||
_dlist_remove(list, ret);
|
||
return ret;
|
||
}
|
||
|
||
static __dlist_node_t *_dlist_peek_head(__dlist_t *list)
|
||
{
|
||
return _DLIST_GET(list->head);
|
||
}
|
||
|
||
static __dlist_node_t *_dlist_peek_tail(__dlist_t *list)
|
||
{
|
||
__dlist_node_t *list_head = _DLIST_GET(list->head);
|
||
if (list_head == NULL)
|
||
{
|
||
return NULL;
|
||
}
|
||
else
|
||
{
|
||
return _DLIST_GET(list_head->prev);
|
||
}
|
||
}
|
||
|
||
static __dlist_node_t *_dlist_peek_next(__dlist_t *list, __dlist_node_t *node)
|
||
{
|
||
__dlist_node_t *ret = _DLIST_GET(node->next);
|
||
if (_dlist_peek_head(list) == ret)
|
||
{
|
||
ret = NULL;
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
static int _dlist_is_pending(__dlist_node_t *node)
|
||
{
|
||
return (_DLIST_GET(node->next) != NULL);
|
||
}
|
||
|
||
static void _k_interrupt_save(void)
|
||
{
|
||
if (s_cm_kit.interrupt_call == 0)
|
||
{
|
||
s_cm_kit.interrupt_nest = _K_PORT->interrupt_save();
|
||
}
|
||
s_cm_kit.interrupt_call++;
|
||
}
|
||
|
||
static void _k_interrupt_restore(void)
|
||
{
|
||
s_cm_kit.interrupt_call--;
|
||
_ASSERT_FALSE((int)s_cm_kit.interrupt_call < 0, "error");
|
||
if (s_cm_kit.interrupt_call == 0)
|
||
{
|
||
_K_PORT->interrupt_restore(s_cm_kit.interrupt_nest);
|
||
}
|
||
}
|
||
|
||
static void _k_scheduler_disable(void)
|
||
{
|
||
_K_PORT->scheduler_disable();
|
||
}
|
||
|
||
static void _k_scheduler_enable(void)
|
||
{
|
||
_K_PORT->scheduler_enable();
|
||
}
|
||
|
||
static void _k_nop(void)
|
||
{
|
||
}
|
||
|
||
static k_work_q_t *_k_nop_get_work_q_hdl(void)
|
||
{
|
||
return default_work_q_hdl;
|
||
}
|
||
|
||
static void _k_read_curr_handle(k_work_q_t **work_q_handle, k_work_t **work_handle)
|
||
{
|
||
*work_q_handle = _K_PORT->get_work_q_hdl();
|
||
*work_handle = ((k_work_q_handle_t *)(*work_q_handle)->hdl)->curr_work;
|
||
}
|
||
|
||
/**
|
||
* @brief 删除指定邮箱队列中的邮件
|
||
*
|
||
* @param list 邮箱队列,mbox_idle 或 mbox_valid
|
||
*/
|
||
static void _k_work_mbox_clr_list(__slist_t *list)
|
||
{
|
||
for (;;)
|
||
{
|
||
__slist_node_t *node = _slist_take_head(list);
|
||
if (node == NULL)
|
||
{
|
||
break;
|
||
}
|
||
else
|
||
{
|
||
k_work_mb_handle_t *mbox_data = _K_CONTAINER_OF(node, k_work_mb_handle_t, ctrl.state_node);
|
||
_K_PORT->free(mbox_data);
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 执行删除任务
|
||
*
|
||
* @param work_handle 由 k_work_create() 初始化
|
||
*/
|
||
static void _k_work_delete(k_work_t *work_handle)
|
||
{
|
||
if (work_handle == NULL)
|
||
{
|
||
k_work_q_t *work_q_handle;
|
||
_k_read_curr_handle(&work_q_handle, &work_handle);
|
||
}
|
||
|
||
if (work_handle->hdl != NULL)
|
||
{
|
||
k_work_handle_t *work = work_handle->hdl;
|
||
|
||
if (work->obj_flag_type == 0 && work->obj_data.mbox_list != NULL)
|
||
{
|
||
k_work_mb_list_t *mbox_list = work->obj_data.mbox_list;
|
||
if (mbox_list)
|
||
{
|
||
_k_work_mbox_clr_list(&mbox_list->mbox_idle);
|
||
_k_work_mbox_clr_list(&mbox_list->mbox_valid);
|
||
_K_PORT->free(mbox_list);
|
||
work->obj_data.mbox_list = NULL;
|
||
}
|
||
}
|
||
_slist_remove(work->state_list, &work->state_node);
|
||
if (_dlist_is_pending(&work->event_node))
|
||
{
|
||
k_work_q_handle_t *work_q = work->work_q_handle->hdl;
|
||
_dlist_remove(&work_q->event_list, &work->event_node);
|
||
}
|
||
_K_PORT->free(work_handle->hdl);
|
||
|
||
#if (CONFIG_K_KIT_LOG_ON)
|
||
{
|
||
size_t max_index = sizeof(s_cm_kit.work_log) / sizeof(s_cm_kit.work_log[0]);
|
||
size_t index;
|
||
|
||
if (max_index > s_cm_kit.log_index)
|
||
{
|
||
max_index = s_cm_kit.log_index;
|
||
}
|
||
|
||
for (index = 0; index < max_index; index++)
|
||
{
|
||
if (s_cm_kit.work_log[index] == work_handle)
|
||
{
|
||
size_t i;
|
||
for (i = index; i + 1 < max_index; i++)
|
||
{
|
||
s_cm_kit.work_log[i] = s_cm_kit.work_log[i + 1];
|
||
}
|
||
s_cm_kit.work_log[i] = NULL;
|
||
s_cm_kit.log_index--;
|
||
s_cm_kit.log_max--;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
#endif
|
||
|
||
work_handle->hdl = NULL;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 从信号链 (work_q->event_list) 提取任务,并根据时间设置插入到延时链或直接插入到就绪链或中
|
||
*
|
||
* @param event_list 来源链
|
||
* @param sys_time 当前系统时间
|
||
*/
|
||
static void _k_work_q_handler_take_event_list(__dlist_t *event_list, k_tick_t sys_time)
|
||
{
|
||
if (!_dlist_peek_head(event_list))
|
||
{
|
||
return;
|
||
}
|
||
|
||
for (;;)
|
||
{
|
||
__dlist_node_t *event_node;
|
||
|
||
_K_DIS_INT();
|
||
event_node = _dlist_take_head(event_list);
|
||
if (event_node == NULL)
|
||
{
|
||
_K_EN_INT();
|
||
break;
|
||
}
|
||
else
|
||
{
|
||
k_work_handle_t *opt_work = _K_CONTAINER_OF(event_node, k_work_handle_t, event_node);
|
||
_K_EN_INT();
|
||
|
||
/* 根据时间设置,把任务插入到延时链或直接插入到就绪链或中 */
|
||
_K_DIS_SCHED();
|
||
if (opt_work->timeout - sys_time > 0)
|
||
{
|
||
/* 按时间排序,插入到 work_q->delayed_list */
|
||
k_work_q_handle_t *work_q = opt_work->work_q_handle->hdl;
|
||
__slist_t *new_list = &work_q->delayed_list;
|
||
__slist_node_t *work_node;
|
||
__slist_node_t *test_node;
|
||
|
||
_slist_remove(opt_work->state_list, &opt_work->state_node);
|
||
opt_work->state_list = new_list;
|
||
work_node = &opt_work->state_node;
|
||
test_node = _slist_peek_head(new_list);
|
||
|
||
if (test_node == NULL)
|
||
{
|
||
work_q->timeout_early = opt_work->timeout;
|
||
_slist_insert_font(new_list, work_node);
|
||
}
|
||
else
|
||
{
|
||
__slist_node_t *end_node = _slist_peek_tail(new_list);
|
||
__slist_node_t *prev_node = NULL;
|
||
k_work_handle_t *test_work = _K_CONTAINER_OF(test_node, k_work_handle_t, state_node);
|
||
|
||
work_q->timeout_early = test_work->timeout;
|
||
|
||
do
|
||
{
|
||
if ((int)(opt_work->timeout - test_work->timeout) < 0)
|
||
{
|
||
break;
|
||
}
|
||
|
||
prev_node = test_node;
|
||
test_node = _slist_peek_next(test_node);
|
||
|
||
test_work = _K_CONTAINER_OF(test_node, k_work_handle_t, state_node);
|
||
|
||
} while (prev_node != end_node);
|
||
|
||
if (prev_node == NULL)
|
||
{
|
||
work_q->timeout_early = opt_work->timeout;
|
||
_slist_insert_font(new_list, work_node);
|
||
}
|
||
else
|
||
{
|
||
_slist_insert_next(new_list, prev_node, work_node);
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
/* 直接插入到 work_q->ready_list[] */
|
||
k_work_q_handle_t *work_q = opt_work->work_q_handle->hdl;
|
||
__slist_t *new_list = &work_q->ready_list[opt_work->priority];
|
||
if (opt_work->state_list != new_list)
|
||
{
|
||
_slist_remove(opt_work->state_list, &opt_work->state_node);
|
||
_slist_insert_tail(new_list, &opt_work->state_node);
|
||
opt_work->state_list = new_list;
|
||
work_q->priority_tab |= 1 << opt_work->priority;
|
||
}
|
||
}
|
||
_K_EN_SCHED();
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 从延时链 (work_q->delayed_list) 中把到所有到达时间的任务插入到就绪链中
|
||
*
|
||
* @param src_list 来源链
|
||
* @return k_tick_t 距离下个延时任务的时间
|
||
*/
|
||
static k_tick_t _k_work_q_handler_take_delay_list(k_work_q_handle_t *work_q, k_tick_t sys_time)
|
||
{
|
||
int ret;
|
||
|
||
_k_work_q_handler_take_event_list(&work_q->event_list, sys_time);
|
||
|
||
if ((int)(sys_time - *(volatile int *)&work_q->timeout_early) >= 0)
|
||
{
|
||
for (;;)
|
||
{
|
||
__slist_node_t *delayed_node;
|
||
|
||
_K_DIS_SCHED();
|
||
delayed_node = _slist_peek_head(&work_q->delayed_list);
|
||
|
||
if (delayed_node != NULL)
|
||
{
|
||
k_work_handle_t *opt_work = _K_CONTAINER_OF(delayed_node, k_work_handle_t, state_node);
|
||
|
||
if (opt_work->work_q_handle->hdl == NULL)
|
||
{
|
||
_k_work_delete(opt_work->work_handle);
|
||
}
|
||
else
|
||
{
|
||
if ((int)(sys_time - opt_work->timeout) >= 0)
|
||
{
|
||
_slist_remove(opt_work->state_list, &opt_work->state_node);
|
||
opt_work->state_list = &work_q->ready_list[7 - _tab_clz_8[1 << opt_work->priority]];
|
||
_slist_insert_tail(opt_work->state_list, &opt_work->state_node);
|
||
work_q->priority_tab |= 1 << opt_work->priority;
|
||
}
|
||
else
|
||
{
|
||
work_q->timeout_early = opt_work->timeout;
|
||
_K_EN_SCHED();
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
work_q->timeout_early = sys_time + _SIGNED_MAX(sys_time);
|
||
_K_EN_SCHED();
|
||
break;
|
||
}
|
||
_K_EN_SCHED();
|
||
}
|
||
}
|
||
|
||
ret = work_q->timeout_early - sys_time;
|
||
if (ret < 0)
|
||
{
|
||
ret = 0;
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
/**
|
||
* @brief 获取下个可执行的任务对象
|
||
*
|
||
* @param work_q_handle 由 k_work_q_create() 初始化
|
||
* @return k_work_handle_t* 下个可执行的任务对象
|
||
*/
|
||
static k_work_handle_t *_k_work_q_handler_take_ready_work(k_work_q_t *work_q_handle)
|
||
{
|
||
for (;;)
|
||
{
|
||
k_work_q_handle_t *work_q;
|
||
|
||
_K_DIS_SCHED();
|
||
work_q = work_q_handle->hdl;
|
||
if (work_q == NULL || work_q->priority_tab == 0)
|
||
{
|
||
_K_EN_SCHED();
|
||
return NULL;
|
||
}
|
||
else
|
||
{
|
||
int prio;
|
||
__slist_t *state_list;
|
||
__slist_node_t *state_node;
|
||
k_work_handle_t *exec_work;
|
||
|
||
prio = 7 - _tab_clz_8[work_q->priority_tab];
|
||
if (work_q->yield_work != NULL && prio < work_q->yield_work->priority)
|
||
{
|
||
_K_EN_SCHED();
|
||
return NULL;
|
||
}
|
||
state_list = &work_q->ready_list[prio];
|
||
state_node = _slist_take_head(state_list);
|
||
exec_work = NULL;
|
||
if (state_node == NULL)
|
||
{
|
||
work_q->priority_tab &= ~(1 << prio);
|
||
}
|
||
else
|
||
{
|
||
exec_work = _K_CONTAINER_OF(state_node, k_work_handle_t, state_node);
|
||
if (_slist_peek_head(state_list) == NULL)
|
||
{
|
||
work_q->priority_tab &= ~(1 << prio);
|
||
}
|
||
if (exec_work->exec_flag == 0)
|
||
{
|
||
work_q->curr_work = exec_work->work_handle;
|
||
}
|
||
exec_work->state_list = NULL;
|
||
}
|
||
_K_EN_SCHED();
|
||
|
||
if (exec_work != NULL)
|
||
{
|
||
if (exec_work->exec_flag == 0)
|
||
{
|
||
return exec_work;
|
||
}
|
||
else
|
||
{
|
||
exec_work->exec_repeat = 1;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 用于记录和打印调度日志
|
||
*
|
||
* @param work_handle 由 k_work_create() 初始化
|
||
*/
|
||
static void _k_work_log(void *arg)
|
||
{
|
||
#if (CONFIG_K_KIT_LOG_ON)
|
||
|
||
k_work_q_t *work_q_handle;
|
||
k_work_t *work_handle;
|
||
size_t max_index;
|
||
|
||
_K_DIS_SCHED();
|
||
|
||
_k_read_curr_handle(&work_q_handle, &work_handle);
|
||
max_index = sizeof(s_cm_kit.work_log) / sizeof(s_cm_kit.work_log[0]);
|
||
if (max_index > s_cm_kit.log_index)
|
||
{
|
||
max_index = s_cm_kit.log_index;
|
||
}
|
||
while (max_index)
|
||
{
|
||
if (s_cm_kit.work_log[--max_index] == work_handle)
|
||
{
|
||
s_cm_kit.log_index = max_index + 1;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (s_cm_kit.work_log[max_index] != work_handle)
|
||
{
|
||
if (s_cm_kit.log_index < sizeof(s_cm_kit.work_log) / sizeof(s_cm_kit.work_log[0]))
|
||
{
|
||
s_cm_kit.work_log[s_cm_kit.log_index] = work_handle;
|
||
}
|
||
|
||
if (s_cm_kit.log_index <= sizeof(s_cm_kit.work_log) / sizeof(s_cm_kit.work_log[0]))
|
||
{
|
||
s_cm_kit.log_index++;
|
||
s_cm_kit.log_max = s_cm_kit.log_index;
|
||
}
|
||
}
|
||
|
||
_K_EN_SCHED();
|
||
|
||
#endif
|
||
}
|
||
|
||
/**
|
||
* @brief 把任务插入到 work_q->event_list 中
|
||
*
|
||
* @param work_q_handle 由 k_work_q_create() 初始化
|
||
* @param work_handle 由 k_work_create() 初始化
|
||
* @param timeout 指定的唤醒时间点
|
||
* @param wait_forever 是否永远等待
|
||
*/
|
||
static void _k_work_do_submit(k_work_q_t *work_q_handle, k_work_t *work_handle, k_tick_t timeout, bool wait_forever)
|
||
{
|
||
k_work_handle_t *work;
|
||
k_work_q_handle_t *work_q;
|
||
int resume_flag = 1;
|
||
|
||
_TEST_HANDLE(work_q_handle, return);
|
||
_TEST_HANDLE(work_handle, return);
|
||
|
||
work = work_handle->hdl;
|
||
work_q = work_q_handle->hdl;
|
||
|
||
if (wait_forever)
|
||
{
|
||
if (work->work_q_handle != work_q_handle ||
|
||
_dlist_is_pending(&work->event_node))
|
||
{
|
||
_K_DIS_INT();
|
||
|
||
if (work_handle->hdl != NULL)
|
||
{
|
||
if (_dlist_is_pending(&work->event_node))
|
||
{
|
||
k_work_q_handle_t *work_q_old = work->work_q_handle->hdl;
|
||
_dlist_remove(&work_q_old->event_list, &work->event_node);
|
||
}
|
||
work->work_q_handle = work_q_handle;
|
||
work->work_handle = work_handle;
|
||
}
|
||
|
||
_K_EN_INT();
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (work->timeout != timeout ||
|
||
work->work_q_handle != work_q_handle ||
|
||
!_dlist_is_pending(&work->event_node))
|
||
{
|
||
_K_DIS_INT();
|
||
|
||
if (work_handle->hdl != NULL)
|
||
{
|
||
work->timeout = timeout;
|
||
if (work->work_q_handle != work_q_handle)
|
||
{
|
||
if (_dlist_is_pending(&work->event_node))
|
||
{
|
||
k_work_q_handle_t *work_q_old = work->work_q_handle->hdl;
|
||
_dlist_remove(&work_q_old->event_list, &work->event_node);
|
||
}
|
||
}
|
||
work->work_q_handle = work_q_handle;
|
||
if (!_dlist_is_pending(&work->event_node))
|
||
{
|
||
_dlist_insert_tail(&work_q->event_list, &work->event_node);
|
||
work->work_handle = work_handle;
|
||
resume_flag = work_q->resume_flag;
|
||
}
|
||
}
|
||
|
||
_K_EN_INT();
|
||
}
|
||
|
||
if (resume_flag == 0)
|
||
{
|
||
work_q->resume_flag = 1;
|
||
if (work_q->work_q_resume != NULL)
|
||
{
|
||
work_q->work_q_resume(work_q->work_q_resume_arg);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 由内部通讯模块所用,执行唤醒已注册的任务。
|
||
*
|
||
* @param resume_work 已注册的任务
|
||
* @param resume_delay 唤醒延时
|
||
* 0 - 计时从首次收到信号后开始;
|
||
* 1 - 计时从最后一次收到信号后开始;
|
||
*/
|
||
static void _k_ipc_resume(k_work_t *resume_work, k_tick_t resume_delay)
|
||
{
|
||
if (resume_work != NULL)
|
||
{
|
||
k_work_handle_t *work = resume_work->hdl;
|
||
if (work != NULL && work->work_q_handle != NULL)
|
||
{
|
||
if (k_work_time_remain(resume_work) < resume_delay)
|
||
{
|
||
k_work_submit(work->work_q_handle, resume_work, resume_delay);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 当被执行完的任务为软件定时器时,按时间重新提交一次到队列中
|
||
*
|
||
* @param work_q_handle 由 k_work_q_create() 初始化
|
||
* @param exec_work 被执行的任务对象
|
||
*/
|
||
static void _k_timer_end(k_work_q_t *work_q_handle, k_work_handle_t *exec_work)
|
||
{
|
||
if (exec_work->obj_flag_auto_del)
|
||
{
|
||
k_work_t work_handle = {.hdl = exec_work};
|
||
exec_work->exec_flag = 0;
|
||
k_work_delete(&work_handle);
|
||
exec_work->work_handle = NULL;
|
||
}
|
||
else if (exec_work->obj_flag_periodic)
|
||
{
|
||
k_tick_t timeout = exec_work->timeout +
|
||
exec_work->obj_data.period +
|
||
(_K_PORT->get_sys_ticks() - exec_work->timeout) / exec_work->obj_data.period * exec_work->obj_data.period;
|
||
_k_work_do_submit(work_q_handle, exec_work->work_handle, timeout, _FALSE);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 初始化微内核
|
||
* 建议初始化后再配置系统的定时器,每1毫秒产生一次中断
|
||
*
|
||
* @param init_struct 初始化参数
|
||
*/
|
||
void k_init(const k_init_t *init_struct)
|
||
{
|
||
if (s_kit_init_struct.malloc != NULL)
|
||
{
|
||
_DBG_WRN("Duplicate initialization");
|
||
}
|
||
_ASSERT_FALSE(init_struct->malloc == NULL ||
|
||
init_struct->free == 0 ||
|
||
init_struct->interrupt_save == NULL ||
|
||
init_struct->interrupt_restore == NULL,
|
||
"Parameter error");
|
||
|
||
memcpy(&s_kit_init_struct, init_struct, sizeof(s_kit_init_struct));
|
||
|
||
if (init_struct->scheduler_disable == NULL || init_struct->scheduler_enable == NULL)
|
||
{
|
||
s_kit_init_struct.scheduler_disable = _k_nop;
|
||
s_kit_init_struct.scheduler_enable = _k_nop;
|
||
}
|
||
if (init_struct->get_work_q_hdl == NULL)
|
||
{
|
||
s_kit_init_struct.get_work_q_hdl = _k_nop_get_work_q_hdl;
|
||
}
|
||
|
||
memset(&s_cm_kit, 0, sizeof(s_cm_kit));
|
||
}
|
||
|
||
/**
|
||
* @brief 取消初始化微内核
|
||
*
|
||
*/
|
||
void k_deinit(void)
|
||
{
|
||
memset(&s_kit_init_struct, 0, sizeof(s_kit_init_struct));
|
||
}
|
||
|
||
/**
|
||
* @brief 工作队列执行入口
|
||
* 所有在队列中就绪的任务都将被按顺序逐个执行。
|
||
* 执行顺序为:
|
||
* 1. 按任务的优先级
|
||
* 2. 按就绪的顺序
|
||
* 栈用量 32 bytes
|
||
*
|
||
* @param work_q_handle 由 k_work_q_create() 初始化
|
||
* @return k_tick_t 距离下个延时任务的时间
|
||
*/
|
||
k_tick_t k_work_q_handler(k_work_q_t *work_q_handle)
|
||
{
|
||
k_work_q_handle_t *work_q;
|
||
k_work_t *last_work;
|
||
k_tick_t ret;
|
||
|
||
if (s_kit_init_struct.malloc == NULL || work_q_handle == NULL || work_q_handle->hdl == NULL)
|
||
{
|
||
return -1u;
|
||
}
|
||
|
||
work_q = work_q_handle->hdl;
|
||
last_work = work_q->curr_work;
|
||
|
||
if (last_work != NULL)
|
||
{
|
||
_DBG_WRN("Not recommended executing this function in work_handler");
|
||
}
|
||
|
||
do
|
||
{
|
||
k_work_handle_t *exec_work;
|
||
|
||
if (work_q->priority_tab != 0)
|
||
{
|
||
exec_work = _k_work_q_handler_take_ready_work(work_q_handle);
|
||
if (exec_work != NULL)
|
||
{
|
||
uint8_t exec_flag = exec_work->exec_flag;
|
||
exec_work->exec_flag = 1;
|
||
|
||
if (exec_work->obj_flag_type)
|
||
{
|
||
exec_work->work_route(exec_work->arg);
|
||
_k_timer_end(work_q_handle, exec_work);
|
||
}
|
||
else
|
||
{
|
||
if (s_cm_kit.curr_hook != exec_work->work_handle)
|
||
{
|
||
k_work_fn hook_entry;
|
||
|
||
s_cm_kit.curr_hook = exec_work->work_handle;
|
||
_k_work_log(exec_work->work_handle);
|
||
|
||
hook_entry = work_q->hook_entry;
|
||
if (hook_entry)
|
||
{
|
||
hook_entry(exec_work->work_handle);
|
||
}
|
||
}
|
||
|
||
exec_work->work_route(exec_work->arg);
|
||
}
|
||
work_q->curr_work = last_work;
|
||
|
||
if (k_work_is_valid(exec_work->work_handle))
|
||
{
|
||
if (exec_work->delete_flag == 0)
|
||
{
|
||
exec_work->exec_flag = exec_flag;
|
||
if (exec_work->obj_flag_type == 0 && exec_work->obj_data.mbox_list != NULL)
|
||
{
|
||
if (_slist_peek_head(&exec_work->obj_data.mbox_list->mbox_idle) != NULL)
|
||
{
|
||
_K_DIS_SCHED();
|
||
_k_work_mbox_clr_list(&exec_work->obj_data.mbox_list->mbox_idle);
|
||
_K_EN_SCHED();
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
exec_work->exec_flag = 0;
|
||
k_work_delete(exec_work->work_handle);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
exec_work = NULL;
|
||
}
|
||
|
||
ret = _k_work_q_handler_take_delay_list(work_q, _K_PORT->get_sys_ticks());
|
||
|
||
if (exec_work != NULL)
|
||
{
|
||
break;
|
||
}
|
||
|
||
} while (*(volatile uint8_t *)&work_q->priority_tab != 0);
|
||
|
||
if (work_q->priority_tab != 0)
|
||
{
|
||
ret = 0;
|
||
}
|
||
|
||
if (last_work != NULL)
|
||
{
|
||
if (((k_work_handle_t *)last_work->hdl)->exec_repeat != 0)
|
||
{
|
||
((k_work_handle_t *)last_work->hdl)->exec_repeat = 0;
|
||
k_work_submit(((k_work_handle_t *)last_work->hdl)->work_q_handle,
|
||
((k_work_handle_t *)last_work->hdl)->work_handle,
|
||
0);
|
||
}
|
||
}
|
||
|
||
if (work_q->resume_flag)
|
||
{
|
||
work_q->resume_flag = 0;
|
||
ret = 0;
|
||
}
|
||
|
||
if (work_q->curr_work)
|
||
{
|
||
if (s_cm_kit.curr_hook != work_q->curr_work)
|
||
{
|
||
k_work_fn hook_entry;
|
||
|
||
s_cm_kit.curr_hook = work_q->curr_work;
|
||
_k_work_log(work_q->curr_work);
|
||
|
||
hook_entry = work_q->hook_entry;
|
||
if (hook_entry)
|
||
{
|
||
hook_entry(work_q->curr_work);
|
||
}
|
||
}
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
|
||
/**
|
||
* @brief 创建一个工作队列的对象
|
||
* 对象数据由堆自动分配
|
||
* 对象内存: 112 bytes
|
||
*
|
||
* @param work_q_handle[out] 初始化队列对象指针
|
||
* @return k_err_t 0 -- 成功, -1 -- 堆内存不足
|
||
*/
|
||
k_err_t k_work_q_create(k_work_q_t *work_q_handle)
|
||
{
|
||
k_work_q_handle_t *work_q;
|
||
|
||
_ASSERT_FALSE(s_kit_init_struct.malloc == NULL, "Never use 'k_init()' to initialize");
|
||
|
||
_K_DIS_SCHED();
|
||
work_q = _K_PORT->malloc(sizeof(k_work_q_handle_t));
|
||
if (work_q != NULL)
|
||
{
|
||
size_t i;
|
||
|
||
memset(work_q, 0, sizeof(*work_q));
|
||
work_q_handle->hdl = work_q;
|
||
work_q->work_q_resume = NULL;
|
||
work_q->work_q_resume_arg = NULL;
|
||
for (i = 0; i < sizeof(work_q->ready_list) / sizeof(work_q->ready_list[0]); i++)
|
||
{
|
||
_slist_init_list(&work_q->ready_list[i]);
|
||
}
|
||
_slist_init_list(&work_q->delayed_list);
|
||
_dlist_init_list(&work_q->event_list);
|
||
}
|
||
_K_EN_SCHED();
|
||
|
||
if (work_q == NULL)
|
||
{
|
||
_DBG_WRN("Insufficient memory");
|
||
return -1;
|
||
}
|
||
else
|
||
{
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 删除一个工作队列的对象
|
||
* 1. 在该队列中所有已就绪的任务被立即删除
|
||
* 2. 延时中的任务在到达时间后被立即删除
|
||
* 3. 工作队列被删除
|
||
* 4. 工作队列及相关任务的堆内存被自动回收
|
||
*
|
||
* @param work_q_handle 由 k_work_q_create() 初始化
|
||
*/
|
||
void k_work_q_delete(k_work_q_t *work_q_handle)
|
||
{
|
||
_ASSERT_FALSE(s_kit_init_struct.malloc == NULL, "Never use 'k_init()' to initialize");
|
||
|
||
_K_DIS_SCHED();
|
||
if (work_q_handle != NULL && work_q_handle->hdl != NULL)
|
||
{
|
||
k_work_q_handle_t *work_q = work_q_handle->hdl;
|
||
|
||
while (*(volatile uint8_t *)&work_q->priority_tab != 0)
|
||
{
|
||
__slist_node_t *state_node = _slist_take_head(&work_q->ready_list[7 - _tab_clz_8[work_q->priority_tab]]);
|
||
if (state_node == NULL)
|
||
{
|
||
break;
|
||
}
|
||
else
|
||
{
|
||
k_work_handle_t *work = _K_CONTAINER_OF(state_node, k_work_handle_t, state_node);
|
||
_k_work_delete(work->work_handle);
|
||
}
|
||
}
|
||
|
||
for (;;)
|
||
{
|
||
__dlist_node_t *node = _dlist_take_head(&work_q->event_list);
|
||
if (node == NULL)
|
||
{
|
||
break;
|
||
}
|
||
else
|
||
{
|
||
k_work_handle_t *work = _K_CONTAINER_OF(node, k_work_handle_t, event_node);
|
||
_k_work_delete(work->work_handle);
|
||
}
|
||
}
|
||
|
||
for (;;)
|
||
{
|
||
__slist_node_t *state_node = _slist_take_head(&work_q->delayed_list);
|
||
if (state_node == NULL)
|
||
{
|
||
break;
|
||
}
|
||
else
|
||
{
|
||
k_work_handle_t *work = _K_CONTAINER_OF(state_node, k_work_handle_t, state_node);
|
||
_k_work_delete(work->work_handle);
|
||
}
|
||
}
|
||
|
||
if (work_q->curr_work != NULL)
|
||
{
|
||
_k_work_delete(work_q->curr_work);
|
||
}
|
||
|
||
_K_PORT->free(work_q_handle->hdl);
|
||
work_q_handle->hdl = NULL;
|
||
}
|
||
_K_EN_SCHED();
|
||
}
|
||
|
||
/**
|
||
* @brief 注册一个函数:当有任务被提交时,此回调函数将被自动执行
|
||
*
|
||
* @param work_q_handle 由 k_work_q_create() 初始化
|
||
* @param work_q_resume 当有任务被提交时,被执行的回调函数将
|
||
* @param arg 回调函数将附带的参数
|
||
*/
|
||
void k_work_q_resume_regist(k_work_q_t *work_q_handle, k_work_q_fn work_q_resume, void *arg)
|
||
{
|
||
if (k_work_q_is_valid(work_q_handle))
|
||
{
|
||
k_work_q_handle_t *work_q = work_q_handle->hdl;
|
||
work_q->work_q_resume_arg = arg;
|
||
work_q->work_q_resume = work_q_resume;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 获取工作队列是否有效
|
||
*
|
||
* @param work_q_handle 由 k_work_q_create() 初始化
|
||
* @retval true 对象有效
|
||
* @retval false 对象无效
|
||
*/
|
||
bool k_work_q_is_valid(k_work_q_t *work_q_handle)
|
||
{
|
||
if (s_kit_init_struct.malloc == NULL || work_q_handle == NULL || work_q_handle->hdl == NULL)
|
||
{
|
||
return _FALSE;
|
||
}
|
||
else
|
||
{
|
||
return _TRUE;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 设置切换任务时,进入和退出任务时回调函数
|
||
*
|
||
* @param work_q_handle 由 k_work_q_create() 初始化
|
||
* @param entry 在执行一个新任务时的回调函数,为 NULL 时不回调,注意同一个任务不会被连续回调
|
||
*/
|
||
void k_work_hook(k_work_q_t *work_q_handle, k_work_fn hook)
|
||
{
|
||
k_work_q_handle_t *work_q;
|
||
|
||
_TEST_HANDLE(work_q_handle, return);
|
||
|
||
work_q = work_q_handle->hdl;
|
||
work_q->hook_entry = hook;
|
||
}
|
||
|
||
/**
|
||
* @brief 获取是否有正在延时状态的任务
|
||
*
|
||
* @retval true 有延时状态的任务
|
||
* @retval false 队列已空
|
||
*/
|
||
bool k_work_q_delayed_state(k_work_q_t *work_q_handle)
|
||
{
|
||
k_work_q_handle_t *work_q;
|
||
|
||
_TEST_HANDLE(work_q_handle, return _FALSE);
|
||
|
||
work_q = work_q_handle->hdl;
|
||
if (_dlist_peek_head(&work_q->event_list) != NULL)
|
||
{
|
||
return _TRUE;
|
||
}
|
||
if (_slist_peek_head(&work_q->delayed_list) != NULL)
|
||
{
|
||
return _TRUE;
|
||
}
|
||
return _FALSE;
|
||
}
|
||
|
||
/**
|
||
* @brief 获取工作队列中是否有就绪的任务
|
||
*
|
||
* @param work_q_handle 由 k_work_q_create() 初始化
|
||
* @retval true 有就绪的任务
|
||
* @retval false 队列已空
|
||
*/
|
||
bool k_work_q_ready_state(k_work_q_t *work_q_handle)
|
||
{
|
||
k_work_q_handle_t *work_q = work_q_handle->hdl;
|
||
if (work_q == NULL || work_q->priority_tab == 0)
|
||
{
|
||
return _FALSE;
|
||
}
|
||
else
|
||
{
|
||
return _FALSE;
|
||
}
|
||
}
|
||
|
||
k_err_t k_work_create_default(k_work_t *work_handle,
|
||
const char *name,
|
||
k_work_fn work_route,
|
||
void *arg,
|
||
uint8_t priority,
|
||
k_tick_t delay_ticks)
|
||
{
|
||
if (!k_work_is_valid(work_handle))
|
||
{
|
||
k_err_t ret = k_work_create(work_handle, name, work_route, arg, priority);
|
||
if (ret == 0)
|
||
{
|
||
k_work_submit(default_work_q_hdl, work_handle, delay_ticks);
|
||
}
|
||
return ret;
|
||
}
|
||
else
|
||
{
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 创建由工作队列管理的任务
|
||
* 任务对象数据由堆内存自动分配
|
||
* 任务必须返回
|
||
* 任务堆栈来自 k_work_q_handler()
|
||
* 对象内存: 48 bytes
|
||
*
|
||
* @param work_handle[out] 初始化任务对象数据
|
||
* @param name 任务名
|
||
* @param work_route 任务的入口地址
|
||
* @param arg 附带的一个参数指针
|
||
* @param priority 任务优先级,0 .. 7,0 为最低
|
||
* @return k_err_t 0 -- 成功,-1 -- 失败:对象非空或堆内存不足
|
||
*/
|
||
k_err_t k_work_create(k_work_t *work_handle,
|
||
const char *name,
|
||
k_work_fn work_route,
|
||
void *arg,
|
||
uint8_t priority)
|
||
{
|
||
k_work_handle_t *work;
|
||
|
||
_ASSERT_FALSE(s_kit_init_struct.malloc == NULL, "Never use 'k_init()' to initialize");
|
||
|
||
if (work_route == NULL)
|
||
{
|
||
_DBG_WRN("work_route invalid");
|
||
return -1;
|
||
}
|
||
|
||
if (priority >= (8 - _tab_clz_8[sizeof(_tab_clz_8) - 1]))
|
||
{
|
||
_DBG_WRN("Param over range: priority = %d, New value is %d",
|
||
priority,
|
||
priority % (8 - _tab_clz_8[sizeof(_tab_clz_8) - 1]) %
|
||
(sizeof(((k_work_q_handle_t *)0)->ready_list) / sizeof(((k_work_q_handle_t *)0)->ready_list[0])));
|
||
}
|
||
|
||
_K_DIS_SCHED();
|
||
work = _K_PORT->malloc(sizeof(k_work_handle_t));
|
||
_K_EN_SCHED();
|
||
|
||
if (work)
|
||
{
|
||
memset(work, 0, sizeof(*work));
|
||
work->work_handle = work_handle;
|
||
work->work_route = work_route;
|
||
work->arg = arg;
|
||
work->priority = priority % (8 - _tab_clz_8[sizeof(_tab_clz_8) - 1]) %
|
||
(sizeof(((k_work_q_handle_t *)0)->ready_list) / sizeof(((k_work_q_handle_t *)0)->ready_list[0]));
|
||
_slist_init_node(&work->state_node);
|
||
_dlist_init_node(&work->event_node);
|
||
#if (CONFIG_K_KIT_LOG_ON)
|
||
work->name = name;
|
||
#endif
|
||
work_handle->hdl = work;
|
||
return 0;
|
||
}
|
||
else
|
||
{
|
||
_DBG_WRN("Insufficient memory");
|
||
return -1;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 删除由工作队列管理的任务
|
||
* 任务立即失效
|
||
* 任务对象数据被立即回收
|
||
*
|
||
* @param work_handle 由 k_work_create() 初始化
|
||
*/
|
||
void k_work_delete(k_work_t *work_handle)
|
||
{
|
||
_ASSERT_FALSE(s_kit_init_struct.malloc == NULL, "Never use 'k_init()' to initialize");
|
||
|
||
if (work_handle == NULL)
|
||
{
|
||
k_work_q_t *work_q_handle;
|
||
_k_read_curr_handle(&work_q_handle, &work_handle);
|
||
}
|
||
|
||
_TEST_HANDLE(work_handle, return);
|
||
|
||
_K_DIS_SCHED();
|
||
k_work_handle_t *work = work_handle->hdl;
|
||
if (work->exec_flag == 0)
|
||
{
|
||
_k_work_delete(work_handle);
|
||
}
|
||
else
|
||
{
|
||
work->delete_flag = 1;
|
||
}
|
||
_K_EN_SCHED();
|
||
}
|
||
|
||
/**
|
||
* @brief 获取任务对象是否有效
|
||
*
|
||
* @param work_handle 由 k_work_create() 初始化
|
||
* @retval true 任务对象有效
|
||
* @retval false 任务对象无效
|
||
*/
|
||
bool k_work_is_valid(k_work_t *work_handle)
|
||
{
|
||
if (work_handle == NULL || work_handle->hdl == NULL)
|
||
{
|
||
return _FALSE;
|
||
}
|
||
else
|
||
{
|
||
return _TRUE;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 获取任务是否在就绪或延时的状态
|
||
*
|
||
* @param work_handle 由 k_work_create() 初始化
|
||
* @retval true 任务就绪或延时
|
||
* @retval false 任务被挂起
|
||
*/
|
||
bool k_work_is_pending(k_work_t *work_handle)
|
||
{
|
||
k_work_handle_t *work = work_handle->hdl;
|
||
|
||
if (work != NULL)
|
||
{
|
||
if (work->exec_flag != 0)
|
||
{
|
||
return _TRUE;
|
||
}
|
||
if (_dlist_is_pending(&work->event_node))
|
||
{
|
||
return _TRUE;
|
||
}
|
||
if (_slist_is_pending(&work->state_node))
|
||
{
|
||
return _TRUE;
|
||
}
|
||
}
|
||
|
||
return _FALSE;
|
||
}
|
||
|
||
/**
|
||
* @brief 获取任务距离下个执行的剩余时间
|
||
*
|
||
* @param work_handle
|
||
* @return k_tick_t
|
||
*/
|
||
k_tick_t k_work_time_remain(k_work_t *work_handle)
|
||
{
|
||
_TEST_HANDLE(work_handle, return -1);
|
||
|
||
k_work_handle_t *work = work_handle->hdl;
|
||
k_tick_t ret = 0;
|
||
|
||
if (!_dlist_is_pending(&work->event_node) &&
|
||
!_slist_is_pending(&work->state_node))
|
||
{
|
||
return -1;
|
||
}
|
||
|
||
ret = work->timeout - _K_PORT->get_sys_ticks();
|
||
if (ret < 0)
|
||
{
|
||
ret = 0;
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
/**
|
||
* @brief 把任务插入到 work_q->event_list 中
|
||
*
|
||
* @param work_q_handle 由 k_work_q_create() 初始化
|
||
* @param work_handle 由 k_work_create() 初始化
|
||
* @param delay_ticks 指定的唤醒时间,为0时立即就绪,-1为永不就绪
|
||
*/
|
||
void k_work_submit(k_work_q_t *work_q_handle, k_work_t *work_handle, k_tick_t delay_ticks)
|
||
{
|
||
if (delay_ticks == -1)
|
||
{
|
||
_k_work_do_submit(work_q_handle, work_handle, 0, _TRUE);
|
||
}
|
||
else
|
||
{
|
||
if ((size_t)delay_ticks > _SIGNED_MAX(delay_ticks))
|
||
{
|
||
delay_ticks = _SIGNED_MAX(delay_ticks);
|
||
}
|
||
_k_work_do_submit(work_q_handle, work_handle, _K_PORT->get_sys_ticks() + delay_ticks, _FALSE);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 唤醒任务。注意需要先使用 k_work_submit 绑定一个 work_q_handle
|
||
*
|
||
* @param work_handle 由 k_work_create() 初始化
|
||
* @param delay_ticks 让出CPU的时间
|
||
*/
|
||
void k_work_resume(k_work_t *work_handle, k_tick_t delay_ticks)
|
||
{
|
||
_TEST_HANDLE(work_handle, return);
|
||
|
||
k_work_handle_t *work = work_handle->hdl;
|
||
|
||
if ((size_t)delay_ticks > _SIGNED_MAX(delay_ticks))
|
||
{
|
||
delay_ticks = _SIGNED_MAX(delay_ticks);
|
||
}
|
||
k_work_submit(work->work_q_handle, work_handle, delay_ticks);
|
||
}
|
||
|
||
/**
|
||
* @brief 延时多少个系统节拍后再执行本任务
|
||
*
|
||
* @param delay_ticks 指定的唤醒时间,为0时立即就绪
|
||
*/
|
||
void k_work_later(k_tick_t delay_ticks)
|
||
{
|
||
k_work_q_t *work_q_handle;
|
||
k_work_t *work_handle;
|
||
_k_read_curr_handle(&work_q_handle, &work_handle);
|
||
if ((size_t)delay_ticks > _SIGNED_MAX(delay_ticks))
|
||
{
|
||
delay_ticks = _SIGNED_MAX(delay_ticks);
|
||
}
|
||
k_work_submit(work_q_handle, work_handle, delay_ticks);
|
||
}
|
||
|
||
/**
|
||
* @brief 挂起任务,任务不会被删除
|
||
*
|
||
* @param work_handle 由 k_work_create() 初始化
|
||
*/
|
||
void k_work_suspend(k_work_t *work_handle)
|
||
{
|
||
k_work_handle_t *work;
|
||
|
||
_K_DIS_INT();
|
||
work = work_handle->hdl;
|
||
if (work != NULL)
|
||
{
|
||
if (_dlist_is_pending(&work->event_node))
|
||
{
|
||
k_work_q_handle_t *work_q = work->work_q_handle->hdl;
|
||
_dlist_remove(&work_q->event_list, &work->event_node);
|
||
}
|
||
}
|
||
_K_EN_INT();
|
||
|
||
_K_DIS_SCHED();
|
||
work = work_handle->hdl;
|
||
if (work != NULL)
|
||
{
|
||
_slist_remove(work->state_list, &work->state_node);
|
||
work->state_list = NULL;
|
||
work->exec_flag = 0;
|
||
work->obj_flag_periodic = 0;
|
||
}
|
||
_K_EN_SCHED();
|
||
}
|
||
|
||
/**
|
||
* @brief 从最后一次唤醒的时间算起,延时多少个系统节拍后再执行本任务(固定周期的延时)
|
||
*
|
||
* @param delay_ticks 指定的唤醒时间,为0时立即就绪
|
||
*/
|
||
void k_work_later_until(k_tick_t delay_ticks)
|
||
{
|
||
k_work_q_t *work_q_handle;
|
||
k_work_t *work_handle;
|
||
k_work_handle_t *work;
|
||
k_tick_t timeout;
|
||
|
||
_k_read_curr_handle(&work_q_handle, &work_handle);
|
||
work = work_handle->hdl;
|
||
|
||
if ((size_t)delay_ticks > _SIGNED_MAX(delay_ticks))
|
||
{
|
||
delay_ticks = _SIGNED_MAX(delay_ticks);
|
||
}
|
||
timeout = work->timeout + delay_ticks + (_K_PORT->get_sys_ticks() - work->timeout) / delay_ticks * delay_ticks;
|
||
|
||
_k_work_do_submit(work_q_handle, work_handle, timeout, _FALSE);
|
||
}
|
||
|
||
/**
|
||
* @brief 释放一次CPU的使用权,不调度低于当前任务优先级的任务
|
||
* 返回机制:
|
||
* 给予的队列中有高于当前任务优先级的任务:直到所有更高优先给的任务被执行完后;
|
||
* 给予的队列中首个任务的优先级等于当前任务的优先级:执行完首个任务后返回。
|
||
* 注意:不允许低优先级的任务堵塞高优先级的任务
|
||
*
|
||
* @param delay_ticks 让出CPU的时间
|
||
*/
|
||
void k_work_yield(k_tick_t delay_ticks)
|
||
{
|
||
k_work_q_t *work_q_handle;
|
||
k_work_t *work_handle;
|
||
k_work_handle_t *yield_work;
|
||
|
||
_ASSERT_FALSE(s_kit_init_struct.malloc == NULL, "Never use 'k_init()' to initialize");
|
||
|
||
_k_read_curr_handle(&work_q_handle, &work_handle);
|
||
yield_work = _WORK_Q->yield_work;
|
||
_WORK_Q->yield_work = _WORK;
|
||
|
||
k_work_sleep(delay_ticks);
|
||
|
||
_WORK_Q->yield_work = yield_work;
|
||
}
|
||
|
||
/**
|
||
* @brief 释放一次CPU的使用权,可调度低于当前任务优先级的任务
|
||
* 返回机制:
|
||
* 给予的队列中有高于当前任务优先级的任务:直到所有更高优先给的任务被执行完后;
|
||
* 给予的队列中首个任务的优先级等于当前任务的优先级:执行完首个任务后返回。
|
||
* 栈用量 24 bytes
|
||
*
|
||
* @param delay_ticks 让出CPU的时间
|
||
*/
|
||
void k_work_sleep(k_tick_t delay_ticks)
|
||
{
|
||
k_work_q_t *work_q_handle;
|
||
k_work_t *work_handle;
|
||
k_work_handle_t *sleep_work;
|
||
k_tick_t sys_time;
|
||
|
||
_ASSERT_FALSE(s_kit_init_struct.malloc == NULL, "Never use 'k_init()' to initialize");
|
||
|
||
if ((size_t)delay_ticks > _SIGNED_MAX(delay_ticks))
|
||
{
|
||
delay_ticks = _SIGNED_MAX(delay_ticks);
|
||
}
|
||
|
||
_k_read_curr_handle(&work_q_handle, &work_handle);
|
||
sys_time = _K_PORT->get_sys_ticks();
|
||
_WORK->timeout = sys_time + delay_ticks;
|
||
|
||
sleep_work = _WORK_Q->sleep_work;
|
||
_WORK_Q->sleep_work = _WORK;
|
||
if (sleep_work != NULL)
|
||
{
|
||
if ((int)(_WORK->timeout - sleep_work->timeout) > 0 &&
|
||
_WORK_Q->sleep_work_prev != sleep_work)
|
||
{
|
||
_WORK_Q->sleep_work_prev = sleep_work;
|
||
// 当前任务的超时时间晚于前个任务的超时时间,上个任务将被阻塞
|
||
#if (CONFIG_K_KIT_LOG_ON)
|
||
_DBG_WRN("Work timeout conflict: previous task will be blocked %d ticks, "
|
||
"current work '%s', previous work '%s'",
|
||
(int)(_WORK->timeout - sleep_work->timeout),
|
||
_WORK->work_handle->name,
|
||
sleep_work->work_handle->name);
|
||
#else
|
||
_DBG_WRN("Work timeout conflict: previous task will be blocked %d ticks, "
|
||
"current work 0x%08x, previous work 0x%08x",
|
||
(int)(_WORK->timeout - sleep_work->timeout),
|
||
(size_t)_WORK->work_route,
|
||
(size_t)sleep_work->work_route);
|
||
#endif
|
||
}
|
||
}
|
||
|
||
_k_work_q_handler_take_event_list(&_WORK_Q->event_list, sys_time);
|
||
|
||
do
|
||
{
|
||
if (default_timer_q_hdl->hdl != NULL && /* 已创建软定时器队列对象 */
|
||
s_kit_init_struct.scheduler_disable == _k_nop && /* 非多线程 */
|
||
k_timer_q_handler(default_timer_q_hdl) == 0) /* 有就绪的定时任务 */
|
||
{
|
||
sys_time = _K_PORT->get_sys_ticks();
|
||
continue;
|
||
}
|
||
|
||
if (_WORK_Q->priority_tab != 0)
|
||
{
|
||
k_work_handle_t *exec_work = _k_work_q_handler_take_ready_work(_WORK->work_q_handle);
|
||
if (exec_work != NULL)
|
||
{
|
||
uint8_t exec_flag = exec_work->exec_flag;
|
||
exec_work->exec_flag = 1;
|
||
|
||
if (exec_work->obj_flag_type)
|
||
{
|
||
exec_work->work_route(exec_work->arg);
|
||
_k_timer_end(work_q_handle, exec_work);
|
||
}
|
||
else
|
||
{
|
||
if (s_cm_kit.curr_hook != exec_work->work_handle)
|
||
{
|
||
k_work_fn hook_entry;
|
||
|
||
s_cm_kit.curr_hook = exec_work->work_handle;
|
||
_k_work_log(exec_work->work_handle);
|
||
|
||
hook_entry = _WORK_Q->hook_entry;
|
||
if (hook_entry)
|
||
{
|
||
hook_entry(exec_work->work_handle);
|
||
}
|
||
}
|
||
|
||
exec_work->work_route(exec_work->arg);
|
||
}
|
||
_WORK_Q->curr_work = work_handle;
|
||
|
||
if (k_work_is_valid(exec_work->work_handle))
|
||
{
|
||
if (exec_work->delete_flag == 0)
|
||
{
|
||
exec_work->exec_flag = exec_flag;
|
||
if (exec_work->obj_flag_type == 0 && exec_work->obj_data.mbox_list != NULL)
|
||
{
|
||
if (_slist_peek_head(&exec_work->obj_data.mbox_list->mbox_idle) != NULL)
|
||
{
|
||
_K_DIS_SCHED();
|
||
_k_work_mbox_clr_list(&exec_work->obj_data.mbox_list->mbox_idle);
|
||
_K_EN_SCHED();
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
exec_work->exec_flag = 0;
|
||
k_work_delete(exec_work->work_handle);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if (work_handle->hdl == NULL)
|
||
{
|
||
break;
|
||
}
|
||
|
||
sys_time = _K_PORT->get_sys_ticks();
|
||
if (_k_work_q_handler_take_delay_list(_WORK_Q, sys_time) > 0 &&
|
||
_K_PORT->thread_sleep &&
|
||
*(volatile int *)&_WORK->timeout - sys_time > 0)
|
||
{
|
||
_K_PORT->thread_sleep(1);
|
||
sys_time = _K_PORT->get_sys_ticks();
|
||
_k_work_q_handler_take_delay_list(_WORK_Q, sys_time);
|
||
}
|
||
|
||
} while (*(volatile int *)&_WORK->timeout - sys_time > 0);
|
||
|
||
if (_WORK->exec_repeat != 0)
|
||
{
|
||
_WORK->exec_repeat = 0;
|
||
k_work_submit(_WORK->work_q_handle, _WORK->work_handle, 0);
|
||
}
|
||
|
||
if (_WORK_Q->curr_work)
|
||
{
|
||
if (s_cm_kit.curr_hook != _WORK_Q->curr_work)
|
||
{
|
||
k_work_fn hook_entry;
|
||
|
||
s_cm_kit.curr_hook = _WORK_Q->curr_work;
|
||
_k_work_log(_WORK_Q->curr_work);
|
||
|
||
hook_entry = _WORK_Q->hook_entry;
|
||
if (hook_entry)
|
||
{
|
||
hook_entry(_WORK_Q->curr_work);
|
||
}
|
||
}
|
||
}
|
||
|
||
_WORK_Q->sleep_work = sleep_work;
|
||
}
|
||
|
||
/**
|
||
* @brief 查询最近一次执行的任务
|
||
*
|
||
* @param work_q_handle 由 k_work_q_create() 初始化
|
||
* @return k_work_t* 指向任务对象
|
||
*/
|
||
k_work_t *k_get_curr_work_handle(k_work_q_t *work_q_handle)
|
||
{
|
||
k_work_q_handle_t *work_q;
|
||
|
||
_TEST_HANDLE(work_q_handle, return NULL);
|
||
|
||
work_q = work_q_handle->hdl;
|
||
return work_q->curr_work;
|
||
}
|
||
|
||
/**
|
||
* @brief 创建任务的邮箱
|
||
* 对象内存: 20 bytes
|
||
*
|
||
* k_mbox 与 k_fifo 的主要区别:
|
||
* 1. 邮箱是任务的扩展,与任务关联;
|
||
* 2. 邮件被发送的同时,对应的任务将被自动唤醒;
|
||
* 3. 邮件收取后,任务结束时被自动删除,也可使用 k_work_mbox_cancel() 来显式删除
|
||
*
|
||
* @param work_handle 由 k_work_create() 初始化
|
||
* @return k_err_t 0 -- 成功,-1 -- 任务对象无效或内存不足
|
||
*/
|
||
k_err_t k_work_mbox_create(k_work_t *work_handle)
|
||
{
|
||
k_work_handle_t *work;
|
||
k_work_mb_list_t *mbox_list;
|
||
|
||
_ASSERT_FALSE(s_kit_init_struct.malloc == NULL, "Never use 'k_init()' to initialize");
|
||
_TEST_HANDLE(work_handle, return -1);
|
||
|
||
work = work_handle->hdl;
|
||
if (work->obj_flag_type != 0)
|
||
{
|
||
_DBG_WRN("work_handle invalid");
|
||
return -1;
|
||
}
|
||
|
||
if (work->obj_data.mbox_list != NULL)
|
||
{
|
||
_DBG_WRN("work mbox was be created");
|
||
return -1;
|
||
}
|
||
|
||
if (work->work_q_handle == NULL)
|
||
{
|
||
_DBG_WRN("work_handle = %p was not submit to any work_q_handle handle", work);
|
||
}
|
||
|
||
_K_DIS_SCHED();
|
||
|
||
mbox_list = _K_PORT->malloc(sizeof(*mbox_list));
|
||
if (mbox_list != NULL)
|
||
{
|
||
_slist_init_list(&mbox_list->mbox_idle);
|
||
_slist_init_list(&mbox_list->mbox_valid);
|
||
work->obj_data.mbox_list = mbox_list;
|
||
}
|
||
|
||
_K_EN_SCHED();
|
||
|
||
if (mbox_list == NULL)
|
||
{
|
||
_DBG_WRN("Insufficient memory");
|
||
return -1;
|
||
}
|
||
else
|
||
{
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 删除任务的邮箱
|
||
*
|
||
* @param work_handle 由 k_work_create() 初始化
|
||
*/
|
||
void k_work_mbox_delete(k_work_t *work_handle)
|
||
{
|
||
k_work_handle_t *work;
|
||
|
||
_ASSERT_FALSE(s_kit_init_struct.malloc == NULL, "Never use 'k_init()' to initialize");
|
||
_TEST_HANDLE(work_handle, return);
|
||
|
||
work = work_handle->hdl;
|
||
|
||
if (work->obj_flag_type != 0)
|
||
{
|
||
_DBG_WRN("work_handle invalid");
|
||
return;
|
||
}
|
||
|
||
if (work->obj_data.mbox_list == NULL)
|
||
{
|
||
_DBG_WRN("work mbox never be created");
|
||
return;
|
||
}
|
||
|
||
_K_DIS_SCHED();
|
||
|
||
if (work->obj_data.mbox_list != NULL)
|
||
{
|
||
k_work_mb_list_t *mbox_list = work->obj_data.mbox_list;
|
||
_k_work_mbox_clr_list(&mbox_list->mbox_idle);
|
||
_k_work_mbox_clr_list(&mbox_list->mbox_valid);
|
||
_K_PORT->free(mbox_list);
|
||
work->obj_data.mbox_list = NULL;
|
||
}
|
||
|
||
_K_EN_SCHED();
|
||
}
|
||
|
||
/**
|
||
* @brief 申请一个邮件
|
||
* 邮件数据没有限制
|
||
* 不能申请给自己的邮件
|
||
* 管理块内存 8 bytes
|
||
*
|
||
* @param work_handle 由 k_work_create() 初始化
|
||
* @param size 数据大小
|
||
* @return void* 内存地址
|
||
*/
|
||
void *k_work_mbox_alloc(k_work_t *work_handle, size_t size)
|
||
{
|
||
k_work_handle_t *work;
|
||
k_work_mb_handle_t *mbox_data;
|
||
|
||
_ASSERT_FALSE(s_kit_init_struct.malloc == NULL, "Never use 'k_init()' to initialize");
|
||
_TEST_HANDLE(work_handle, return NULL);
|
||
|
||
work = work_handle->hdl;
|
||
|
||
if (work->work_q_handle == NULL)
|
||
{
|
||
_DBG_WRN("work was not pending or to be canceled");
|
||
return NULL;
|
||
}
|
||
|
||
if (work->obj_flag_type != 0)
|
||
{
|
||
_DBG_WRN("work_handle invalid");
|
||
return NULL;
|
||
}
|
||
|
||
if (work->obj_data.mbox_list == NULL)
|
||
{
|
||
_DBG_WRN("never create mbox with function 'k_work_mbox_create()'");
|
||
return NULL;
|
||
}
|
||
|
||
_K_DIS_SCHED();
|
||
mbox_data = _K_PORT->malloc(sizeof(*mbox_data) + size);
|
||
if (mbox_data != NULL)
|
||
{
|
||
mbox_data->ctrl.work_handle = work_handle;
|
||
}
|
||
_K_EN_SCHED();
|
||
|
||
if (mbox_data == NULL)
|
||
{
|
||
_DBG_WRN("Insufficient memory");
|
||
return NULL;
|
||
}
|
||
else
|
||
{
|
||
return (void *)&mbox_data[1];
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 取消已申请的邮件
|
||
*
|
||
* @param mbox 通过 k_work_mbox_alloc() 申请的数据
|
||
* @return k_err_t 0 -- 成功,-1 -- 工作队列对象或任务对象无效
|
||
*/
|
||
k_err_t k_work_mbox_cancel(void *mbox)
|
||
{
|
||
k_work_mb_handle_t *mbox_data = &((k_work_mb_handle_t *)mbox)[-1];
|
||
k_err_t ret = 0;
|
||
|
||
if (mbox == NULL)
|
||
{
|
||
_DBG_WRN("mbox invalid");
|
||
return -1;
|
||
}
|
||
|
||
k_work_handle_t *work = mbox_data->ctrl.work_handle->hdl;
|
||
if (work == NULL)
|
||
{
|
||
_DBG_WRN("work_handle invalid");
|
||
ret = -1;
|
||
}
|
||
|
||
if (work->work_q_handle == NULL)
|
||
{
|
||
_DBG_WRN("work was not pending or to be canceled");
|
||
ret = -1;
|
||
}
|
||
|
||
if (work->obj_data.mbox_list == NULL)
|
||
{
|
||
_DBG_WRN("never create mbox with function 'k_work_mbox_create()'");
|
||
ret = -1;
|
||
}
|
||
|
||
if (ret == 0)
|
||
{
|
||
_K_DIS_SCHED();
|
||
_K_PORT->free(mbox_data);
|
||
_K_EN_SCHED();
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
|
||
/**
|
||
* @brief 发送邮件
|
||
* 如果任务在延时的状态则立即被切换到就绪状态
|
||
*
|
||
* @param mbox 通过 k_work_mbox_alloc() 申请的数据
|
||
* @return k_err_t 0 -- 成功,-1 -- 工作队列对象或任务对象无效
|
||
*/
|
||
k_err_t k_work_mbox_submit(void *mbox)
|
||
{
|
||
k_work_mb_handle_t *mbox_data = &((k_work_mb_handle_t *)mbox)[-1];
|
||
k_work_handle_t *work = mbox_data->ctrl.work_handle->hdl;
|
||
k_err_t ret = 0;
|
||
|
||
if (mbox == NULL)
|
||
{
|
||
_DBG_WRN("mbox invalid");
|
||
return -1;
|
||
}
|
||
if (work == NULL)
|
||
{
|
||
_DBG_WRN("work_handle invalid");
|
||
ret = -1;
|
||
}
|
||
else if (work->work_q_handle == NULL)
|
||
{
|
||
_DBG_WRN("work was not pending or to be canceled");
|
||
ret = -1;
|
||
}
|
||
else if (work->obj_flag_type != 0)
|
||
{
|
||
_DBG_WRN("work_handle invalid");
|
||
ret = -1;
|
||
}
|
||
else if (work->obj_data.mbox_list == NULL)
|
||
{
|
||
_DBG_WRN("never create mbox with function 'k_work_mbox_create()'");
|
||
ret = -1;
|
||
}
|
||
|
||
if (ret != 0)
|
||
{
|
||
_K_DIS_SCHED();
|
||
_K_PORT->free(mbox_data);
|
||
_K_EN_SCHED();
|
||
return ret;
|
||
}
|
||
|
||
_slist_init_node(&mbox_data->ctrl.state_node);
|
||
_K_DIS_SCHED();
|
||
_slist_insert_tail(&work->obj_data.mbox_list->mbox_valid, &mbox_data->ctrl.state_node);
|
||
_K_EN_SCHED();
|
||
|
||
k_work_submit(work->work_q_handle, work->work_handle, 0);
|
||
|
||
return ret;
|
||
}
|
||
|
||
/**
|
||
* @brief 提取邮件
|
||
* 当任务返回后自动被清除
|
||
*
|
||
* @return void* 数据地址,NULL -- 邮箱队列为空
|
||
*/
|
||
void *k_work_mbox_take(void)
|
||
{
|
||
k_work_q_t *work_q_handle;
|
||
k_work_t *work_handle;
|
||
k_work_handle_t *work;
|
||
__slist_node_t *node;
|
||
|
||
_k_read_curr_handle(&work_q_handle, &work_handle);
|
||
work = work_handle->hdl;
|
||
|
||
if (work == NULL)
|
||
{
|
||
_DBG_WRN("work_handle invalid");
|
||
return NULL;
|
||
}
|
||
|
||
if (work->obj_flag_type != 0)
|
||
{
|
||
_DBG_WRN("work_handle invalid");
|
||
return NULL;
|
||
}
|
||
|
||
if (work->obj_data.mbox_list == NULL)
|
||
{
|
||
_DBG_WRN("never create mbox with function 'k_work_mbox_create()'");
|
||
return NULL;
|
||
}
|
||
|
||
_K_DIS_SCHED();
|
||
|
||
node = _slist_take_head(&work->obj_data.mbox_list->mbox_valid);
|
||
if (node == NULL)
|
||
{
|
||
_K_EN_SCHED();
|
||
return NULL;
|
||
}
|
||
else
|
||
{
|
||
k_work_mb_handle_t *mbox_data = _K_CONTAINER_OF(node, k_work_mb_handle_t, ctrl.state_node);
|
||
_slist_insert_tail(&work->obj_data.mbox_list->mbox_idle, &mbox_data->ctrl.state_node);
|
||
_K_EN_SCHED();
|
||
return &mbox_data[1];
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 查询邮件
|
||
*
|
||
* @return void* 数据地址,NULL -- 邮箱队列为空
|
||
*/
|
||
void *k_work_mbox_peek(void)
|
||
{
|
||
k_work_q_t *work_q_handle;
|
||
k_work_t *work_handle;
|
||
k_work_handle_t *work;
|
||
__slist_node_t *node;
|
||
|
||
_k_read_curr_handle(&work_q_handle, &work_handle);
|
||
work = work_handle->hdl;
|
||
|
||
if (work == NULL)
|
||
{
|
||
_DBG_WRN("work_handle invalid");
|
||
return NULL;
|
||
}
|
||
|
||
if (work->obj_flag_type != 0)
|
||
{
|
||
_DBG_WRN("work_handle invalid");
|
||
return NULL;
|
||
}
|
||
|
||
if (work->obj_data.mbox_list == NULL)
|
||
{
|
||
_DBG_WRN("never create mbox with function 'k_work_mbox_create()'");
|
||
return NULL;
|
||
}
|
||
|
||
node = _slist_peek_head(&work->obj_data.mbox_list->mbox_valid);
|
||
if (node == NULL)
|
||
{
|
||
return NULL;
|
||
}
|
||
else
|
||
{
|
||
k_work_mb_handle_t *mbox_data = _K_CONTAINER_OF(node, k_work_mb_handle_t, ctrl.state_node);
|
||
return (void *)&mbox_data[1];
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 清空任务的所有邮件
|
||
*/
|
||
void k_work_mbox_clr(void)
|
||
{
|
||
k_work_q_t *work_q_handle;
|
||
k_work_t *work_handle;
|
||
k_work_handle_t *work;
|
||
|
||
_ASSERT_FALSE(s_kit_init_struct.malloc == NULL, "Never use 'k_init()' to initialize");
|
||
|
||
_k_read_curr_handle(&work_q_handle, &work_handle);
|
||
work = work_handle->hdl;
|
||
|
||
if (work == NULL)
|
||
{
|
||
_DBG_WRN("work_handle invalid");
|
||
return;
|
||
}
|
||
|
||
if (work->obj_flag_type != 0)
|
||
{
|
||
_DBG_WRN("work_handle invalid");
|
||
return;
|
||
}
|
||
|
||
if (work->obj_data.mbox_list == NULL)
|
||
{
|
||
_DBG_WRN("work mbox never be created");
|
||
return;
|
||
}
|
||
|
||
_K_DIS_SCHED();
|
||
|
||
if (work->obj_data.mbox_list != NULL)
|
||
{
|
||
_k_work_mbox_clr_list(&work->obj_data.mbox_list->mbox_idle);
|
||
_k_work_mbox_clr_list(&work->obj_data.mbox_list->mbox_valid);
|
||
}
|
||
|
||
_K_EN_SCHED();
|
||
}
|
||
|
||
/**
|
||
* @brief 软定时器队列执行入口
|
||
* 所有在队列中就绪的定时器都将被按顺序逐个执行。
|
||
* 执行顺序为:
|
||
* 1. 按定时器的优先级
|
||
* 2. 按就绪的顺序
|
||
* 栈用量 32 bytes
|
||
*
|
||
* @param timer_q_handle 由 k_timer_q_create() 初始化
|
||
* @return k_tick_t 距离下个延时定时器的时间
|
||
*/
|
||
k_tick_t k_timer_q_handler(k_timer_q_t *timer_q_handle)
|
||
{
|
||
return k_work_q_handler((k_work_q_t *)timer_q_handle);
|
||
}
|
||
|
||
/**
|
||
* @brief 创建一个软定时器队列的对象
|
||
* 对象数据由堆自动分配
|
||
* 对象内存: 104 bytes
|
||
*
|
||
* @param timer_q_handle[out] 初始化队列对象指针
|
||
* @return k_err_t 0 -- 成功, -1 -- 堆内存不足
|
||
*/
|
||
k_err_t k_timer_q_create(k_timer_q_t *timer_q_handle)
|
||
{
|
||
return k_work_q_create((k_work_q_t *)timer_q_handle);
|
||
}
|
||
|
||
/**
|
||
* @brief 删除一个软定时器队列的对象
|
||
* 1. 在该队列中所有已就绪的定时器被立即删除
|
||
* 2. 延时中的定时器在到达时间后被立即删除
|
||
* 3. 软定时器队列被删除
|
||
* 4. 软定时器队列及相关定时器的堆内存被自动回收
|
||
*
|
||
* @param timer_q_handle 由 k_timer_q_create() 初始化
|
||
*/
|
||
void k_timer_q_delete(k_timer_q_t *timer_q_handle)
|
||
{
|
||
k_work_q_delete((k_work_q_t *)timer_q_handle);
|
||
}
|
||
|
||
/**
|
||
* @brief 注册一个函数:当有任务被提交时,此回调函数将被自动执行
|
||
*
|
||
* @param timer_q_handle 由 k_timer_q_create() 初始化
|
||
* @param timer_q_resume 当有任务被提交时,被执行的回调函数将
|
||
* @param arg 回调函数将附带的参数
|
||
*/
|
||
void k_timer_q_resume_regist(k_timer_q_t *timer_q_handle, k_timer_q_fn timer_q_resume, void *arg)
|
||
{
|
||
k_work_q_resume_regist((k_work_q_t *)timer_q_handle, (k_work_q_fn)timer_q_resume, arg);
|
||
}
|
||
|
||
/**
|
||
* @brief 获取软定时器队列是否有效
|
||
*
|
||
* @param timer_q_handle 由 k_timer_q_create() 初始化
|
||
* @retval true 对象有效
|
||
* @retval false 对象无效
|
||
*/
|
||
bool k_timer_q_is_valid(k_timer_q_t *timer_q_handle)
|
||
{
|
||
return k_work_q_is_valid((k_work_q_t *)timer_q_handle);
|
||
}
|
||
|
||
/**
|
||
* @brief 获取是否有正在延时状态的定时器
|
||
*
|
||
* @retval true 有延时状态的定时器
|
||
* @retval false 队列已空
|
||
*/
|
||
bool k_timer_q_delayed_state(k_timer_q_t *timer_q_handle)
|
||
{
|
||
return k_work_q_delayed_state((k_work_q_t *)timer_q_handle);
|
||
}
|
||
|
||
/**
|
||
* @brief 获取软定时器队列中是否有就绪的定时器
|
||
*
|
||
* @param timer_q_handle 由 k_timer_q_create() 初始化
|
||
* @retval true 有就绪的定时器
|
||
* @retval false 队列已空
|
||
*/
|
||
bool k_timer_q_ready_state(k_timer_q_t *timer_q_handle)
|
||
{
|
||
return k_work_q_ready_state((k_work_q_t *)timer_q_handle);
|
||
}
|
||
|
||
/**
|
||
* @brief 创建由软定时器队列管理的定时器
|
||
* 定时器对象数据由堆内存自动分配
|
||
* 定时器必须返回
|
||
* 定时器堆栈来自 k_timer_q_handler()
|
||
* 对象内存: 48 bytes
|
||
*
|
||
* @param timer_handle[out] 初始化定时器对象数据
|
||
* @param timer_q_handle 由 k_timer_q_create() 初始化
|
||
* @param timer_route 定时器的入口地址
|
||
* @param arg 附带的一个参数指针
|
||
* @param priority 定时器优先级,0 .. 7,0 为最低
|
||
* @return k_err_t 0 -- 成功,-1 -- 失败:对象非空或堆内存不足
|
||
*/
|
||
k_err_t k_timer_create(k_timer_t *timer_handle,
|
||
k_timer_q_t *timer_q_handle,
|
||
k_timer_fn timer_route,
|
||
void *arg,
|
||
uint8_t priority)
|
||
{
|
||
_ASSERT_FALSE(s_kit_init_struct.malloc == NULL, "Never use 'k_init()' to initialize");
|
||
_TEST_HANDLE(timer_q_handle, return -1);
|
||
|
||
if (k_work_create((k_work_t *)timer_handle, "", (k_work_fn)timer_route, arg, priority) == 0)
|
||
{
|
||
k_work_handle_t *work = timer_handle->hdl;
|
||
work->work_q_handle = (k_work_q_t *)timer_q_handle;
|
||
work->obj_flag_type = 1;
|
||
work->obj_data.period = _SIGNED_MAX(work->obj_data.period);
|
||
return 0;
|
||
}
|
||
else
|
||
{
|
||
return -1;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 删除由软定时器队列管理的定时器
|
||
* 定时器立即失效
|
||
* 定时器对象数据被立即回收
|
||
*
|
||
* @param timer_handle 由 k_timer_create() 初始化
|
||
*/
|
||
void k_timer_delete(k_timer_t *timer_handle)
|
||
{
|
||
_ASSERT_FALSE(s_kit_init_struct.malloc == NULL, "Never use 'k_init()' to initialize");
|
||
_TEST_HANDLE(timer_handle, return);
|
||
|
||
if (timer_handle == NULL)
|
||
{
|
||
k_work_q_t *work_q_handle;
|
||
_k_read_curr_handle(&work_q_handle, (k_work_t **)&timer_handle);
|
||
}
|
||
|
||
_K_DIS_SCHED();
|
||
k_work_handle_t *work = timer_handle->hdl;
|
||
if (work->exec_flag == 0)
|
||
{
|
||
_k_work_delete((k_work_t *)timer_handle);
|
||
}
|
||
else
|
||
{
|
||
work->delete_flag = 1;
|
||
}
|
||
_K_EN_SCHED();
|
||
}
|
||
|
||
/**
|
||
* @brief 设置定时器的自动重装值
|
||
*
|
||
* @param timer_handle 由 k_timer_create() 初始化
|
||
* @param periodic 是否自动重装
|
||
* @param period 重装值
|
||
*/
|
||
void k_timer_set_period(k_timer_t *timer_handle, bool periodic, k_tick_t period)
|
||
{
|
||
k_work_handle_t *work = timer_handle->hdl;
|
||
if (work)
|
||
{
|
||
if ((size_t)period > _SIGNED_MAX(period))
|
||
{
|
||
period = _SIGNED_MAX(period);
|
||
}
|
||
_K_DIS_SCHED();
|
||
work->obj_flag_periodic = periodic;
|
||
work->obj_data.period = period;
|
||
_K_EN_SCHED();
|
||
}
|
||
else
|
||
{
|
||
_DBG_WRN("you must using k_timer_create() to create one timer_handle first");
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 启动定时器
|
||
*
|
||
* @param timer_handle 由 k_timer_create() 初始化
|
||
* @param periodic 是否自动重装
|
||
* @param period 重装值
|
||
* @param delay_ticks 延时启动
|
||
*/
|
||
void k_timer_start(k_timer_t *timer_handle, k_tick_t delay_ticks)
|
||
{
|
||
k_work_handle_t *work;
|
||
|
||
_TEST_HANDLE(timer_handle, return);
|
||
|
||
work = timer_handle->hdl;
|
||
_k_work_do_submit(work->work_q_handle, (k_work_t *)timer_handle, _K_PORT->get_sys_ticks() + delay_ticks, _FALSE);
|
||
}
|
||
|
||
/**
|
||
* @brief 挂起定时器,定时器不会被删除
|
||
*
|
||
* @param timer_handle 由 k_timer_create() 初始化
|
||
*/
|
||
void k_timer_stop(k_timer_t *timer_handle)
|
||
{
|
||
k_work_suspend((k_work_t *)timer_handle);
|
||
}
|
||
|
||
/**
|
||
* @brief 生成一个临时定时器,执行完自动删除
|
||
*
|
||
* @param timer_q_handle 由 k_timer_q_create() 初始化
|
||
* @param timer_route
|
||
* @param arg
|
||
* @param delay_ticks
|
||
* @return k_err_t
|
||
*/
|
||
k_err_t k_timer_newsubmit(k_timer_q_t *timer_q_handle, k_timer_fn timer_route, void *arg, k_tick_t delay_ticks)
|
||
{
|
||
k_timer_t timer_handle;
|
||
|
||
_TEST_HANDLE(timer_q_handle, return -1);
|
||
|
||
memset(&timer_handle, 0, sizeof(timer_handle));
|
||
|
||
if (k_timer_create(
|
||
&timer_handle,
|
||
timer_q_handle,
|
||
timer_route,
|
||
arg,
|
||
0) == 0)
|
||
{
|
||
k_work_handle_t *work = timer_handle.hdl;
|
||
work->obj_flag_auto_del = 1;
|
||
k_timer_set_period(&timer_handle, _FALSE, delay_ticks);
|
||
k_timer_start(&timer_handle, delay_ticks);
|
||
return 0;
|
||
}
|
||
else
|
||
{
|
||
return -1;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 删除并重新生成一个新的临时定时器,执行完自动删除
|
||
*
|
||
* @param timer_q_handle 由 k_timer_q_create() 初始化
|
||
* @param timer_route
|
||
* @param arg
|
||
* @param delay_ticks
|
||
* @return k_err_t
|
||
*/
|
||
k_err_t k_timer_resubmit(k_timer_q_t *timer_q_handle, k_timer_fn timer_route, void *arg, k_tick_t delay_ticks)
|
||
{
|
||
k_timer_cancel(timer_q_handle, timer_route);
|
||
return k_timer_newsubmit(timer_q_handle, timer_route, arg, delay_ticks);
|
||
}
|
||
|
||
/**
|
||
* @brief 立即删除临时定时器
|
||
*
|
||
* @param timer_q_handle 由 k_timer_q_create() 初始化
|
||
* @param timer_route
|
||
*/
|
||
void k_timer_cancel(k_timer_q_t *timer_q_handle, k_timer_fn timer_route)
|
||
{
|
||
k_work_q_handle_t *work_q;
|
||
|
||
_TEST_HANDLE(timer_q_handle, return);
|
||
|
||
_K_DIS_SCHED();
|
||
|
||
work_q = timer_q_handle->hdl;
|
||
if (work_q != NULL)
|
||
{
|
||
do
|
||
{
|
||
__dlist_t *test_list = &work_q->event_list;
|
||
__dlist_node_t *test_node = _dlist_peek_head(test_list);
|
||
__dlist_node_t *end_node = _dlist_peek_tail(test_list);
|
||
__dlist_node_t *prev_node = NULL;
|
||
|
||
do
|
||
{
|
||
k_work_handle_t *test_work;
|
||
|
||
if (test_node == NULL)
|
||
{
|
||
break;
|
||
}
|
||
test_work = _K_CONTAINER_OF(test_node, k_work_handle_t, event_node);
|
||
|
||
if ((void *)test_work->work_route == (void *)timer_route)
|
||
{
|
||
_dlist_remove(test_list, test_node);
|
||
if (prev_node == NULL)
|
||
{
|
||
test_node = _dlist_peek_head(test_list);
|
||
}
|
||
else
|
||
{
|
||
test_node = _dlist_peek_next(test_list, prev_node);
|
||
}
|
||
_K_PORT->free(test_work);
|
||
}
|
||
else
|
||
{
|
||
prev_node = test_node;
|
||
test_node = _dlist_peek_next(test_list, prev_node);
|
||
}
|
||
|
||
} while (prev_node != end_node);
|
||
|
||
} while (0);
|
||
|
||
do
|
||
{
|
||
__slist_t *test_list = &work_q->delayed_list;
|
||
__slist_node_t *test_node = _slist_peek_head(test_list);
|
||
__slist_node_t *end_node = _slist_peek_tail(test_list);
|
||
__slist_node_t *prev_node = NULL;
|
||
|
||
do
|
||
{
|
||
k_work_handle_t *test_work;
|
||
|
||
if (test_node == NULL)
|
||
{
|
||
break;
|
||
}
|
||
test_work = _K_CONTAINER_OF(test_node, k_work_handle_t, state_node);
|
||
|
||
if ((void *)test_work->work_route == (void *)timer_route)
|
||
{
|
||
_slist_remove_next(test_list, prev_node, test_node);
|
||
if (prev_node == NULL)
|
||
{
|
||
test_node = _slist_peek_head(test_list);
|
||
}
|
||
else
|
||
{
|
||
test_node = _slist_peek_next(prev_node);
|
||
}
|
||
_K_PORT->free(test_work);
|
||
}
|
||
else
|
||
{
|
||
prev_node = test_node;
|
||
test_node = _slist_peek_next(prev_node);
|
||
}
|
||
|
||
} while (prev_node != end_node);
|
||
|
||
} while (0);
|
||
|
||
do
|
||
{
|
||
size_t i;
|
||
for (i = 0; i < sizeof(work_q->ready_list) / sizeof(work_q->ready_list[0]); i++)
|
||
{
|
||
__slist_t *test_list = &work_q->ready_list[i];
|
||
__slist_node_t *test_node = _slist_peek_head(test_list);
|
||
__slist_node_t *end_node = _slist_peek_tail(test_list);
|
||
__slist_node_t *prev_node = NULL;
|
||
|
||
do
|
||
{
|
||
k_work_handle_t *test_work;
|
||
|
||
if (test_node == NULL)
|
||
{
|
||
break;
|
||
}
|
||
test_work = _K_CONTAINER_OF(test_node, k_work_handle_t, state_node);
|
||
|
||
if ((void *)test_work->work_route == (void *)timer_route)
|
||
{
|
||
_slist_remove_next(test_list, prev_node, test_node);
|
||
if (prev_node == NULL)
|
||
{
|
||
test_node = _slist_peek_head(test_list);
|
||
}
|
||
else
|
||
{
|
||
test_node = _slist_peek_next(prev_node);
|
||
}
|
||
_K_PORT->free(test_work);
|
||
}
|
||
else
|
||
{
|
||
prev_node = test_node;
|
||
test_node = _slist_peek_next(prev_node);
|
||
}
|
||
|
||
} while (prev_node != end_node);
|
||
}
|
||
|
||
} while (0);
|
||
}
|
||
|
||
_K_EN_SCHED();
|
||
}
|
||
|
||
/**
|
||
* @brief 获取定时器对象是否有效
|
||
*
|
||
* @param timer_handle 由 k_timer_create() 初始化
|
||
* @retval true 定时器对象有效
|
||
* @retval false 定时器对象无效
|
||
*/
|
||
bool k_timer_is_valid(k_timer_t *timer_handle)
|
||
{
|
||
return k_work_is_valid((k_work_t *)timer_handle);
|
||
}
|
||
|
||
/**
|
||
* @brief 获取定时器是否在就绪或延时的状态
|
||
*
|
||
* @param timer_handle 由 k_timer_create() 初始化
|
||
* @retval true 定时器就绪或延时
|
||
* @retval false 定时器被挂起
|
||
*/
|
||
bool k_timer_is_pending(k_timer_t *timer_handle)
|
||
{
|
||
return k_work_is_pending((k_work_t *)timer_handle);
|
||
}
|
||
|
||
/**
|
||
* @brief 查询当前是否自动重装
|
||
*
|
||
* @param timer_handle 由 k_timer_create() 初始化
|
||
* @retval true 当前状态为自动重装
|
||
* @retval false 当前状态为单次模式
|
||
*/
|
||
bool k_timer_is_periodic(k_timer_t *timer_handle)
|
||
{
|
||
k_work_handle_t *work = timer_handle->hdl;
|
||
return (bool)!!work->obj_flag_periodic;
|
||
}
|
||
|
||
/**
|
||
* @brief 查询当前的自动重装值
|
||
*
|
||
* @param timer_handle
|
||
* @return k_tick_t
|
||
*/
|
||
k_tick_t k_timer_get_period(k_timer_t *timer_handle)
|
||
{
|
||
k_work_handle_t *work;
|
||
|
||
_TEST_HANDLE(timer_handle, return -1u);
|
||
|
||
work = timer_handle->hdl;
|
||
return work->obj_data.period;
|
||
}
|
||
|
||
/**
|
||
* @brief 获取定时器距离下个执行的剩余时间
|
||
*
|
||
* @param timer_handle
|
||
* @return k_tick_t
|
||
*/
|
||
k_tick_t k_timer_time_remain(k_timer_t *timer_handle)
|
||
{
|
||
return k_work_time_remain((k_work_t *)timer_handle);
|
||
}
|
||
|
||
/**
|
||
* @brief 创建一个FIFO对象
|
||
* 对象数据由堆自动分配
|
||
* 对象内存: 20 bytes
|
||
*
|
||
* @param fifo_handle[out] 初始化FIFO对象指针
|
||
* @return k_err_t 0 -- 成功, -1 -- 堆内存不足
|
||
*/
|
||
k_err_t k_fifo_q_create(k_fifo_t *fifo_handle)
|
||
{
|
||
k_fifo_q_handle_t *fifo_q;
|
||
|
||
_ASSERT_FALSE(s_kit_init_struct.malloc == NULL, "Never use 'k_init()' to initialize");
|
||
|
||
_K_DIS_SCHED();
|
||
fifo_q = _K_PORT->malloc(sizeof(k_fifo_q_handle_t));
|
||
if (fifo_q != NULL)
|
||
{
|
||
fifo_handle->hdl = fifo_q;
|
||
fifo_q->resume_work = NULL;
|
||
fifo_q->resume_delay = 0;
|
||
_slist_init_list(&fifo_q->list);
|
||
}
|
||
_K_EN_SCHED();
|
||
|
||
if (fifo_q == NULL)
|
||
{
|
||
_DBG_WRN("Insufficient memory");
|
||
return -1;
|
||
}
|
||
else
|
||
{
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 删除一个FIFO的对象
|
||
* 1. 在该队列中所有数据被立即删除
|
||
* 2. FIFO对象被删除
|
||
* 3. FIFO对象及数据的堆内存被自动回收
|
||
*
|
||
* @param fifo_handle 由 k_fifo_q_create() 初始化
|
||
*/
|
||
void k_fifo_q_delete(k_fifo_t *fifo_handle)
|
||
{
|
||
k_fifo_q_handle_t *fifo_q;
|
||
|
||
_TEST_HANDLE(fifo_handle, return);
|
||
|
||
_K_DIS_SCHED();
|
||
|
||
fifo_q = fifo_handle->hdl;
|
||
for (;;)
|
||
{
|
||
__slist_node_t *node = _slist_take_head(&fifo_q->list);
|
||
if (node == NULL)
|
||
{
|
||
break;
|
||
}
|
||
else
|
||
{
|
||
k_fifo_handle_t *fifo_data = _K_CONTAINER_OF(node, k_fifo_handle_t, ctrl.state_node);
|
||
_K_PORT->free(fifo_data);
|
||
}
|
||
}
|
||
_K_PORT->free(fifo_q);
|
||
fifo_handle->hdl = NULL;
|
||
|
||
_K_EN_SCHED();
|
||
}
|
||
|
||
/**
|
||
* @brief 清除FIFO内的所有数据
|
||
*
|
||
* @param fifo_handle 由 k_fifo_q_create() 初始化
|
||
*/
|
||
void k_fifo_q_clr(k_fifo_t *fifo_handle)
|
||
{
|
||
k_fifo_q_handle_t *fifo_q;
|
||
|
||
_ASSERT_FALSE(s_kit_init_struct.malloc == NULL, "Never use 'k_init()' to initialize");
|
||
_TEST_HANDLE(fifo_handle, return);
|
||
|
||
_K_DIS_SCHED();
|
||
|
||
fifo_q = fifo_handle->hdl;
|
||
for (;;)
|
||
{
|
||
__slist_node_t *node = _slist_take_head(&fifo_q->list);
|
||
if (node == NULL)
|
||
{
|
||
break;
|
||
}
|
||
else
|
||
{
|
||
k_fifo_handle_t *fifo_data = _K_CONTAINER_OF(node, k_fifo_handle_t, ctrl.state_node);
|
||
_K_PORT->free(fifo_data);
|
||
}
|
||
}
|
||
|
||
_K_EN_SCHED();
|
||
}
|
||
|
||
/**
|
||
* @brief 获取 FIFO 对象是否有效
|
||
*
|
||
* @param fifo_handle 由 k_fifo_q_create() 初始化
|
||
* @retval true
|
||
* @retval false
|
||
*/
|
||
bool k_fifo_q_is_valid(k_fifo_t *fifo_handle)
|
||
{
|
||
if (s_kit_init_struct.malloc == NULL || fifo_handle == NULL || fifo_handle->hdl == NULL)
|
||
{
|
||
return _FALSE;
|
||
}
|
||
else
|
||
{
|
||
return _TRUE;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 注册任务,当队列非空时,任务被唤醒。
|
||
* 注意同时只能注册一个任务
|
||
*
|
||
* @param fifo_handle 由 k_fifo_q_create() 初始化
|
||
* @param work_handle 由 k_work_create() 初始化
|
||
* @param delay_ticks 延迟唤醒时间
|
||
*/
|
||
void k_fifo_q_regist(k_fifo_t *fifo_handle, k_work_t *work_handle, k_tick_t delay_ticks)
|
||
{
|
||
k_fifo_q_handle_t *fifo_q;
|
||
|
||
_TEST_HANDLE(fifo_handle, return);
|
||
|
||
fifo_q = fifo_handle->hdl;
|
||
fifo_q->resume_work = work_handle;
|
||
fifo_q->resume_delay = delay_ticks;
|
||
}
|
||
|
||
/**
|
||
* @brief 取消注册任务
|
||
*
|
||
* @param fifo_handle 由 k_fifo_q_create() 初始化
|
||
*/
|
||
void k_fifo_q_unregist(k_fifo_t *fifo_handle)
|
||
{
|
||
k_fifo_q_handle_t *fifo_q;
|
||
|
||
_TEST_HANDLE(fifo_handle, return);
|
||
|
||
fifo_q = fifo_handle->hdl;
|
||
fifo_q->resume_work = NULL;
|
||
}
|
||
|
||
/**
|
||
* @brief 申请可用于FIFO的数据结构
|
||
* 管理块内存 8 bytes
|
||
*
|
||
* @param size 数据结构大小,单位为字节
|
||
* @return void* 数据结构地址,为 NULL 时表示内存不足
|
||
*/
|
||
void *k_fifo_alloc(size_t size)
|
||
{
|
||
k_fifo_handle_t *fifo_data;
|
||
|
||
_ASSERT_FALSE(s_kit_init_struct.malloc == NULL, "Never use 'k_init()' to initialize");
|
||
|
||
_K_DIS_SCHED();
|
||
fifo_data = _K_PORT->malloc(sizeof(*fifo_data) + size);
|
||
_K_EN_SCHED();
|
||
|
||
if (fifo_data == NULL)
|
||
{
|
||
_DBG_WRN("Insufficient memory");
|
||
return NULL;
|
||
}
|
||
else
|
||
{
|
||
fifo_data->ctrl.free_flag = _K_FIFO_FREE;
|
||
return (void *)&fifo_data[1];
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 释放由 k_fifo_alloc() 申请的数据结构
|
||
* 注意数据不允许在FIFO中时被释放
|
||
*
|
||
* @param data 数据结构地址
|
||
* @return k_err_t 0 -- 成功,-1 -- 数据未从FIFO中提取或数据无效
|
||
*/
|
||
k_err_t k_fifo_free(void *data)
|
||
{
|
||
k_fifo_handle_t *fifo_data;
|
||
|
||
_ASSERT_FALSE(s_kit_init_struct.malloc == NULL, "Never use 'k_init()' to initialize");
|
||
|
||
if (data == NULL)
|
||
{
|
||
_DBG_WRN("data invalid");
|
||
return -1;
|
||
}
|
||
fifo_data = &((k_fifo_handle_t *)data)[-1];
|
||
|
||
_K_DIS_SCHED();
|
||
if (fifo_data->ctrl.free_flag == _K_FIFO_FREE)
|
||
{
|
||
fifo_data->ctrl.free_flag = 0;
|
||
_K_PORT->free(fifo_data);
|
||
fifo_data = NULL;
|
||
}
|
||
_K_EN_SCHED();
|
||
|
||
if (fifo_data != NULL)
|
||
{
|
||
_DBG_WRN("%p was not in fifo queue, can not to free", data);
|
||
return -1;
|
||
}
|
||
else
|
||
{
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 把数据结构压入到FIFO中
|
||
*
|
||
* @param fifo_handle 由 k_fifo_q_create() 初始化
|
||
* @param data 数据结构
|
||
* @return k_err_t 0 -- 成功,-1 -- FIFO对象无效或数据结不是由 k_fifo_alloc() 所创建
|
||
*/
|
||
k_err_t k_fifo_put(k_fifo_t *fifo_handle, void *data)
|
||
{
|
||
k_fifo_q_handle_t *fifo_q;
|
||
k_fifo_handle_t *fifo_data;
|
||
bool resume_flag = _FALSE;
|
||
|
||
_TEST_HANDLE(fifo_handle, return -1);
|
||
|
||
if (data == NULL)
|
||
{
|
||
_DBG_WRN("data invalid");
|
||
return -1;
|
||
}
|
||
|
||
fifo_q = fifo_handle->hdl;
|
||
fifo_data = &((k_fifo_handle_t *)data)[-1];
|
||
|
||
if (fifo_data->ctrl.free_flag != _K_FIFO_FREE)
|
||
{
|
||
_DBG_WRN("fifo_data invalid");
|
||
return -1;
|
||
}
|
||
|
||
_slist_init_node(&fifo_data->ctrl.state_node);
|
||
_K_DIS_INT();
|
||
if (_slist_peek_head(&fifo_q->list) == NULL)
|
||
{
|
||
resume_flag = _TRUE;
|
||
}
|
||
_slist_insert_tail(&fifo_q->list, &fifo_data->ctrl.state_node);
|
||
_K_EN_INT();
|
||
|
||
if (resume_flag)
|
||
{
|
||
_k_ipc_resume(fifo_q->resume_work, fifo_q->resume_delay);
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* @brief 从FIFO中弹出最先压入的数据
|
||
*
|
||
* @param fifo_handle 由 k_fifo_q_create() 初始化
|
||
* @return void* 数据地址,NULL -- FIFO队列为空
|
||
*/
|
||
void *k_fifo_take(k_fifo_t *fifo_handle)
|
||
{
|
||
k_fifo_q_handle_t *fifo_q;
|
||
__slist_node_t *node;
|
||
|
||
_TEST_HANDLE(fifo_handle, return NULL);
|
||
|
||
fifo_q = fifo_handle->hdl;
|
||
|
||
_K_DIS_INT();
|
||
node = _slist_take_head(&fifo_q->list);
|
||
_K_EN_INT();
|
||
|
||
if (node == NULL)
|
||
{
|
||
return NULL;
|
||
}
|
||
else
|
||
{
|
||
k_fifo_handle_t *fifo_data = _K_CONTAINER_OF(node, k_fifo_handle_t, ctrl.state_node);
|
||
fifo_data->ctrl.free_flag = _K_FIFO_FREE;
|
||
return (void *)&fifo_data[1];
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 查询FIFO中头部的数据地址
|
||
*
|
||
* @param fifo_handle 由 k_fifo_q_create() 初始化
|
||
* @return void* 数据地址,NULL -- FIFO队列为空
|
||
*/
|
||
void *k_fifo_peek_head(k_fifo_t *fifo_handle)
|
||
{
|
||
k_fifo_q_handle_t *fifo_q;
|
||
__slist_node_t *node;
|
||
|
||
_TEST_HANDLE(fifo_handle, return NULL);
|
||
|
||
fifo_q = fifo_handle->hdl;
|
||
node = _slist_peek_head(&fifo_q->list);
|
||
if (node == NULL)
|
||
{
|
||
return NULL;
|
||
}
|
||
else
|
||
{
|
||
k_fifo_handle_t *fifo_data = _K_CONTAINER_OF(node, k_fifo_handle_t, ctrl.state_node);
|
||
return (void *)&fifo_data[1];
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 查询FIFO中尾部的数据地址
|
||
*
|
||
* @param fifo_handle 由 k_fifo_q_create() 初始化
|
||
* @return void* 数据地址,NULL -- FIFO队列为空
|
||
*/
|
||
void *k_fifo_peek_tail(k_fifo_t *fifo_handle)
|
||
{
|
||
k_fifo_q_handle_t *fifo_q;
|
||
__slist_node_t *node;
|
||
|
||
_TEST_HANDLE(fifo_handle, return NULL);
|
||
|
||
fifo_q = fifo_handle->hdl;
|
||
node = _slist_peek_tail(&fifo_q->list);
|
||
if (node == NULL)
|
||
{
|
||
return NULL;
|
||
}
|
||
else
|
||
{
|
||
k_fifo_handle_t *fifo_data = _K_CONTAINER_OF(node, k_fifo_handle_t, ctrl.state_node);
|
||
return (void *)&fifo_data[1];
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 创建一个QUEUE对象
|
||
* 对象数据由堆自动分配
|
||
* 对象内存: 32 bytes
|
||
*
|
||
* @param queue_handle[out] 初始化QUEUE对象指针
|
||
* @param queue_length 指定队列有多少顶
|
||
* @param item_size 指定每项的长度(字节)
|
||
* @return k_err_t 0 -- 成功, -1 -- 堆内存不足
|
||
*/
|
||
k_err_t k_queue_create(k_queue_t *queue_handle, size_t queue_length, size_t item_size)
|
||
{
|
||
size_t real_item_size;
|
||
k_queue_handle_t *queue;
|
||
|
||
_ASSERT_FALSE(s_kit_init_struct.malloc == NULL, "Never use 'k_init()' to initialize");
|
||
|
||
real_item_size = (size_t) & ((k_queue_data_t *)0)[1] + (item_size + sizeof(size_t) - 1) / sizeof(size_t) * sizeof(size_t);
|
||
|
||
_K_DIS_SCHED();
|
||
queue = _K_PORT->malloc(sizeof(k_queue_handle_t) + real_item_size * queue_length);
|
||
if (queue != NULL)
|
||
{
|
||
size_t i;
|
||
queue_handle->hdl = queue;
|
||
queue->item_size = item_size;
|
||
queue->resume_work = NULL;
|
||
queue->resume_delay = 0;
|
||
_slist_init_list(&queue->list_valid);
|
||
_slist_init_list(&queue->list_idle);
|
||
for (i = 0; i < queue_length; i++)
|
||
{
|
||
k_queue_data_t *queue_data = (k_queue_data_t *)&((uint8_t *)&queue[1])[real_item_size * i];
|
||
queue_data->queue_handle = queue_handle;
|
||
_slist_init_node(&queue_data->ctrl.state_node);
|
||
_slist_insert_tail(&queue->list_idle, &queue_data->ctrl.state_node);
|
||
}
|
||
}
|
||
_K_EN_SCHED();
|
||
|
||
if (queue == NULL)
|
||
{
|
||
_DBG_WRN("Insufficient memory");
|
||
return -1;
|
||
}
|
||
else
|
||
{
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 删除一个QUEUE的对象
|
||
* 1. 在该队列中所有数据被立即删除
|
||
* 2. QUEUE对象被删除
|
||
* 3. QUEUE对象及数据的堆内存被自动回收
|
||
*
|
||
* @param queue_handle 由 k_queue_create() 初始化
|
||
*/
|
||
void k_queue_delete(k_queue_t *queue_handle)
|
||
{
|
||
k_queue_handle_t *queue;
|
||
|
||
_TEST_HANDLE(queue_handle, return);
|
||
|
||
_K_DIS_SCHED();
|
||
queue = queue_handle->hdl;
|
||
if (queue != NULL)
|
||
{
|
||
_K_PORT->free(queue);
|
||
queue_handle->hdl = NULL;
|
||
}
|
||
_K_EN_SCHED();
|
||
}
|
||
|
||
/**
|
||
* @brief 清除QUEUE内的所有数据
|
||
*
|
||
* @param queue_handle 由 k_queue_create() 初始化
|
||
*/
|
||
void k_queue_clr(k_queue_t *queue_handle)
|
||
{
|
||
k_queue_handle_t *queue;
|
||
__slist_node_t *node;
|
||
|
||
_ASSERT_FALSE(s_kit_init_struct.malloc == NULL, "Never use 'k_init()' to initialize");
|
||
_TEST_HANDLE(queue_handle, return);
|
||
|
||
queue = queue_handle->hdl;
|
||
if (queue != NULL)
|
||
{
|
||
for (;;)
|
||
{
|
||
_K_DIS_INT();
|
||
node = _slist_take_head(&queue->list_valid);
|
||
if (node == NULL)
|
||
{
|
||
_K_EN_INT();
|
||
break;
|
||
}
|
||
else
|
||
{
|
||
_slist_insert_font(&queue->list_idle, node);
|
||
_K_EN_INT();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 获取 QUEUE 对象是否有效
|
||
*
|
||
* @param queue_handle 由 k_queue_create() 初始化
|
||
* @retval true
|
||
* @retval false
|
||
*/
|
||
bool k_queue_is_valid(k_queue_t *queue_handle)
|
||
{
|
||
if (s_kit_init_struct.malloc == NULL || queue_handle == NULL || queue_handle->hdl == NULL)
|
||
{
|
||
return _FALSE;
|
||
}
|
||
else
|
||
{
|
||
return _TRUE;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 注册任务,当队列非空时,任务被唤醒。
|
||
* 注意同时只能注册一个任务
|
||
*
|
||
* @param queue_handle 由 k_queue_create() 初始化
|
||
* @param work_handle 由 k_work_create() 初始化
|
||
* @param delay_ticks 延迟唤醒时间
|
||
*/
|
||
void k_queue_regist(k_queue_t *queue_handle, k_work_t *work_handle, k_tick_t delay_ticks)
|
||
{
|
||
k_queue_handle_t *queue;
|
||
|
||
_TEST_HANDLE(queue_handle, return);
|
||
|
||
queue = queue_handle->hdl;
|
||
queue->resume_work = work_handle;
|
||
queue->resume_delay = delay_ticks;
|
||
}
|
||
|
||
/**
|
||
* @brief 取消注册任务
|
||
*
|
||
* @param queue_handle 由 k_queue_create() 初始化
|
||
*/
|
||
void k_queue_unregist(k_queue_t *queue_handle)
|
||
{
|
||
k_queue_handle_t *queue;
|
||
|
||
_TEST_HANDLE(queue_handle, return);
|
||
|
||
queue = queue_handle->hdl;
|
||
queue->resume_work = NULL;
|
||
}
|
||
|
||
/**
|
||
* @brief 接收并复制数据
|
||
* 等价于 k_queue_take() + memcpy() + k_queue_free()
|
||
*
|
||
* @param queue_handle 由 k_queue_create() 初始化
|
||
* @param dst 保存接收到的数据
|
||
* @return k_err_t 0 接收成功,-1 队列中没有数据
|
||
*/
|
||
k_err_t k_queue_recv(k_queue_t *queue_handle, void *dst)
|
||
{
|
||
k_queue_handle_t *queue;
|
||
void *data = k_queue_take(queue_handle);
|
||
if (data == NULL)
|
||
{
|
||
return -1;
|
||
}
|
||
|
||
queue = queue_handle->hdl;
|
||
memcpy(dst, data, queue->item_size);
|
||
|
||
k_queue_free(data);
|
||
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* @brief 复制数据并发送
|
||
* 等价于 k_queue_alloc() + memcpy() + k_queue_put()
|
||
*
|
||
* @param queue_handle 由 k_queue_create() 初始化
|
||
* @param src 发送的数据
|
||
* @return k_err_t 0 发送成功,-1 队列已满
|
||
*/
|
||
k_err_t k_queue_send(k_queue_t *queue_handle, const void *src)
|
||
{
|
||
k_queue_handle_t *queue;
|
||
void *data = k_queue_alloc(queue_handle);
|
||
if (data == NULL)
|
||
{
|
||
return -1;
|
||
}
|
||
|
||
queue = queue_handle->hdl;
|
||
memcpy(data, src, queue->item_size);
|
||
|
||
k_queue_put(data);
|
||
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* @brief 申请可用于QUEUE的数据结构
|
||
* 管理块内存 4 bytes
|
||
*
|
||
* @param queue_handle 由 k_queue_create() 初始化
|
||
* @return void* 数据结构地址,为0时表示内存不足
|
||
*/
|
||
void *k_queue_alloc(k_queue_t *queue_handle)
|
||
{
|
||
k_queue_handle_t *queue;
|
||
__slist_node_t *node;
|
||
|
||
_ASSERT_FALSE(s_kit_init_struct.malloc == NULL, "Never use 'k_init()' to initialize");
|
||
_TEST_HANDLE(queue_handle, return NULL);
|
||
|
||
queue = queue_handle->hdl;
|
||
|
||
_K_DIS_INT();
|
||
node = _slist_take_head(&queue->list_idle);
|
||
_K_EN_INT();
|
||
|
||
if (node == NULL)
|
||
{
|
||
return NULL;
|
||
}
|
||
else
|
||
{
|
||
k_queue_data_t *queue_data = _K_CONTAINER_OF(node, k_queue_data_t, ctrl.state_node);
|
||
queue_data->ctrl.free_flag = _K_QUEUE_FREE;
|
||
return (void *)&queue_data[1];
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 释放由 k_queue_alloc() 申请的数据结构
|
||
* 注意数据不允许在QUEUE中时被释放
|
||
*
|
||
* @param data 由 k_queue_alloc() 或 k_queue_take() 获取
|
||
* @return k_err_t 0 -- 成功,-1 -- 数据未从QUEUE中弹出或数据无效
|
||
*/
|
||
k_err_t k_queue_free(void *data)
|
||
{
|
||
k_queue_data_t *queue_data;
|
||
k_queue_handle_t *queue;
|
||
|
||
_ASSERT_FALSE(s_kit_init_struct.malloc == NULL, "Never use 'k_init()' to initialize");
|
||
|
||
if (data == NULL)
|
||
{
|
||
_DBG_WRN("data invalid");
|
||
return -1;
|
||
}
|
||
|
||
queue_data = &((k_queue_data_t *)data)[-1];
|
||
|
||
if (queue_data->queue_handle == NULL || queue_data->queue_handle->hdl == NULL)
|
||
{
|
||
_DBG_WRN("queue_handle invalid");
|
||
return -1;
|
||
}
|
||
|
||
if (queue_data->ctrl.free_flag != _K_QUEUE_FREE)
|
||
{
|
||
_DBG_WRN("%p was freed", data);
|
||
return -1;
|
||
}
|
||
|
||
queue = (k_queue_handle_t *)queue_data->queue_handle->hdl;
|
||
|
||
_slist_init_node(&queue_data->ctrl.state_node);
|
||
_K_DIS_INT();
|
||
_slist_insert_font(&queue->list_idle, &queue_data->ctrl.state_node);
|
||
_K_EN_INT();
|
||
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* @brief 把数据结构压入到QUEUE中
|
||
*
|
||
* @param data 由 k_queue_alloc() 或 k_queue_take() 获取
|
||
* @return k_err_t 0 -- 成功,-1 -- QUEUE对象无效或数据结不是由 k_queue_alloc() 所创建
|
||
*/
|
||
k_err_t k_queue_put(void *data)
|
||
{
|
||
k_queue_data_t *queue_data;
|
||
k_queue_handle_t *queue;
|
||
bool resume_flag = _FALSE;
|
||
|
||
if (data == NULL)
|
||
{
|
||
_DBG_WRN("data invalid");
|
||
return -1;
|
||
}
|
||
|
||
queue_data = &((k_queue_data_t *)data)[-1];
|
||
|
||
if (queue_data->queue_handle == NULL || queue_data->queue_handle->hdl == NULL)
|
||
{
|
||
_DBG_WRN("queue_handle invalid");
|
||
return -1;
|
||
}
|
||
if (queue_data->ctrl.free_flag != _K_QUEUE_FREE)
|
||
{
|
||
_DBG_WRN("%p was freed", data);
|
||
return -1;
|
||
}
|
||
|
||
queue = (k_queue_handle_t *)queue_data->queue_handle->hdl;
|
||
|
||
_slist_init_node(&queue_data->ctrl.state_node);
|
||
_K_DIS_INT();
|
||
if (_slist_peek_head(&queue->list_valid) == NULL)
|
||
{
|
||
resume_flag = _TRUE;
|
||
}
|
||
_slist_insert_tail(&queue->list_valid, &queue_data->ctrl.state_node);
|
||
_K_EN_INT();
|
||
|
||
if (resume_flag)
|
||
{
|
||
_k_ipc_resume(queue->resume_work, queue->resume_delay);
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* @brief 从QUEUE中弹出最先压入的数据
|
||
*
|
||
* @param queue_handle 由 k_queue_create() 初始化
|
||
* @return void* 数据地址,NULL -- QUEUE队列为空
|
||
*/
|
||
void *k_queue_take(k_queue_t *queue_handle)
|
||
{
|
||
k_queue_handle_t *queue;
|
||
__slist_node_t *node;
|
||
|
||
_TEST_HANDLE(queue_handle, return NULL);
|
||
|
||
queue = queue_handle->hdl;
|
||
|
||
_K_DIS_INT();
|
||
node = _slist_take_head(&queue->list_valid);
|
||
_K_EN_INT();
|
||
|
||
if (node == NULL)
|
||
{
|
||
return NULL;
|
||
}
|
||
else
|
||
{
|
||
k_queue_data_t *queue_data = _K_CONTAINER_OF(node, k_queue_data_t, ctrl.state_node);
|
||
queue_data->ctrl.free_flag = _K_QUEUE_FREE;
|
||
return (void *)&queue_data[1];
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 查询QUEUE中头部的数据地址
|
||
*
|
||
* @param queue_handle 由 k_queue_create() 初始化
|
||
* @return void* 数据地址,NULL -- QUEUE队列为空
|
||
*/
|
||
void *k_queue_peek_head(k_queue_t *queue_handle)
|
||
{
|
||
k_queue_handle_t *queue;
|
||
__slist_node_t *node;
|
||
|
||
_TEST_HANDLE(queue_handle, return NULL);
|
||
|
||
queue = queue_handle->hdl;
|
||
node = _slist_peek_head(&queue->list_valid);
|
||
if (node == NULL)
|
||
{
|
||
return NULL;
|
||
}
|
||
else
|
||
{
|
||
k_queue_data_t *queue_data = _K_CONTAINER_OF(node, k_queue_data_t, ctrl.state_node);
|
||
return (void *)&queue_data[1];
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 查询QUEUE中尾部的数据地址
|
||
*
|
||
* @param queue_handle 由 k_queue_create() 初始化
|
||
* @return void* 数据地址,NULL -- QUEUE队列为空
|
||
*/
|
||
void *k_queue_peek_tail(k_queue_t *queue_handle)
|
||
{
|
||
k_queue_handle_t *queue;
|
||
__slist_node_t *node;
|
||
|
||
_TEST_HANDLE(queue_handle, return NULL);
|
||
|
||
queue = queue_handle->hdl;
|
||
node = _slist_peek_tail(&queue->list_valid);
|
||
if (node == NULL)
|
||
{
|
||
return NULL;
|
||
}
|
||
else
|
||
{
|
||
k_queue_data_t *queue_data = _K_CONTAINER_OF(node, k_queue_data_t, ctrl.state_node);
|
||
return (void *)&queue_data[1];
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 查询已申请数据的所属队列句柄
|
||
*
|
||
* @param data 已申请数据的数据地址
|
||
* @return k_queue_t 所属队列句柄
|
||
*/
|
||
k_queue_t *k_queue_read_handle(void *data)
|
||
{
|
||
k_queue_data_t *queue_data;
|
||
|
||
if (data == NULL)
|
||
{
|
||
_DBG_WRN("data invalid");
|
||
return NULL;
|
||
}
|
||
|
||
queue_data = &((k_queue_data_t *)data)[-1];
|
||
return queue_data->queue_handle;
|
||
}
|
||
|
||
/**
|
||
* @brief 读回 k_queue_create() 中设置的 item_size 的值
|
||
*
|
||
* @param queue_handle 由 k_queue_create() 初始化
|
||
* @return size_t k_queue_create() 中设置的 item_size 的值
|
||
*/
|
||
size_t k_queue_get_item_size(k_queue_t *queue_handle)
|
||
{
|
||
k_queue_handle_t *queue;
|
||
|
||
_TEST_HANDLE(queue_handle, return 0);
|
||
|
||
queue = queue_handle->hdl;
|
||
return queue->item_size;
|
||
}
|
||
|
||
/**
|
||
* @brief 创建一个管道对象
|
||
* 对象内存: 24 bytes
|
||
*
|
||
* @param pipe_handle[out] 初始化管道对象
|
||
* @param pipe_size 可保存的最大长度
|
||
* @return k_err_t 0 -- 成功, -1 -- 堆内存不足
|
||
*/
|
||
k_err_t k_pipe_create(k_pipe_t *pipe_handle, size_t pipe_size)
|
||
{
|
||
k_pipe_handle_t *pipe;
|
||
|
||
_ASSERT_FALSE(s_kit_init_struct.malloc == NULL, "Never use 'k_init()' to initialize");
|
||
|
||
pipe_size++;
|
||
|
||
_K_DIS_SCHED();
|
||
pipe = _K_PORT->malloc(sizeof(k_pipe_handle_t) + pipe_size);
|
||
if (pipe != NULL)
|
||
{
|
||
pipe_handle->hdl = pipe;
|
||
pipe->size = pipe_size;
|
||
pipe->resume_work = NULL;
|
||
pipe->resume_delay = 0;
|
||
}
|
||
_K_EN_SCHED();
|
||
|
||
if (pipe == NULL)
|
||
{
|
||
_DBG_WRN("Insufficient memory");
|
||
return -1;
|
||
}
|
||
else
|
||
{
|
||
k_pipe_clr(pipe_handle);
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 删除一个管道对象
|
||
*
|
||
* @param pipe_handle 由 k_pipe_create() 初始化
|
||
*/
|
||
void k_pipe_delete(k_pipe_t *pipe_handle)
|
||
{
|
||
_ASSERT_FALSE(s_kit_init_struct.malloc == NULL, "Never use 'k_init()' to initialize");
|
||
_TEST_HANDLE(pipe_handle, return);
|
||
|
||
_K_DIS_SCHED();
|
||
_K_PORT->free(pipe_handle->hdl);
|
||
pipe_handle->hdl = NULL;
|
||
_K_EN_SCHED();
|
||
}
|
||
|
||
/**
|
||
* @brief 清空管道的数据
|
||
*
|
||
* @param pipe_handle 由 k_pipe_create() 初始化
|
||
*/
|
||
void k_pipe_clr(k_pipe_t *pipe_handle)
|
||
{
|
||
k_pipe_handle_t *pipe;
|
||
|
||
_TEST_HANDLE(pipe_handle, return);
|
||
|
||
pipe = (k_pipe_handle_t *)pipe_handle->hdl;
|
||
|
||
_K_DIS_SCHED();
|
||
pipe->wid = 0;
|
||
pipe->rid = 0;
|
||
_K_EN_SCHED();
|
||
}
|
||
|
||
/**
|
||
* @brief 获取 PIPE 对象是否有效
|
||
*
|
||
* @param pipe_handle 由 k_pipe_create() 初始化
|
||
* @retval true
|
||
* @retval false
|
||
*/
|
||
bool k_pipe_is_valid(k_pipe_t *pipe_handle)
|
||
{
|
||
if (s_kit_init_struct.malloc == NULL || pipe_handle == NULL || pipe_handle->hdl == NULL)
|
||
{
|
||
return _FALSE;
|
||
}
|
||
else
|
||
{
|
||
return _TRUE;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 注册任务,当队列非空时,任务被唤醒。
|
||
* 注意同时只能注册一个任务
|
||
*
|
||
* @param pipe_handle 由 k_pipe_create() 初始化
|
||
* @param work_handle 由 k_work_create() 初始化
|
||
* @param delay_ticks 延迟唤醒时间
|
||
*/
|
||
void k_pipe_regist(k_pipe_t *pipe_handle, k_work_t *work_handle, k_tick_t delay_ticks)
|
||
{
|
||
k_pipe_handle_t *pipe;
|
||
|
||
_TEST_HANDLE(pipe_handle, return);
|
||
|
||
pipe = pipe_handle->hdl;
|
||
pipe->resume_work = work_handle;
|
||
pipe->resume_delay = delay_ticks;
|
||
}
|
||
|
||
/**
|
||
* @brief 取消注册任务
|
||
*
|
||
* @param pipe_handle 由 k_pipe_create() 初始化
|
||
*/
|
||
void k_pipe_unregist(k_pipe_t *pipe_handle)
|
||
{
|
||
k_pipe_handle_t *pipe = pipe_handle->hdl;
|
||
pipe->resume_work = NULL;
|
||
}
|
||
|
||
/**
|
||
* @brief 写一个字节到缓存中(写入缓存)
|
||
*
|
||
* @param pipe_handle 由 k_pipe_create() 初始化
|
||
* @param data 值(字节)
|
||
* @return size_t 返回实际复制成功的字节数
|
||
*/
|
||
size_t k_pipe_poll_write(k_pipe_t *pipe_handle, uint8_t data)
|
||
{
|
||
k_pipe_handle_t *pipe;
|
||
pipe_id_t wid;
|
||
bool resume_flag;
|
||
|
||
_TEST_HANDLE(pipe_handle, return 0);
|
||
|
||
pipe = (k_pipe_handle_t *)pipe_handle->hdl;
|
||
wid = pipe->wid;
|
||
if (++wid >= pipe->size)
|
||
{
|
||
wid = 0;
|
||
}
|
||
|
||
if (wid != pipe->rid)
|
||
{
|
||
((uint8_t *)&pipe[1])[pipe->wid] = data;
|
||
|
||
_K_DIS_INT();
|
||
resume_flag = (pipe->wid == pipe->rid);
|
||
pipe->wid = wid;
|
||
_K_EN_INT();
|
||
|
||
if (resume_flag)
|
||
{
|
||
_k_ipc_resume(pipe->resume_work, pipe->resume_delay);
|
||
}
|
||
|
||
return 1;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* @brief 把内存数据复制到缓存中
|
||
*
|
||
* @param pipe_handle 由 k_pipe_create() 初始化
|
||
* @param data 来源数据。如果值为 NULL 时,仅执行填充
|
||
* @param size 来源数据大小(字节)
|
||
* @return size_t 返回实际复制成功的字节数
|
||
*/
|
||
size_t k_pipe_fifo_fill(k_pipe_t *pipe_handle, const void *data, size_t size)
|
||
{
|
||
size_t ret = 0;
|
||
k_pipe_handle_t *pipe;
|
||
pipe_id_t wid;
|
||
bool resume_flag;
|
||
|
||
_TEST_HANDLE(pipe_handle, return 0);
|
||
|
||
pipe = (k_pipe_handle_t *)pipe_handle->hdl;
|
||
wid = pipe->wid;
|
||
resume_flag = (wid == pipe->rid);
|
||
|
||
while (size)
|
||
{
|
||
pipe_id_t rid = *(volatile pipe_id_t *)&pipe->rid;
|
||
pipe_id_t min;
|
||
pipe_id_t remain;
|
||
|
||
if (wid >= rid)
|
||
{
|
||
remain = pipe->size - wid - (rid == 0);
|
||
}
|
||
else
|
||
{
|
||
remain = rid - wid - 1;
|
||
}
|
||
if (remain == 0)
|
||
{
|
||
break;
|
||
}
|
||
min = size < remain ? size : remain;
|
||
|
||
if (data)
|
||
{
|
||
memcpy(&((uint8_t *)&pipe[1])[wid], &((uint8_t *)data)[ret], min);
|
||
}
|
||
|
||
if ((wid += min) >= pipe->size)
|
||
{
|
||
wid = 0;
|
||
}
|
||
|
||
size -= min;
|
||
ret += min;
|
||
}
|
||
_K_DIS_INT();
|
||
resume_flag = (pipe->wid == pipe->rid);
|
||
pipe->wid = wid;
|
||
_K_EN_INT();
|
||
|
||
if (resume_flag && ret)
|
||
{
|
||
_k_ipc_resume(pipe->resume_work, pipe->resume_delay);
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
|
||
/**
|
||
* @brief 从缓存复制一个字节到指定地址中
|
||
*
|
||
* @param pipe_handle 由 k_pipe_create() 初始化
|
||
* @param data 目标内存地址
|
||
* @return size_t 返回 0 表示缓存空
|
||
*/
|
||
size_t k_pipe_poll_read(k_pipe_t *pipe_handle, uint8_t *data)
|
||
{
|
||
k_pipe_handle_t *pipe;
|
||
pipe_id_t rid;
|
||
|
||
_TEST_HANDLE(pipe_handle, return 0);
|
||
|
||
pipe = (k_pipe_handle_t *)pipe_handle->hdl;
|
||
rid = pipe->rid;
|
||
if (rid != pipe->wid)
|
||
{
|
||
data[0] = ((uint8_t *)&pipe[1])[rid++];
|
||
if (rid < pipe->size)
|
||
{
|
||
pipe->rid = rid;
|
||
}
|
||
else
|
||
{
|
||
pipe->rid = 0;
|
||
}
|
||
return 1;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* @brief 从管道中复制数据到内存(从缓存读取)。注:参数 data 值可以为 NULL,此时不复制数据,只释放相应的数据量
|
||
*
|
||
* @param pipe_handle 由 k_pipe_create() 初始化
|
||
* @param data 目标内存地址。如果值为 NULL 时,仅执行释放
|
||
* @param size 目标内存大小(字节)
|
||
* @return size_t 返回实际复制成功的字节数
|
||
*/
|
||
size_t k_pipe_fifo_read(k_pipe_t *pipe_handle, void *data, size_t size)
|
||
{
|
||
size_t ret = 0;
|
||
k_pipe_handle_t *pipe;
|
||
pipe_id_t rid;
|
||
|
||
_TEST_HANDLE(pipe_handle, return 0);
|
||
|
||
pipe = (k_pipe_handle_t *)pipe_handle->hdl;
|
||
rid = pipe->rid;
|
||
while (size)
|
||
{
|
||
pipe_id_t wid = *(volatile pipe_id_t *)&pipe->wid;
|
||
pipe_id_t min;
|
||
pipe_id_t remain;
|
||
|
||
if (rid > wid)
|
||
{
|
||
remain = pipe->size - rid;
|
||
}
|
||
else
|
||
{
|
||
remain = wid - rid;
|
||
}
|
||
if (remain == 0)
|
||
{
|
||
break;
|
||
}
|
||
min = size < remain ? size : remain;
|
||
|
||
if (data)
|
||
{
|
||
memcpy(&((uint8_t *)data)[ret], &((uint8_t *)&pipe[1])[rid], min);
|
||
}
|
||
|
||
if ((rid += min) >= pipe->size)
|
||
{
|
||
rid = 0;
|
||
}
|
||
|
||
size -= min;
|
||
ret += min;
|
||
}
|
||
pipe->rid = rid;
|
||
|
||
return ret;
|
||
}
|
||
|
||
/**
|
||
* @brief 获取管道非空
|
||
*
|
||
* @param pipe_handle 由 k_pipe_create() 初始化
|
||
* @retval true 有数据
|
||
* @retval false 表示空
|
||
*/
|
||
bool k_pipe_is_ne(k_pipe_t *pipe_handle)
|
||
{
|
||
k_pipe_handle_t *pipe;
|
||
|
||
_TEST_HANDLE(pipe_handle, return _FALSE);
|
||
|
||
pipe = (k_pipe_handle_t *)pipe_handle->hdl;
|
||
if (pipe->rid == pipe->wid)
|
||
{
|
||
return _FALSE;
|
||
}
|
||
else
|
||
{
|
||
return _TRUE;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 获取管道的数据大小(字节数)
|
||
*
|
||
* @param pipe_handle 由 k_pipe_create() 初始化
|
||
* @return size_t 数据大小(字节数)
|
||
*/
|
||
size_t k_pipe_get_valid_size(k_pipe_t *pipe_handle)
|
||
{
|
||
k_pipe_handle_t *pipe;
|
||
|
||
_TEST_HANDLE(pipe_handle, return 0);
|
||
|
||
pipe = (k_pipe_handle_t *)pipe_handle->hdl;
|
||
if (pipe->wid < pipe->rid)
|
||
{
|
||
return pipe->size + pipe->wid - pipe->rid;
|
||
}
|
||
else
|
||
{
|
||
return pipe->wid - pipe->rid;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 获取管道的剩余空间(字节数)
|
||
*
|
||
* @param pipe_handle 由 k_pipe_create() 初始化
|
||
* @return size_t 总剩余大小(字节数)
|
||
*/
|
||
size_t k_pipe_get_empty_size(k_pipe_t *pipe_handle)
|
||
{
|
||
k_pipe_handle_t *pipe;
|
||
|
||
_TEST_HANDLE(pipe_handle, return 0);
|
||
|
||
pipe = (k_pipe_handle_t *)pipe_handle->hdl;
|
||
return pipe->size - (k_pipe_get_valid_size(pipe_handle) + 1);
|
||
}
|
||
|
||
/**
|
||
* @brief 获取当前已写入的连续的内存信息。
|
||
* pipe 实际是一环形缓存结构,获取的 dst_size 是指在缓存中的连续的长度,因此并不一定等于总长度。
|
||
* 当需要读取已缓存数据时,取得当前已缓存的数据的连续内存信息后,可对缓存的直接访问,以节省多次复制内存的资源开销,
|
||
* 配合使用 k_pipe_fifo_read(pipe_handle, NULL, size) 直接释放对应的长度。
|
||
*
|
||
* @param pipe_handle 由 k_pipe_create() 初始化
|
||
* @param dst_base[out] 已缓存数据的内存地址
|
||
* @param dst_size[out] 已缓存数据的连续长度(字节)
|
||
*/
|
||
void k_pipe_peek_valid(k_pipe_t *pipe_handle, void **dst_base, size_t *dst_size)
|
||
{
|
||
k_pipe_handle_t *pipe;
|
||
|
||
_TEST_HANDLE(pipe_handle, return);
|
||
|
||
pipe = (k_pipe_handle_t *)pipe_handle->hdl;
|
||
if (dst_base)
|
||
{
|
||
*dst_base = (&((uint8_t *)&pipe[1])[pipe->rid]);
|
||
}
|
||
if (dst_size)
|
||
{
|
||
pipe_id_t rid = pipe->rid;
|
||
pipe_id_t wid = pipe->wid;
|
||
if (rid > wid)
|
||
{
|
||
*dst_size = pipe->size - rid;
|
||
}
|
||
else
|
||
{
|
||
*dst_size = wid - rid;
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 获取当前空闲的连续的内存信息。
|
||
* pipe 实际是一环形缓存结构,获取的 dst_size 是指在缓存中的连续的长度,因此并不一定等于总长度。
|
||
* 当需要写入缓存数据时,此函数用于取得当前空闲的连续内存信息后,可对缓存的直接访问,以节省多次复制内存的资源开销,
|
||
* 配合使用 k_pipe_fifo_fill(pipe_handle, NULL, size) 直接填充对应的长度。
|
||
*
|
||
* @param pipe_handle 由 k_pipe_create() 初始化
|
||
* @param dst_base[out] 当前空闲的内存地址
|
||
* @param dst_size[out] 当前空闲的连续长度(字节)
|
||
*/
|
||
void k_pipe_peek_empty(k_pipe_t *pipe_handle, void **dst_base, size_t *dst_size)
|
||
{
|
||
k_pipe_handle_t *pipe;
|
||
|
||
_TEST_HANDLE(pipe_handle, return);
|
||
|
||
pipe = (k_pipe_handle_t *)pipe_handle->hdl;
|
||
if (dst_base)
|
||
{
|
||
*dst_base = (&((uint8_t *)&pipe[1])[pipe->wid]);
|
||
}
|
||
if (dst_size)
|
||
{
|
||
pipe_id_t rid = pipe->rid;
|
||
pipe_id_t wid = pipe->wid;
|
||
if (wid >= rid)
|
||
{
|
||
*dst_size = pipe->size - wid - (rid == 0);
|
||
}
|
||
else
|
||
{
|
||
*dst_size = rid - wid - 1;
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 获取当前系统时间
|
||
*
|
||
* @return k_tick_t 当前系统时间
|
||
*/
|
||
k_tick_t k_get_sys_ticks(void)
|
||
{
|
||
return _K_PORT->get_sys_ticks();
|
||
}
|
||
|
||
/**
|
||
* @brief 禁止中断
|
||
*
|
||
*/
|
||
void k_disable_interrupt(void)
|
||
{
|
||
_K_DIS_INT();
|
||
}
|
||
|
||
/**
|
||
* @brief 恢复中断
|
||
*
|
||
*/
|
||
void k_enable_interrupt(void)
|
||
{
|
||
_K_EN_INT();
|
||
}
|
||
|
||
/**
|
||
* @brief 打印当前调度日志。
|
||
* 在调度的过程中会实时记录调度和嵌套顺序,
|
||
* 通过本函数打印出具日志。
|
||
* 需要配置 CONFIG_K_KIT_LOG_ON 为非 0 时生效
|
||
* 注意若当前执行的任务未发生变化时不会打印
|
||
*/
|
||
void k_log_sched(void)
|
||
{
|
||
#if (CONFIG_K_KIT_LOG_ON)
|
||
#define _WORK_NAME(WORK) ((k_work_handle_t *)WORK->hdl)->name
|
||
k_work_t *work = s_cm_kit.curr_hook;
|
||
size_t flag;
|
||
|
||
if (s_cm_kit.curr_log == work)
|
||
{
|
||
return;
|
||
}
|
||
else
|
||
{
|
||
s_cm_kit.curr_log = work;
|
||
}
|
||
|
||
_K_DIS_SCHED();
|
||
|
||
CONFIG_K_KIT_PRINT("\r\n");
|
||
|
||
do
|
||
{
|
||
size_t index;
|
||
const char *arg;
|
||
size_t max_index;
|
||
|
||
flag = 0;
|
||
|
||
max_index = sizeof(s_cm_kit.work_log) / sizeof(s_cm_kit.work_log[0]);
|
||
if (max_index > s_cm_kit.log_index)
|
||
{
|
||
max_index = s_cm_kit.log_index;
|
||
}
|
||
|
||
CONFIG_K_KIT_PRINT("[work_q]");
|
||
|
||
for (index = 0; index < max_index; index++)
|
||
{
|
||
if (s_cm_kit.work_log[index] == work)
|
||
{
|
||
index++;
|
||
break;
|
||
}
|
||
arg = _WORK_NAME(s_cm_kit.work_log[index]);
|
||
if (arg == NULL)
|
||
arg = "Unknow";
|
||
CONFIG_K_KIT_PRINT(" ==> '" _COLOR_C "%s" _COLOR_END "'", arg);
|
||
}
|
||
|
||
arg = _WORK_NAME(work);
|
||
if (arg == NULL)
|
||
arg = "Unknow";
|
||
if (index < s_cm_kit.log_max)
|
||
{
|
||
if (s_cm_kit.log_index > sizeof(s_cm_kit.work_log) / sizeof(s_cm_kit.work_log[0]))
|
||
{
|
||
CONFIG_K_KIT_PRINT(" ==> ... ==> '" _COLOR_C "%s" _COLOR_END "' >>>\r\n", arg);
|
||
}
|
||
else
|
||
{
|
||
size_t i;
|
||
|
||
CONFIG_K_KIT_PRINT(" ==> '" _COLOR_C "%s" _COLOR_END "'", arg);
|
||
|
||
max_index = sizeof(s_cm_kit.work_log) / sizeof(s_cm_kit.work_log[0]);
|
||
if (max_index > s_cm_kit.log_max)
|
||
{
|
||
max_index = s_cm_kit.log_max;
|
||
}
|
||
for (i = index; i < max_index; i++)
|
||
{
|
||
arg = _WORK_NAME(s_cm_kit.work_log[i]);
|
||
if (arg == NULL)
|
||
arg = "Unknow";
|
||
CONFIG_K_KIT_PRINT(" <<< '" _COLOR_C "%s" _COLOR_END "'", arg);
|
||
s_cm_kit.work_log[i] = NULL;
|
||
}
|
||
|
||
if (s_cm_kit.log_max > sizeof(s_cm_kit.work_log) / sizeof(s_cm_kit.work_log[0]))
|
||
{
|
||
CONFIG_K_KIT_PRINT(" <<< ...");
|
||
}
|
||
|
||
CONFIG_K_KIT_PRINT("\r\n");
|
||
|
||
s_cm_kit.log_max = index;
|
||
flag = 1;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
CONFIG_K_KIT_PRINT(" ==> '" _COLOR_C "%s" _COLOR_END "' >>>\r\n", arg);
|
||
}
|
||
|
||
} while (flag);
|
||
|
||
_K_EN_SCHED();
|
||
#undef _WORK_NAME
|
||
#endif
|
||
}
|