From 937429b83f85961483e4c6ef5f3e5abbf25fae34 Mon Sep 17 00:00:00 2001 From: N1netyNine99 <2570955716@qq.com> Date: Sat, 4 Apr 2026 18:36:36 +0800 Subject: [PATCH 1/5] =?UTF-8?q?[add]=20=E6=B7=BB=E5=8A=A0=E4=BA=86=20ek=5F?= =?UTF-8?q?list=5Finsert=5Fafter=20=E5=92=8C=20ek=5Flist=5Finsert=5Fbefore?= =?UTF-8?q?=20=E5=87=BD=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- L2_Core/utils/inc/ek_list.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/L2_Core/utils/inc/ek_list.h b/L2_Core/utils/inc/ek_list.h index 5f164fb..eac284d 100644 --- a/L2_Core/utils/inc/ek_list.h +++ b/L2_Core/utils/inc/ek_list.h @@ -113,6 +113,26 @@ __EK_STATIC_INLINE void ek_list_insert_tail(ek_list_node_t *head, ek_list_node_t _ek_list_insert(new_node, head->prev, head); } +/** + * @brief 在指定节点前面插入新节点 + * @param next 指定节点指针(新节点将插入到此节点前面) + * @param new_node 要插入的新节点 + */ +__EK_STATIC_INLINE void ek_list_insert_before(ek_list_node_t *next, ek_list_node_t *new_node) +{ + _ek_list_insert(new_node, next->prev, next); +} + +/** + * @brief 在指定节点后面插入新节点 + * @param prev 指定节点指针(新节点将插入到此节点后面) + * @param new_node 要插入的新节点 + */ +__EK_STATIC_INLINE void ek_list_insert_after(ek_list_node_t *prev, ek_list_node_t *new_node) +{ + _ek_list_insert(new_node, prev, prev->next); +} + /** * @brief 内部函数:断开两个节点之间的连接 * @param prev 前一个节点 From 811e961bc3c4c04dd1634b5e2a4484e6416e6f88 Mon Sep 17 00:00:00 2001 From: N1netyNine99 <2570955716@qq.com> Date: Sun, 5 Apr 2026 14:19:56 +0800 Subject: [PATCH 2/5] =?UTF-8?q?[feat]=20=E6=B7=BB=E5=8A=A0=E4=BA=86=20ek?= =?UTF-8?q?=5Fevoke=20=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- L2_Core/utils/inc/ek_evoke.h | 285 +++++++++++++++++++++++ L2_Core/utils/src/ek_evoke.c | 430 +++++++++++++++++++++++++++++++++++ 2 files changed, 715 insertions(+) create mode 100644 L2_Core/utils/inc/ek_evoke.h create mode 100644 L2_Core/utils/src/ek_evoke.c diff --git a/L2_Core/utils/inc/ek_evoke.h b/L2_Core/utils/inc/ek_evoke.h new file mode 100644 index 0000000..79d2d63 --- /dev/null +++ b/L2_Core/utils/inc/ek_evoke.h @@ -0,0 +1,285 @@ +/** + * @file ek_evoke.h + * @brief 协作式事件驱动任务调度器 + * @author N1netyNine99 + * + * 提供轻量级的事件驱动机制,用于非 RTOS 环境下的任务调度和事件处理 + * 支持任务等待事件、延迟发布、ISR 请求队列等功能 + * + * @note 仅在 EK_USE_RTOS == 0 时可用 + * @note 需要用户实现睡眠和定时器回调的弱函数 + */ + +#ifndef EK_EVOKE_H +#define EK_EVOKE_H + +#include "ek_conf.h" + +#if EK_USE_RTOS == 0 + +# include "ek_def.h" +# include "ek_list.h" + +/** + * @brief ISR 请求队列最大容量 + */ +# ifndef EK_EVOKE_MAX_ISR_REQ +# define EK_EVOKE_MAX_ISR_REQ (10) +# endif /* EK_EVOKE_MAX_ISR_REQ */ + +/** + * @brief 延迟请求池最大容量 + */ +# ifndef EK_EVOKE_MAX_DEFER_REQ +# define EK_EVOKE_MAX_DEFER_REQ (10) +# endif /* EK_EVOKE_MAX_DEFER_REQ */ + +/** + * @brief 任务结构体(前置声明) + */ +typedef struct ek_evoke_task_t ek_evoke_task_t; + +/** + * @brief 事件结构体(前置声明) + */ +typedef struct ek_evoke_event_t ek_evoke_event_t; + +/** + * @brief 任务句柄类型 + */ +typedef ek_evoke_task_t *ek_evoke_task_handle_t; + +/** + * @brief 事件句柄类型 + */ +typedef ek_evoke_event_t *ek_evoke_event_handle_t; + +/** + * @brief 任务回调函数类型 + * @param evt 触发的事件 + * @param arg 用户传入的参数 + */ +typedef void (*ek_evoke_cb_t)(ek_evoke_event_t *, void *); + +/** + * @brief 任务状态枚举 + */ +typedef enum +{ + EK_EVOKE_STATE_IDLE = 0, /**< 空闲状态 */ + EK_EVOKE_STATE_DELAY, /**< 延迟状态 */ + EK_EVOKE_STATE_WAITTING, /**< 等待状态 */ + EK_EVOKE_STATE_READY, /**< 就绪状态 */ + EK_EVOKE_STATE_RUNNING, /**< 运行状态 */ + + EK_EVOKE_STATE_MAX, /**< 状态最大值 */ +} ek_evoke_state_t; + +/** + * @brief 任务结构体 + */ +struct ek_evoke_task_t +{ + ek_evoke_state_t state; /**< 任务状态 */ + ek_list_node_t node; /**< 链表节点 */ + const char *name; /**< 任务名称 */ + ek_evoke_event_t *wait_event; /**< 等待的事件 */ + void *arg; /**< 用户参数 */ + ek_evoke_cb_t cb; /**< 回调函数 */ +}; + +/** + * @brief 事件结构体 + */ +struct ek_evoke_event_t +{ + ek_list_node_t wait_list; /**< 等待该事件的任务链表 */ + const char *name; /**< 事件名称 */ + uint32_t count; /**< 事件计数(用于信号量机制) */ + void *data; /**< 事件携带的数据 */ +}; + +/* ========== 初始化 ========== */ + +/** + * @brief 初始化事件调度器 + * + * @note 使用前必须调用此函数进行初始化 + */ +void ek_evoke_init(void); + +/* ========== 任务/事件 创建/销毁 ========== */ + +/** + * @brief 创建任务 + * @param name 任务名称 + * @param cb 任务回调函数 + * @param arg 用户参数 + * @return 任务句柄 + */ +ek_evoke_task_handle_t ek_evoke_task_create(const char *name, ek_evoke_cb_t cb, void *arg); + +/** + * @brief 销毁任务 + * @param tsk 任务句柄 + */ +void ek_evoke_task_destroy(ek_evoke_task_handle_t tsk); + +/** + * @brief 创建事件 + * @param name 事件名称 + * @param init 初始计数值 + * @return 事件句柄 + */ +ek_evoke_event_handle_t ek_evoke_event_create(const char *name, uint32_t init); + +/** + * @brief 销毁事件 + * @param evt 事件句柄 + * + * @warning 销毁事件时会将所有等待该事件的任务状态设为 IDLE + */ +void ek_evoke_event_destroy(ek_evoke_event_handle_t evt); + +/* ========== 事件订阅/分发 ========== */ + +/** + * @brief 任务订阅事件 + * @param tsk 任务句柄 + * @param evt 事件句柄 + * @return true 任务立即就绪(事件已有计数) + * @return false 任务进入等待状态 + */ +bool ek_evoke_event_subscribe(ek_evoke_task_handle_t tsk, ek_evoke_event_handle_t evt); + +/** + * @brief 广播事件(唤醒所有等待任务) + * @param evt 事件句柄 + * @param payload 事件携带的数据 + * + * @note 如果没有任务等待,则增加事件计数 + */ +void ek_evoke_event_broadcast(ek_evoke_event_handle_t evt, void *payload); + +/** + * @brief 发布事件(唤醒单个等待任务) + * @param evt 事件句柄 + * @param payload 事件携带的数据 + * + * @note 如果没有任务等待,则增加事件计数 + */ +void ek_evoke_event_publish(ek_evoke_event_handle_t evt, void *payload); + +/** + * @brief 延迟发布事件 + * @param evt 事件句柄 + * @param payload 事件携带的数据 + * @param delay 延迟时间(tick) + * @param broadcast true 广播模式,false 发布模式 + */ +void ek_evoke_event_defer(ek_evoke_event_handle_t evt, void *payload, uint32_t delay, bool broadcast); + +/** + * @brief ISR 中广播事件 + * @param evt 事件句柄 + * @param payload 事件携带的数据 + * + * @note 请求会被放入 ISR 请求队列,在主循环中处理 + */ +void ek_evoke_event_broadcast_from_isr(ek_evoke_event_handle_t evt, void *payload); + +/** + * @brief ISR 中发布事件 + * @param evt 事件句柄 + * @param payload 事件携带的数据 + * + * @note 请求会被放入 ISR 请求队列,在主循环中处理 + */ +void ek_evoke_event_publish_from_isr(ek_evoke_event_handle_t evt, void *payload); + +/** + * @brief ISR 中延迟发布事件 + * @param evt 事件句柄 + * @param payload 事件携带的数据 + * @param delay 延迟时间(tick) + * @param broadcast true 广播模式,false 发布模式 + * + * @note 请求会被放入 ISR 请求队列,在主循环中处理 + */ +void ek_evoke_event_defer_from_isr(ek_evoke_event_handle_t evt, void *payload, uint32_t delay, bool broadcast); + +/* ========== 睡眠锁 ========== */ + +/** + * @brief 睡眠锁(禁止深度睡眠) + * + * @note 每次调用增加锁计数,需要与 unlock 配对使用 + */ +void ek_evoke_sleep_lock(void); + +/** + * @brief 解锁睡眠 + * + * @note 每次调用减少锁计数,锁计数为 0 时允许深度睡眠 + */ +void ek_evoke_sleep_unlock(void); + +/* ========== 事件主循环 ========== */ + +/** + * @brief 事件主循环 + * + * @note 此函数永远不会返回,应在 ek_main() 中调用 + */ +void ek_evoke_event_loop(void); + +/* ========== 回调函数 ========== */ + +/** + * @brief 延迟定时器回调函数 + * + * @note 在定时器中断中调用,用于唤醒延迟事件 + */ +void ek_evoke_delay_timer_callback(void); + +/* ========== 弱函数(用户实现) ========== */ + +/** + * @brief 进入临界区(弱函数) + * + * @note 用户需要实现此函数,通常使用关中断或互斥锁 + */ +void ek_evoke_enter_critical(void); + +/** + * @brief 退出临界区(弱函数) + * + * @note 用户需要实现此函数,通常使用开中断或释放互斥锁 + */ +void ek_evoke_exit_critical(void); + +/** + * @brief 设置定时器(弱函数) + * @param xtick 定时器触发时间(tick) + * + * @note 用户需要实现此函数,用于延迟事件的定时唤醒 + */ +void ek_evoke_set_timer(uint32_t xtick); + +/** + * @brief 浅睡眠(弱函数) + * + * @note 用户需要实现此函数,通常使用 WFI 指令 + */ +void ek_evoke_light_sleep(void); + +/** + * @brief 深度睡眠(弱函数) + * + * @note 用户需要实现此函数,通常进入低功耗模式 + */ +void ek_evoke_deep_sleep(void); + +#endif // EK_USE_RTOS + +#endif // EK_EVOKE_H diff --git a/L2_Core/utils/src/ek_evoke.c b/L2_Core/utils/src/ek_evoke.c new file mode 100644 index 0000000..d5ef83e --- /dev/null +++ b/L2_Core/utils/src/ek_evoke.c @@ -0,0 +1,430 @@ +/** + * @file ek_evoke.c + * @brief 协作式事件驱动任务调度器实现 + * @author N1netyNine99 + */ + +#include "ek_evoke.h" + +#if EK_USE_RTOS == 0 + +# include "ek_ringbuf.h" +# include "ek_mem.h" +# include "ek_export.h" +# include "ek_log.h" +# include "ek_assert.h" + +EK_LOG_FILE_TAG("ek_evoke.c"); + +# define ISR_REQ_PUBLISH (0x01) +# define ISR_REQ_PUBLISH_DEALY (0x02) +# define ISR_REQ_BROADCAST (0x04) + +typedef uint8_t _isr_req_type_t; + +typedef struct +{ + _isr_req_type_t type; + ek_evoke_event_t *evt; + void *payload; + uint32_t delay; +} _isr_req_t; + +typedef struct +{ + ek_list_node_t node; + ek_evoke_event_t *evt; + void *payload; + uint32_t wakeup_tick; + bool broadcast; +} _defer_req_t; + +static volatile uint32_t _sleep_lock; +static volatile uint32_t _event_tick_base; +static volatile uint32_t _event_tick_diff; +static volatile uint32_t _defer_earilest_tick; +static volatile bool _defer_evt_wakeup; + +static _defer_req_t _defer_req_pool[EK_EVOKE_MAX_DEFER_REQ]; +static ek_list_node_t _defer_pool_free_list; +static ek_ringbuf_spsc_t *_isr_fifo; + +static ek_list_node_t _ready_task_list; +static ek_list_node_t _defer_evt_list; + +static _defer_req_t *_defer_req_malloc(void); +static void _defer_req_free(_defer_req_t *req); + +__EK_STATIC_INLINE void _ek_evoke_set_timer(uint32_t xtick) +{ + ek_evoke_set_timer(xtick); + _event_tick_diff = xtick; +} + +void ek_evoke_sleep_lock(void) +{ + _sleep_lock++; +} + +void ek_evoke_sleep_unlock(void) +{ + if (_sleep_lock) _sleep_lock--; + else EK_LOG_WARN("the sleep lock is 0, fail to decrease the sleep lock"); +} + +void ek_evoke_delay_timer_callback(void) +{ + _defer_evt_wakeup = true; + _event_tick_base += _event_tick_diff; + _event_tick_diff = 0; +} + +void ek_evoke_init(void) +{ + ek_list_init(&_ready_task_list); + ek_list_init(&_defer_evt_list); + ek_list_init(&_defer_pool_free_list); + + for (size_t i = 0; i < EK_EVOKE_MAX_DEFER_REQ; i++) + { + ek_list_insert_tail(&_defer_pool_free_list, &_defer_req_pool[i].node); + } + + _isr_fifo = ek_ringbuf_create_spsc(sizeof(_isr_req_t), EK_EVOKE_MAX_ISR_REQ); + ek_assert_param(_isr_fifo != NULL); + + _defer_earilest_tick = UINT32_MAX; + _event_tick_base = 0; + _sleep_lock = 0; + _defer_evt_wakeup = false; +} + +EK_EXPORT_COMPONENTS(ek_evoke_init); + +ek_evoke_task_handle_t ek_evoke_task_create(const char *name, ek_evoke_cb_t cb, void *arg) +{ + ek_assert_param(cb != NULL); + + ek_evoke_task_t *tsk = ek_malloc(sizeof(*tsk)); + ek_assert_param(tsk != NULL); + + ek_list_init(&tsk->node); + tsk->name = name; + tsk->cb = cb; + tsk->arg = arg; + tsk->state = EK_EVOKE_STATE_IDLE; + tsk->wait_event = NULL; + + return tsk; +} + +void ek_evoke_task_destroy(ek_evoke_task_handle_t tsk) +{ + ek_assert_param(tsk != NULL); + if (tsk->state != EK_EVOKE_STATE_IDLE) + { + ek_list_remove(&tsk->node); + } + ek_free(tsk); +} + +ek_evoke_event_handle_t ek_evoke_event_create(const char *name, uint32_t init) +{ + ek_evoke_event_t *evt = ek_malloc(sizeof(*evt)); + ek_assert_param(evt != NULL); + + ek_list_init(&evt->wait_list); + evt->name = name; + evt->count = init; + evt->data = NULL; + + return evt; +} + +void ek_evoke_event_destroy(ek_evoke_event_handle_t evt) +{ + ek_assert_param(evt != NULL); + while (!ek_list_is_empty(&evt->wait_list)) + { + ek_list_node_t *node = ek_list_get_first(&evt->wait_list); + ek_evoke_task_t *tsk = ek_list_container(node, ek_evoke_task_t, node); + ek_list_remove(&tsk->node); + tsk->wait_event = NULL; + tsk->state = EK_EVOKE_STATE_IDLE; + } + ek_free(evt); +} + +bool ek_evoke_event_subscribe(ek_evoke_task_handle_t tsk, ek_evoke_event_handle_t evt) +{ + ek_assert_param(tsk != NULL); + ek_assert_param(evt != NULL); + + tsk->wait_event = evt; + // 等待的事件中有计数量 + // 且没有其他任务已经在等待这个事件 + // 则可以直接减少计数量并且运行任务 + if (evt->count && ek_list_is_empty(&evt->wait_list)) + { + evt->count--; + ek_list_insert_tail(&_ready_task_list, &tsk->node); + tsk->state = EK_EVOKE_STATE_READY; + + return true; + } + + // 否则说明需要等待事件发布 + ek_list_insert_tail(&evt->wait_list, &tsk->node); + tsk->state = EK_EVOKE_STATE_WAITTING; + + return false; +} + +void ek_evoke_event_broadcast(ek_evoke_event_handle_t evt, void *payload) +{ + ek_assert_param(evt != NULL); + + evt->data = payload; + // 没有任务等待这个事件 + // 增加计数值 + if (ek_list_is_empty(&evt->wait_list)) + { + evt->count++; + return; + } + + // 唤醒所有等待该事件的任务 + while (!ek_list_is_empty(&evt->wait_list)) + { + ek_list_node_t *node = ek_list_get_first(&evt->wait_list); + ek_evoke_task_t *tsk = ek_list_container(node, ek_evoke_task_t, node); + ek_list_remove(node); + ek_list_insert_tail(&_ready_task_list, node); + tsk->state = EK_EVOKE_STATE_READY; + } +} + +void ek_evoke_event_publish(ek_evoke_event_handle_t evt, void *payload) +{ + ek_assert_param(evt != NULL); + + evt->data = payload; + // 只唤醒第一个等待该事件的任务 + if (!ek_list_is_empty(&evt->wait_list)) + { + ek_list_node_t *node = ek_list_get_first(&evt->wait_list); + ek_evoke_task_t *tsk = ek_list_container(node, ek_evoke_task_t, node); + ek_list_remove(node); + ek_list_insert_tail(&_ready_task_list, node); + tsk->state = EK_EVOKE_STATE_READY; + + return; + } + + // 如果没有任务等待,就增加计数值 + evt->count++; +} + +void ek_evoke_event_defer(ek_evoke_event_handle_t evt, void *payload, uint32_t delay, bool broadcast) +{ + ek_assert_param(evt != NULL); + + if (!delay) + { + if (broadcast) return ek_evoke_event_broadcast(evt, payload); + else return ek_evoke_event_publish(evt, payload); + } + + _defer_req_t *req = _defer_req_malloc(); + if (req == NULL) + { + EK_LOG_WARN("the defer request pool is empty, fail to create a defer request"); + return; + } + uint32_t wakeup_tick = delay + _event_tick_base; + + req->evt = evt; + req->broadcast = broadcast; + req->payload = payload; + req->wakeup_tick = wakeup_tick; + + ek_list_node_t *pos; + ek_list_foreach(pos, &_defer_evt_list) + { + _defer_req_t *pos_req = ek_list_container(pos, _defer_req_t, node); + if (pos_req->wakeup_tick >= wakeup_tick) break; + } + ek_list_insert_before(pos, &req->node); +} + +void ek_evoke_event_broadcast_from_isr(ek_evoke_event_handle_t evt, void *payload) +{ + ek_assert_param(evt != NULL); + + ek_evoke_enter_critical(); + + _isr_req_t req = { + .type = ISR_REQ_BROADCAST, + .evt = evt, + .payload = payload, + }; + ek_ringbuf_write_spsc(_isr_fifo, &req); + + ek_evoke_exit_critical(); +} + +void ek_evoke_event_publish_from_isr(ek_evoke_event_handle_t evt, void *payload) +{ + ek_assert_param(evt != NULL); + + ek_evoke_enter_critical(); + + _isr_req_t req = { + .type = ISR_REQ_PUBLISH, + .evt = evt, + .payload = payload, + }; + ek_ringbuf_write_spsc(_isr_fifo, &req); + + ek_evoke_exit_critical(); +} + +void ek_evoke_event_defer_from_isr(ek_evoke_event_handle_t evt, void *payload, uint32_t delay, bool broadcast) +{ + ek_assert_param(evt != NULL); + + ek_evoke_enter_critical(); + + _isr_req_t req = { + .type = (broadcast == true) ? (ISR_REQ_PUBLISH_DEALY | ISR_REQ_BROADCAST) + : (ISR_REQ_PUBLISH_DEALY | ISR_REQ_PUBLISH), + .evt = evt, + .payload = payload, + .delay = delay, + }; + ek_ringbuf_write_spsc(_isr_fifo, &req); + + ek_evoke_exit_critical(); +} + +void ek_evoke_event_loop(void) +{ + while (1) + { + // 先处理是否有来自中断的请求 + // 从中断请求fifo中读取 + while (!ek_ringbuf_empty_spsc(_isr_fifo)) + { + _isr_req_t req = { 0 }; + if (ek_ringbuf_read_spsc(_isr_fifo, &req)) + { + if (req.type & ISR_REQ_PUBLISH) + { + if (req.type & ISR_REQ_PUBLISH_DEALY) ek_evoke_event_defer(req.evt, req.payload, req.delay, false); + else ek_evoke_event_publish(req.evt, req.payload); + } + else if (req.type & ISR_REQ_BROADCAST) + { + if (req.type & ISR_REQ_PUBLISH_DEALY) ek_evoke_event_defer(req.evt, req.payload, req.delay, true); + else ek_evoke_event_broadcast(req.evt, req.payload); + } + } + } + + // 检查延时链表 + // 如果有延时的事件,则取出最早的唤醒事件然后设置中断时间 + if (!ek_list_is_empty(&_defer_evt_list)) + { + ek_list_node_t *node = ek_list_get_first(&_defer_evt_list); + _defer_req_t *req = ek_list_container(node, _defer_req_t, node); + if (req->wakeup_tick != _defer_earilest_tick) + { + _defer_earilest_tick = req->wakeup_tick; + _ek_evoke_set_timer(_defer_earilest_tick - _event_tick_base); + } + } + + // 首先检查就绪链表是否为空 + // 如果不为空则执行所有到期任务 + // 如果为空就直接去检查延时链表 + while (!ek_list_is_empty(&_ready_task_list)) + { + ek_list_node_t *node = ek_list_get_first(&_ready_task_list); + ek_evoke_task_t *tsk = ek_list_container(node, ek_evoke_task_t, node); + ek_list_remove(&tsk->node); + tsk->state = EK_EVOKE_STATE_RUNNING; + tsk->cb(tsk->wait_event, tsk->arg); + ek_list_insert_tail(&tsk->wait_event->wait_list, &tsk->node); + tsk->state = EK_EVOKE_STATE_WAITTING; + } + + // 检查睡眠锁,根据锁的状态来执行不同的睡眠状态 + // 如果有锁没有释放,则去浅睡眠 WFI + // 如果所有的锁都释放了,则进行深度睡眠 + if (_sleep_lock) ek_evoke_light_sleep(); + else ek_evoke_deep_sleep(); + + // 中断唤醒,要去检查是否有延时事件被唤醒 + // 如果有,则依次唤醒 + // 并且要去检查是否有其他同样唤醒时间的事件 + // 如果有,一并发布 + if (_defer_evt_wakeup) + { + _defer_evt_wakeup = false; + + while (!ek_list_is_empty(&_defer_evt_list)) + { + ek_list_node_t *node = ek_list_get_first(&_defer_evt_list); + _defer_req_t *req = ek_list_container(node, _defer_req_t, node); + + if (req->wakeup_tick > _defer_earilest_tick) break; + + ek_list_remove(node); + if (req->broadcast) ek_evoke_event_broadcast(req->evt, req->payload); + else ek_evoke_event_publish(req->evt, req->payload); + _defer_req_free(req); + } + _defer_earilest_tick = UINT32_MAX; + } + } +} + +static _defer_req_t *_defer_req_malloc(void) +{ + if (!ek_list_is_empty(&_defer_pool_free_list)) + { + ek_list_node_t *node = ek_list_get_first(&_defer_pool_free_list); + ek_list_remove(node); + _defer_req_t *req = ek_list_container(node, _defer_req_t, node); + return req; + } + return NULL; +} + +static void _defer_req_free(_defer_req_t *req) +{ + ek_list_insert_tail(&_defer_pool_free_list, &req->node); +} + +__EK_WEAK void ek_evoke_enter_critical(void) +{ +} + +__EK_WEAK void ek_evoke_exit_critical(void) +{ +} + +__EK_WEAK void ek_evoke_light_sleep(void) +{ +} + +__EK_WEAK void ek_evoke_deep_sleep(void) +{ +} + +__EK_WEAK void ek_evoke_set_timer(uint32_t xtick) +{ + __EK_UNUSED(xtick); +} + +#endif // EK_USE_RTOS From baf506b7fe6315adaf620d40a21b6791d6cf20d8 Mon Sep 17 00:00:00 2001 From: N1netyNine99 <2570955716@qq.com> Date: Sun, 5 Apr 2026 14:20:15 +0800 Subject: [PATCH 3/5] =?UTF-8?q?[feat]=20=E6=B7=BB=E5=8A=A0=E4=BA=86=20spsc?= =?UTF-8?q?=20=E7=9A=84=E5=94=A4=E9=86=92=E7=BC=93=E5=86=B2=E5=8C=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- L2_Core/utils/inc/ek_ringbuf.h | 106 +++++++++++++++++++++--- L2_Core/utils/src/ek_ringbuf.c | 143 +++++++++++++++++++++++++++++---- 2 files changed, 222 insertions(+), 27 deletions(-) diff --git a/L2_Core/utils/inc/ek_ringbuf.h b/L2_Core/utils/inc/ek_ringbuf.h index ee9160e..afa398f 100644 --- a/L2_Core/utils/inc/ek_ringbuf.h +++ b/L2_Core/utils/inc/ek_ringbuf.h @@ -11,7 +11,7 @@ #include "ek_conf.h" -#if EK_RINGBUF_ENABLE == 1 +#if (EK_RINGBUF_ENABLE == 1) || (EK_RINGBUF_SPSC_ENABLE == 1) # include "ek_def.h" @@ -19,7 +19,9 @@ * @brief 环形缓冲区结构 */ typedef struct ek_ringbuf_t ek_ringbuf_t; +typedef struct ek_ringbuf_spsc_t ek_ringbuf_spsc_t; +# if EK_RINGBUF_ENABLE == 1 struct ek_ringbuf_t { uint8_t *buffer; /**< 缓冲区指针 */ @@ -28,16 +30,29 @@ struct ek_ringbuf_t uint32_t item_amount; /**< 当前元素个数 */ size_t cap; /**< 缓冲区容量(元素个数) */ size_t item_size; /**< 单个元素大小(字节) */ -# if EK_USE_RTOS == 1 +# if EK_USE_RTOS == 1 bool lock; -# endif /* EK_USE_RTOS */ +# endif /* EK_USE_RTOS */ }; +# endif /* EK_RINGBUF_ENABLE */ + +# if EK_RINGBUF_SPSC_ENABLE == 1 +struct ek_ringbuf_spsc_t +{ + uint8_t *buffer; /**< 缓冲区指针 */ + uint32_t write_idx; /**< 写入位置索引 */ + uint32_t read_idx; /**< 读取位置索引 */ + size_t cap; /**< 底层槽位数量,实际最大可存元素数为 cap - 1 */ + size_t item_size; /**< 单个元素大小(字节) */ +}; +# endif /* EK_RINGBUF_SPSC_ENABLE */ # ifdef __cplusplus extern "C" { # endif /* __cplusplus */ +# if EK_RINGBUF_ENABLE == 1 /** * @brief 判断环形缓冲区是否已满 * @param rb 环形缓冲区指针 @@ -75,12 +90,12 @@ void ek_ringbuf_destroy(ek_ringbuf_t *rb); * @param rb_ptr 要销毁的环形缓冲区 * */ -# define ek_ringbuf_destroy_safely(rb_ptr) \ - do \ - { \ - ek_ringbuf_destroy((rb_ptr)); \ - rb_ptr = NULL; \ - } while (0) +# define ek_ringbuf_destroy_safely(rb_ptr) \ + do \ + { \ + ek_ringbuf_destroy(rb_ptr); \ + rb_ptr = NULL; \ + } while (0) /** * @brief 向环形缓冲区写入一个元素 @@ -108,11 +123,82 @@ bool ek_ringbuf_read(ek_ringbuf_t *rb, void *item); * @return false 查看失败(缓冲区为空) */ bool ek_ringbuf_peek(ek_ringbuf_t *rb, void *item); +# endif /* EK_RINGBUF_ENABLE */ + +# if EK_RINGBUF_SPSC_ENABLE == 1 +/** + * @brief 判断 SPSC 环形缓冲区是否已满 + * @param rb 环形缓冲区指针 + * @return true 已满 + * @return false 未满 + */ +bool ek_ringbuf_full_spsc(const ek_ringbuf_spsc_t *rb); + +/** + * @brief 判断 SPSC 环形缓冲区是否为空 + * @param rb 环形缓冲区指针 + * @return true 为空 + * @return false 不为空 + */ +bool ek_ringbuf_empty_spsc(const ek_ringbuf_spsc_t *rb); + +/** + * @brief 创建 SPSC 环形缓冲区 + * @param item_size 单个元素大小(字节) + * @param item_amount 底层槽位数量,实际最大可存元素数为 item_amount - 1 + * @return 成功返回缓冲区指针,失败返回 NULL + */ +ek_ringbuf_spsc_t *ek_ringbuf_create_spsc(size_t item_size, uint32_t item_amount); + +/** + * @brief 销毁 SPSC 环形缓冲区 + * @param rb 要销毁的环形缓冲区 + */ +void ek_ringbuf_destroy_spsc(ek_ringbuf_spsc_t *rb); + +/** + * @brief 销毁 SPSC 环形缓冲区并把 rb_ptr 设置为 NULL + * @param rb_ptr 要销毁的环形缓冲区 + */ +# define ek_ringbuf_destroy_safely_spsc(rb_ptr) \ + do \ + { \ + ek_ringbuf_destroy_spsc(rb_ptr); \ + rb_ptr = NULL; \ + } while (0) + +/** + * @brief 向 SPSC 环形缓冲区写入一个元素 + * @param rb 环形缓冲区指针 + * @param item 要写入的元素指针 + * @return true 写入成功 + * @return false 写入失败(缓冲区已满) + */ +bool ek_ringbuf_write_spsc(ek_ringbuf_spsc_t *rb, const void *item); + +/** + * @brief 从 SPSC 环形缓冲区读取一个元素 + * @param rb 环形缓冲区指针 + * @param item 存储读取结果的缓冲区指针,传入 NULL 则直接丢弃数据 + * @return true 读取成功 + * @return false 读取失败(缓冲区为空) + */ +bool ek_ringbuf_read_spsc(ek_ringbuf_spsc_t *rb, void *item); + +/** + * @brief 查看 SPSC 环形缓冲区首个元素(不移动读指针) + * @param rb 环形缓冲区指针 + * @param item 存储查看结果的缓冲区指针 + * @return true 查看成功 + * @return false 查看失败(缓冲区为空) + */ +bool ek_ringbuf_peek_spsc(ek_ringbuf_spsc_t *rb, void *item); +# endif /* EK_RINGBUF_SPSC_ENABLE */ # ifdef __cplusplus } # endif /* __cplusplus */ -#endif /* EK_RINGBUF_ENABLE */ +#endif /* EK_RINGBUF_ENABLE || EK_RINGBUF_SPSC_ENABLE */ #endif /* EK_RINGBUF_H */ diff --git a/L2_Core/utils/src/ek_ringbuf.c b/L2_Core/utils/src/ek_ringbuf.c index eb3dbdc..26295fe 100644 --- a/L2_Core/utils/src/ek_ringbuf.c +++ b/L2_Core/utils/src/ek_ringbuf.c @@ -6,20 +6,21 @@ #include "ek_ringbuf.h" -#if EK_RINGBUF_ENABLE == 1 - -# include "../inc/ek_mem.h" -# include "../inc/ek_assert.h" - -# if EK_USE_RTOS == 1 -# define EK_LOCKUP(prb) ((prb)->lock = true) -# define EK_UNLOCK(prb) ((prb)->lock = false) -# define EK_LOCK_TEST(prb) ((prb)->lock == true) -# else -# define EK_LOCKUP(prb) -# define EK_UNLOCK(prb) -# define EK_LOCK_TEST(prb) (false) -# endif /* EK_USE_RTOS */ +#if (EK_RINGBUF_ENABLE == 1) || (EK_RINGBUF_SPSC_ENABLE == 1) + +# include "ek_mem.h" +# include "ek_assert.h" + +# if EK_RINGBUF_ENABLE == 1 +# if EK_USE_RTOS == 1 +# define EK_LOCKUP(prb) ((prb)->lock = true) +# define EK_UNLOCK(prb) ((prb)->lock = false) +# define EK_LOCK_TEST(prb) ((prb)->lock == true) +# else +# define EK_LOCKUP(prb) +# define EK_UNLOCK(prb) +# define EK_LOCK_TEST(prb) (false) +# endif /* EK_USE_RTOS */ bool ek_ringbuf_full(const ek_ringbuf_t *rb) { @@ -55,9 +56,9 @@ ek_ringbuf_t *ek_ringbuf_create(size_t item_size, uint32_t item_amount) rb->read_idx = 0; rb->write_idx = 0; rb->item_amount = 0; -# if EK_USE_RTOS == 1 +# if EK_USE_RTOS == 1 rb->lock = false; -# endif /* EK_USE_RTOS */ +# endif /* EK_USE_RTOS */ return rb; } @@ -146,5 +147,113 @@ bool ek_ringbuf_peek(ek_ringbuf_t *rb, void *item) return true; } +# endif /* EK_RINGBUF_ENABLE */ + +# if EK_RINGBUF_SPSC_ENABLE == 1 +__EK_STATIC_INLINE uint32_t _ek_ringbuf_spsc_next_idx(const ek_ringbuf_spsc_t *rb, uint32_t idx) +{ + return (idx + 1U) % rb->cap; +} + +bool ek_ringbuf_full_spsc(const ek_ringbuf_spsc_t *rb) +{ + ek_assert_param(rb != NULL); + return _ek_ringbuf_spsc_next_idx(rb, rb->write_idx) == rb->read_idx; +} + +bool ek_ringbuf_empty_spsc(const ek_ringbuf_spsc_t *rb) +{ + ek_assert_param(rb != NULL); + return rb->read_idx == rb->write_idx; +} + +ek_ringbuf_spsc_t *ek_ringbuf_create_spsc(size_t item_size, uint32_t item_amount) +{ + ek_assert_param(item_amount > 1U); + ek_assert_param(item_size != 0U); + + ek_ringbuf_spsc_t *rb = (ek_ringbuf_spsc_t *)ek_malloc(sizeof(ek_ringbuf_spsc_t)); + if (rb == NULL) + { + return NULL; + } + + rb->buffer = (uint8_t *)ek_malloc(item_amount * item_size); + if (rb->buffer == NULL) + { + ek_free(rb); + return NULL; + } + + rb->cap = item_amount; + rb->item_size = item_size; + rb->read_idx = 0U; + rb->write_idx = 0U; + + return rb; +} + +void ek_ringbuf_destroy_spsc(ek_ringbuf_spsc_t *rb) +{ + ek_assert_param(rb != NULL); + + ek_free(rb->buffer); + ek_free(rb); +} + +bool ek_ringbuf_write_spsc(ek_ringbuf_spsc_t *rb, const void *item) +{ + ek_assert_param(rb != NULL); + ek_assert_param(item != NULL); + + uint32_t next_idx = _ek_ringbuf_spsc_next_idx(rb, rb->write_idx); + if (next_idx == rb->read_idx) + { + return false; + } + + uint8_t *target = rb->buffer + (rb->write_idx * rb->item_size); + memcpy(target, item, rb->item_size); + rb->write_idx = next_idx; + + return true; +} + +bool ek_ringbuf_read_spsc(ek_ringbuf_spsc_t *rb, void *item) +{ + ek_assert_param(rb != NULL); + + if (rb->read_idx == rb->write_idx) + { + return false; + } + + if (item != NULL) + { + const uint8_t *source = rb->buffer + (rb->read_idx * rb->item_size); + memcpy(item, source, rb->item_size); + } + + rb->read_idx = _ek_ringbuf_spsc_next_idx(rb, rb->read_idx); + + return true; +} + +bool ek_ringbuf_peek_spsc(ek_ringbuf_spsc_t *rb, void *item) +{ + ek_assert_param(rb != NULL); + ek_assert_param(item != NULL); + + if (rb->read_idx == rb->write_idx) + { + return false; + } + + const uint8_t *source = rb->buffer + (rb->read_idx * rb->item_size); + memcpy(item, source, rb->item_size); + + return true; +} +# endif /* EK_RINGBUF_SPSC_ENABLE */ -#endif /* EK_RINGBUF_ENABLE */ +#endif /* EK_RINGBUF_ENABLE || EK_RINGBUF_SPSC_ENABLE */ From eedfc603ca505698b403c38ba6927986448f8608 Mon Sep 17 00:00:00 2001 From: N1netyNine99 <2570955716@qq.com> Date: Sun, 5 Apr 2026 14:20:30 +0800 Subject: [PATCH 4/5] =?UTF-8?q?[feat]=20=E6=94=AF=E6=8C=81spsc=E5=92=8Cek?= =?UTF-8?q?=5Fevoke?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ek_conf.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/ek_conf.h b/ek_conf.h index e44e1b9..4cad1b6 100644 --- a/ek_conf.h +++ b/ek_conf.h @@ -35,18 +35,18 @@ * - EK_LOG_ENABLE: 使能日志模块 * - EK_LIST_ENABLE: 使能链表模块 * - EK_VEC_ENABLE: 使能向量模块 - * - EK_RINGBUF_ENABLE: 使能环形缓冲区模块 + * - EK_RINGBUF_ENABLE: 使能通用环形缓冲区模块 + * - EK_RINGBUF_SPSC_ENABLE: 使能单生产者单消费者环形缓冲区模块 * - EK_STACK_ENABLE: 使能栈模块 - * - EK_SHELL_ENABLE: 使能shell模块 * ======================================================================== */ -#define EK_EXPORT_ENABLE (0) -#define EK_STR_ENABLE (1) -#define EK_LOG_ENABLE (1) -#define EK_LIST_ENABLE (1) -#define EK_VEC_ENABLE (1) -#define EK_RINGBUF_ENABLE (1) -#define EK_STACK_ENABLE (1) -#define EK_SHELL_ENABLE (0) +#define EK_EXPORT_ENABLE (0) +#define EK_STR_ENABLE (1) +#define EK_LOG_ENABLE (1) +#define EK_LIST_ENABLE (1) +#define EK_VEC_ENABLE (1) +#define EK_RINGBUF_ENABLE (1) +#define EK_RINGBUF_SPSC_ENABLE (1) +#define EK_STACK_ENABLE (1) /* ======================================================================== * 日志模块配置 From f7efe42d09bc4f27ede608360b51b1583bd49f25 Mon Sep 17 00:00:00 2001 From: N1netyNine99 <2570955716@qq.com> Date: Sun, 5 Apr 2026 18:50:46 +0800 Subject: [PATCH 5/5] =?UTF-8?q?[fix]=20=E4=BF=AE=E5=A4=8D=E5=9C=A8?= =?UTF-8?q?=E6=99=AE=E9=80=9A=E4=BB=BB=E5=8A=A1=E4=B8=AD=E6=97=A0=E6=B3=95?= =?UTF-8?q?=E6=AD=A3=E7=A1=AE=E8=AE=BE=E7=BD=AEdefer=E8=AF=B7=E6=B1=82?= =?UTF-8?q?=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- L2_Core/utils/src/ek_evoke.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/L2_Core/utils/src/ek_evoke.c b/L2_Core/utils/src/ek_evoke.c index d5ef83e..86861eb 100644 --- a/L2_Core/utils/src/ek_evoke.c +++ b/L2_Core/utils/src/ek_evoke.c @@ -331,19 +331,6 @@ void ek_evoke_event_loop(void) } } - // 检查延时链表 - // 如果有延时的事件,则取出最早的唤醒事件然后设置中断时间 - if (!ek_list_is_empty(&_defer_evt_list)) - { - ek_list_node_t *node = ek_list_get_first(&_defer_evt_list); - _defer_req_t *req = ek_list_container(node, _defer_req_t, node); - if (req->wakeup_tick != _defer_earilest_tick) - { - _defer_earilest_tick = req->wakeup_tick; - _ek_evoke_set_timer(_defer_earilest_tick - _event_tick_base); - } - } - // 首先检查就绪链表是否为空 // 如果不为空则执行所有到期任务 // 如果为空就直接去检查延时链表 @@ -358,6 +345,19 @@ void ek_evoke_event_loop(void) tsk->state = EK_EVOKE_STATE_WAITTING; } + // 检查延时链表 + // 如果有延时的事件,则取出最早的唤醒事件然后设置中断时间 + if (!ek_list_is_empty(&_defer_evt_list)) + { + ek_list_node_t *node = ek_list_get_first(&_defer_evt_list); + _defer_req_t *req = ek_list_container(node, _defer_req_t, node); + if (req->wakeup_tick != _defer_earilest_tick) + { + _defer_earilest_tick = req->wakeup_tick; + _ek_evoke_set_timer(_defer_earilest_tick - _event_tick_base); + } + } + // 检查睡眠锁,根据锁的状态来执行不同的睡眠状态 // 如果有锁没有释放,则去浅睡眠 WFI // 如果所有的锁都释放了,则进行深度睡眠