Files
ESPC3-wireless/components/system/source/k_kit/k_kit.c

4473 lines
119 KiB
C
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* @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_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 .. 70 为最低
* @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_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;
_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);
}
}
}
}
/**
* @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 .. 70 为最低
* @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
}