varch/source/08_coroutine/coroutine.h
Lamdonn c0a7f18093 Update coroutine
1. Compatibility with coroutine API highly intensive IO, sockets, etc
2. Fix running fail on arm64
3. Add low power configuration hook
TODO:
1. Add a scheduling ready task queue mechanism
2. Add CoTask communication channel
2026-10-11 00:01:44 +08:00

641 lines
30 KiB
C

/*********************************************************************************************************
* ------------------------------------------------------------------------------------------------------
* file description
* ------------------------------------------------------------------------------------------------------
* \file coroutine.h
* \unit coroutine
* \brief This is a C language coroutine library
* \author Lamdonn
* \version v0.2.0
* \license GPL-2.0
* \copyright Copyright (C) 2025 Lamdonn.
********************************************************************************************************/
#ifndef __coroutine_H
#define __coroutine_H
#ifdef __cplusplus
extern "C" {
#endif
/* Version infomation */
#define COROUTINE_V_MAJOR 0
#define COROUTINE_V_MINOR 2
#define COROUTINE_V_PATCH 0
#include "coroutine_cfg.h"
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <stdbool.h>
#include <setjmp.h>
/**
* \brief: Coroutine task
*/
typedef struct CoTask* CoTask_t;
/**
* \brief: Coroutine timer
*/
typedef struct CoTimer* CoTimer_t;
/**
* \brief: Coroutine task entry function
* \param arg: Task argument address
* \return: Task return value address
*/
typedef void *(*CoTaskEntry_t)(void *arg);
/**
* \brief: Coroutine timer entry function
*/
typedef void (*CoTimerEntry_t)(void);
/**
* \brief: Coroutine lock function
* \note: Use coroutines for multi-thread, protect the security of multi-thread shared resources, lock
*/
typedef void (*CoLock_t)(void);
/**
* \brief: Coroutine unlock function
* \note: Use coroutines for multi-thread, protect the security of multi-thread shared resources, unlock
*/
typedef void (*CoUnlock_t)(void);
/**
* \brief: Coroutine malloc function
* \param size: Allocate memory size
* \return: Allocate memory address
* \note: Use coroutines for multi-thread, protect the security of multi-thread shared resources, malloc
*/
typedef void *(*CoMalloc_t)(size_t size);
/**
* \brief: Coroutine free function
* \param block: Free memory address
* \note: Use coroutines for multi-thread, protect the security of multi-thread shared resources, free
*/
typedef void (*CoFree_t)(void *block);
/**
* \brief: Coroutine tick function
* \return: Current tick value
* \note: The time base on which the coroutine schedule depends, such as system tick.
*/
typedef uint64_t (*CoTick_t)(void);
/**
* \brief: Coroutine scheduler idle hook function pointer
* \param schedulerId: Current scheduler ID
* \param idleUs: Estimated idle duration in microseconds until the earliest task or timer wake-up (0 if unknown or none)
* \note: Can be used to execute WFI on MCU, epoll_wait on Linux, or custom sleep/reactor logic.
*/
typedef void (*CoIdleHook_t)(uint32_t schedulerId, uint32_t idleUs);
/**
* \brief: Coroutine scheduler wakeup hook function pointer
* \param schedulerId: Target scheduler ID to wake up
* \note: Used to unblock or interrupt an in-progress idleHook (e.g. pthread_cond_signal, eventfd write, SetEvent)
*/
typedef void (*CoWakeupHook_t)(uint32_t schedulerId);
/**
* \brief: Coroutine event
* \note: Used for synchronization between coroutines
*/
typedef struct
{
uint32_t flag; /**< Event flag, 32 bit storage, each bit can individually represent an event */
} CoEvent;
/**
* \brief: Coroutine global runtime environment parameters
* \note: Configures global dynamic memory allocators and thread synchronization locks
*/
typedef struct CoroutineInitPara
{
CoLock_t lock; /**< Global coroutine thread lock function */
CoUnlock_t unlock; /**< Global coroutine thread unlock function */
CoMalloc_t malloc; /**< Global dynamic memory allocator function */
CoFree_t free; /**< Global dynamic memory free function */
} CoroutineInitPara;
/**
* \brief: Coroutine scheduler initialize parameter
* \note: Coroutine scheduler initialize parameter is used to initialize the coroutine scheduler instance.
*/
typedef struct CoSchedulerInitPara
{
CoIdleHook_t idleHook; /**< Coroutine scheduler idle hook function */
CoWakeupHook_t wakeupHook; /**< Coroutine scheduler wakeup hook function */
} CoSchedulerInitPara;
/**
* \brief: Coroutine task create parameter
* \note: Coroutine task create parameter is used to create a coroutine task.
*/
typedef struct CoTaskCreatePara
{
void *pStack; /**< Coroutine task stack address */
size_t stackSize; /**< Coroutine task stack size */
void *arg; /**< Coroutine task argument */
int schedulerId; /**< Coroutine task scheduler id */
uint8_t manual; /**< 1: Manual control mode (libco style, CoScheduler will not auto-run), 0: Auto scheduled */
uint8_t sharedStack; /**< 1: Use shared stack (requires COROUTINE_SHARED_STACK_SIZE > 0), 0: Dedicated stack */
} CoTaskCreatePara;
/**
* \brief: Coroutine timer create parameter
* \note: Coroutine timer create parameter is used to create a coroutine timer.
*/
typedef struct CoTimerCreatePara
{
uint64_t ms; /**< Coroutine timer ms, indicates the ms interval */
uint64_t tick; /**< Coroutine timer tick, indicates the tick interval */
int schedulerId; /**< Coroutine timer scheduler id */
} CoTimerCreatePara;
/**
* \brief: Coroutine task wait parameter
* \note: Coroutine task wait parameter is used to blocking task waiting for event or timeout.
*/
typedef struct CoTaskWaitPara
{
CoEvent *pEvent; /**< Coroutine task wait event pointer */
uint64_t ms; /**< Coroutine task wait timeout in ms */
uint64_t tick; /**< Coroutine task wait timeout in tick */
} CoTaskWaitPara;
/**
* \brief: Coroutine task create parameter default value
* \note: Coroutine task create parameter default value is used to create a coroutine task.
*/
#define COROUTINE_E_OK (0) /**< Coroutine task create parameter default value, indicates success */
#define COROUTINE_E_INVALID_PARAMETER (-1) /**< Coroutine task create parameter default value, indicates invalid parameter */
#define COROUTINE_E_INVALID_TICK (-2) /**< Coroutine task create parameter default value, indicates invalid tick function */
#define COROUTINE_E_INVALID_TICK_INTERVAL (-3) /**< Coroutine task create parameter default value, indicates invalid tick interval */
#define COROUTINE_E_INVALID_LOCK (-4) /**< Coroutine task create parameter default value, indicates invalid lock function */
#define COROUTINE_E_INVALID_MHOOK (-5) /**< Coroutine task create parameter default value, indicates invalid memory hook function */
#define COROUTINE_E_TCB_MEM_STACK_FAIL (-6) /**< Coroutine task create parameter default value, indicates memory stack fail */
/**
* \brief: Coroutine event default value
* \note: Coroutine event default value is used to initialize the coroutine event.
*/
#define COEVENT_STATIC_VALUE ((CoEvent){.flag=0})
/**
* \brief: Coroutine global runtime environment initialize function
* \param lock: [Default parameter] Coroutine thread lock function,
* for use on multiple threads, you must specify as follows .lock=thread_lock
* \param unlock: [Default parameter] Coroutine thread unlock function,
* for use on multiple threads, you must specify as follows .unlock=thread_unlock
* \param malloc: [Default parameter] Coroutine dynamic memory allocator function,
* if you need to allocate memory dynamically (shared stack, CoTask, etc),
* you must specify as follows .malloc=malloc
* \param free: [Default parameter] Coroutine dynamic memory free function,
* if you need to free memory dynamically (shared stack, CoTask, etc),
* you must specify as follows .free=free
* \return: COROUTINE_E_OK on success, or negative error code
* \note: Configures global runtime infrastructure (memory hooks and thread locks) independently of specific schedulers.
* It is recommended to call this once at module or process startup.
* \example:
* Coroutine_Init(.malloc=malloc, .free=free);
* \example:
* Coroutine_Init(.lock=thread_lock, .unlock=thread_unlock, .malloc=malloc, .free=free);
*/
#define Coroutine_Init(...) Coroutine_InitP((CoroutineInitPara[1]){[0]={.lock=NULL,.unlock=NULL,.malloc=NULL,.free=NULL,__VA_ARGS__}})
/**
* \brief: Coroutine global runtime environment initialize function, it is recommended to use @ref `Coroutine_Init` instead
* \param pPara: Coroutine global environment parameter pointer
* \return: COROUTINE_E_OK on success, or negative error code
* \note: Configures global runtime infrastructure independently of specific scheduler instances.
*/
int Coroutine_InitP(CoroutineInitPara *pPara);
/**
* \brief: Check if global dynamic memory hooks (malloc and free) are configured
* \return: 1 if dynamic memory hooks are configured, 0 if in pure static mode
*/
int Coroutine_HasMemHook(void);
/**
* \brief: Allocate memory using the configured coroutine dynamic allocator
* \param size: Number of bytes to allocate
* \return: Pointer to allocated memory, or NULL if not configured or allocation failed
*/
void *Coroutine_Malloc(size_t size);
/**
* \brief: Free memory using the configured coroutine dynamic deallocator
* \param ptr: Pointer to memory to free
*/
void Coroutine_Free(void *ptr);
/**
* \brief: Coroutine scheduler initialize function
* \param CoSchedulerId: Coroutine scheduler ID
* \param tick: [Non-default parameter] Coroutine scheduler tick function, must be specified
* \param tickInterval: [Non-default parameter] Coroutine scheduler tick interval, indicates how many ns each tick is, must be specified
* \param idleHook: [Default parameter] Coroutine scheduler idle hook function,
* you can specify as follows .idleHook=my_idle_hook
* \return: Coroutine task create parameter default value, indicates success
* \note: Coroutine scheduler initialize function is used to initialize the coroutine scheduler instance.
* It must be called once before any other coroutine scheduler function for that scheduler.
* The coroutine scheduler will use the given tick function to measure the load of each task.
* The tick function must be called periodically with the given tick interval.
* \example:
* CoScheduler_Init(0, GetTimerUsec, 1000);
* \example:
* CoScheduler_Init(0, GetTimerUsec, 1000, .idleHook=my_idle_hook, .wakeupHook=my_wakeup_hook);
*/
#define CoScheduler_Init(CoSchedulerId, tick, tickInterval, ...) CoScheduler_InitP(CoSchedulerId, tick, tickInterval, (CoSchedulerInitPara[1]){[0]={.idleHook=NULL,.wakeupHook=NULL,__VA_ARGS__}})
/**
* \brief: Coroutine scheduler initialize function
* \param pScheduler: Coroutine scheduler pointer
* \param tick: Coroutine scheduler tick function
* \param tickInterval: Coroutine scheduler tick interval, indicates how many ns each tick is
* \param pPara: Coroutine scheduler initialize parameter pointer
* \return: Coroutine task create parameter default value, indicates success
* \note: Coroutine scheduler initialize function is used to initialize the coroutine scheduler.
* It must be called once before any other coroutine scheduler function.
* Only one initialization is allowed within a single thread
* It will initialize the coroutine scheduler with the given parameter.
* The coroutine scheduler will use the given tick function to measure the load of each task.
* The tick function must be called periodically with the given tick interval.
* The coroutine scheduler will use the given lock function to protect the shared resources.
* The coroutine scheduler will use the given malloc function to allocate memory for the tasks.
* The coroutine scheduler will use the given free function to free memory of the tasks.
*/
int CoScheduler_InitP(uint32_t CoSchedulerId, CoTick_t tick, uint32_t tickInterval, CoSchedulerInitPara *pPara);
/**
* \brief: Set the coroutine scheduler idle hook function
* \param CoSchedulerId: Coroutine scheduler ID
* \param idleHook: User-defined idle callback
* \return: COROUTINE_E_OK on success, or negative error code
* \note: When there are no runnable tasks, the scheduler invokes this hook with the estimated idle time (us).
*/
int CoScheduler_SetIdleHook(uint32_t CoSchedulerId, CoIdleHook_t idleHook);
/**
* \brief: Set the coroutine scheduler wakeup hook function
* \param CoSchedulerId: Coroutine scheduler ID
* \param wakeupHook: User-defined wakeup callback to unblock idleHook
* \return: COROUTINE_E_OK on success, or negative error code
* \note: Invoked whenever an event is notified or task is woken up to immediately interrupt an in-progress idle sleep.
*/
int CoScheduler_SetWakeupHook(uint32_t CoSchedulerId, CoWakeupHook_t wakeupHook);
/**
* \brief: Wake up a specific coroutine scheduler, unblocking its idleHook immediately
* \param CoSchedulerId: Coroutine scheduler ID
* \return: COROUTINE_E_OK on success, or negative error code
*/
int CoScheduler_Wakeup(uint32_t CoSchedulerId);
/**
* \brief: Coroutine scheduler start function
* \param pScheduler: Coroutine scheduler pointer
* \return: Coroutine task create parameter default value, indicates success
* \note: Coroutine scheduler start function is used to start the coroutine scheduler.
* It must be called once after the coroutine scheduler is initialized.
* It will start the coroutine scheduler and run the tasks.
* \example:
* CoScheduler_Init(0, GetTimerUsec, 1000);
* testCoroutine = CoTask_Create(test, g_StackTest, sizeof(g_StackTest), 0);
* CoScheduler_Start(0);
*/
int CoScheduler_Start(uint32_t CoSchedulerId);
/**
* \brief: Coroutine scheduler exit function
* \param pScheduler: Coroutine scheduler pointer
* \return: Coroutine task create parameter default value, indicates success
* \note: Coroutine scheduler exit function is used to exit the coroutine scheduler.
* It must be called once after the coroutine scheduler is started.
* It will exit the coroutine scheduler and stop the tasks.
*/
int CoScheduler_Exit(uint32_t CoSchedulerId);
/**
* \brief: Coroutine scheduler task count function
* \param pScheduler: Coroutine scheduler pointer
* \return: Coroutine scheduler task count, indicates the number of tasks in the coroutine scheduler
* \note: Coroutine scheduler task count function is used to get the number of tasks in the coroutine scheduler.
*/
int CoScheduler_TaskCount(uint32_t CoSchedulerId);
/**
* \brief: Coroutine scheduler timer count function
* \param pScheduler: Coroutine scheduler pointer
* \return: Coroutine scheduler timer count, indicates the number of timers in the coroutine scheduler
* \note: Coroutine scheduler timer count function is used to get the number of timers in the coroutine scheduler.
*/
int CoScheduler_TimerCount(uint32_t CoSchedulerId);
/**
* \brief: Coroutine scheduler current load function
* \param pScheduler: Coroutine scheduler pointer
* \return: Coroutine scheduler current load, indicates the load of the coroutine scheduler
* \note: Coroutine scheduler current load function is used to get the current load of the coroutine scheduler.
* The load is the number of ticks that the coroutine scheduler has run.
* The load is updated periodically with the given tick interval.
*/
#if (COROUTINE_ENABLE_LOADING_CALCULATE > 0)
uint16_t CoScheduler_CurLoad(uint32_t CoSchedulerId);
#endif
/**
* \brief: Coroutine scheduler maximum load function
* \param pScheduler: Coroutine scheduler pointer
* \return: Coroutine scheduler maximum load, indicates the maximum load of the coroutine scheduler
* \note: Coroutine scheduler maximum load function is used to get the maximum load of the coroutine scheduler.
* The load is the number of ticks that the coroutine scheduler has run.
* The load is updated periodically with the given tick interval.
*/
#if (COROUTINE_ENABLE_LOADING_CALCULATE > 0)
uint16_t CoScheduler_MaxLoad(uint32_t CoSchedulerId);
#endif
/**
* \brief: Coroutine task create function
* \param entry: [Non-default parameter] Coroutine task entry function, indicates the entry function of the coroutine task, must be specified
* \param stack: [Default parameter] Coroutine task stack, indicates the stack of the coroutine task.
* If not specified, it is allocated via the scheduler's malloc function.
* \param stackSize: [Default parameter] Coroutine task stack size, indicates the size of the coroutine task stack
* If not specified, it is the default stack size `COROUTINE_STACK_DEFAULT_SIZE`.
* \param arg: [Default parameter] Coroutine task argument, indicates the argument of the coroutine task
* \param schedulerId: [Default parameter] Coroutine timer scheduler id, indicates the scheduler id of the coroutine timer
* Negative value means the auto distribution.
* \return: Coroutine task handle, indicates the created coroutine task
* \note: Coroutine task create function is used to create a coroutine task.
* It will create a coroutine task with the given parameter.
* The coroutine task will run in the coroutine scheduler.
* \example:
* CoTask_t testCoroutine = CoTask_Create(test);
* \example:
* CoTask_t testCoroutine = CoTask_Create(test, g_StackTest, sizeof(g_StackTest));
* \example:
* CoTask_t testCoroutine = CoTask_Create(test, .stackSize=4096);
* \example:
* int arg = 4096;
* CoTask_t testCoroutine = CoTask_Create(test, .arg=&arg);
*/
#define CoTask_Create(entry, ...) CoTask_CreateP(entry, (CoTaskCreatePara[1]){[0]={.pStack=NULL,.stackSize=0,.arg=NULL,.schedulerId=-1,.manual=0,.sharedStack=0,__VA_ARGS__}})
/**
* \brief: Coroutine task create function, it is recommended to use @ref `CoTask_Create` instead
* \param pPara: Coroutine task create parameter pointer
* \return: Coroutine task handle, indicates the created coroutine task
* \note: Coroutine task create function is used to create a coroutine task.
* It will create a coroutine task with the given parameter.
* The coroutine task will run in the coroutine scheduler.
*/
CoTask_t CoTask_CreateP(CoTaskEntry_t entry, CoTaskCreatePara *pPara);
/**
* \brief: Coroutine task delete function
* \param CoTask: Coroutine task handle, indicates the coroutine task to be deleted
* \return: Coroutine task delete parameter default value, indicates success
* \note: Coroutine task delete function is used to delete a coroutine task.
* It will delete the given coroutine task.
* The coroutine task must be in the deleted state.
*/
int CoTask_Delete(CoTask_t CoTask);
/**
* \brief: Coroutine task self function
* \return: Coroutine task handle, indicates the current coroutine task
* \note: Coroutine task self function is used to get the current coroutine task.
* It will return the handle of the current coroutine task.
*/
CoTask_t CoTask_Self(void);
/**
* \brief: Explicitly resume/step into a specific manual coroutine task (point-to-point libco style)
* \param task: Coroutine task handle (must be created with .manual = 1)
* \return: COROUTINE_E_OK (0) if task yielded back, 1 if task finished execution, or negative error code (e.g. COROUTINE_E_INVALID_PARAMETER if not a manual task)
* \note: This allows running and stepping manual coroutines directly without running CoScheduler_Start.
* \example:
* CoTask_t co = CoTask_Create(my_task, .manual = 1);
* CoTask_Resume(co);
*/
int CoTask_Resume(CoTask_t task);
/**
* \brief: Wake up a suspended coroutine managed by the central scheduler, marking it immediately ready
* \param task: Coroutine task handle
* \return: COROUTINE_E_OK (0) on success, or negative error code
* \note: Clears remaining sleep ticks, allowing the central scheduler to execute it in the next scheduling pass.
*/
int CoTask_Wakeup(CoTask_t task);
/**
* \brief: Explicitly yield the current coroutine task (equivalent to CoTask_Wait(), libco style)
* \note: In manual/direct mode (resumed via CoTask_Resume), yields directly back to CoTask_Resume's caller.
* In scheduler mode (managed by CoScheduler_Start), yields time-slice to other tasks.
*/
#define CoTask_Yield() CoTask_Wait()
/**
* \brief: Coroutine task scheduler id function
* \return: Coroutine task scheduler id, indicates the scheduler id of the coroutine task
* \note: Coroutine task scheduler id function is used to get the scheduler id of the coroutine task.
*/
int CoTask_SchedulerId(void);
/**
* \brief: Coroutine task stack max used function
* \param CoTask: Coroutine task handle, indicates the coroutine task to get the stack max used
* \return: Coroutine task stack max used, indicates the maximum stack used of the coroutine task
* \note: Coroutine task stack max used function is used to get the maximum stack used of the coroutine task.
* The stack used is the maximum stack used of the coroutine task.
* The stack used is updated periodically with the given tick interval.
*/
#if (COROUTINE_ENABLE_STACK_CALCULATE > 0)
size_t CoTask_StackMaxUsed(CoTask_t CoTask);
#endif
/**
* \brief: Coroutine task stack current used function
* \param CoTask: Coroutine task handle, indicates the coroutine task to get the stack current used
* \return: Coroutine task stack current used, indicates the current stack used of the coroutine task
* \note: Coroutine task stack current used function is used to get the current stack used of the coroutine task.
* The stack used is the current stack used of the coroutine task.
* The stack used is updated periodically with the given tick interval.
*/
#if (COROUTINE_ENABLE_STACK_CALCULATE > 0)
size_t CoTask_StackCurUsed(CoTask_t CoTask);
#endif
/**
* \brief: Coroutine task wait function, blocking task waiting for event or timeout.
* \param pEvent: [Default parameter] Coroutine event pointer, indicates the event to wait
* \param ms: [Default parameter] Coroutine task wait ms, indicates the ms to wait
* \param tick: [Default parameter] Coroutine task wait tick, indicates the tick to wait
* \return: Coroutine event value, indicates the event value that triggered the coroutine task
* \note: Coroutine task wait event function is used to wait for the given event.
* @ref `CoEvent_Init` must first be called to initialize the event.
* @ref `CoEvent_Notify` notifies the occurrence of the event
* It will block the current coroutine task.
* The event value is a bit mask, each bit represents an event.
* If multiple events are triggered, the corresponding bits will be set.
* \note: Coroutine task wait ms function is used to wait for the given ms.
* It will block the current coroutine task.
* \note: Coroutine task wait tick function is used to wait for the given tick.
* It will block the current coroutine task.
* \example:
* void *test(void *arg)
* {
* while (1)
* {
* // Give up access to the scheduler without waiting, similar to yeild
* CoTask_Wait();
*
* // Wait for 1000 ms
* CoTask_Wait(.ms=1000);
*
* // Wait for 1000000 tick
* CoTask_Wait(.tick=1000000);
*
* // Wait for 1000 ms or event, if no any events occur within 1000 ms, and will timeout blocking
* CoTask_Wait(.pEvent=&g_Event, .ms=1000);
*
* // Always wait for the event, and judge every events
* uint32_t evs = CoTask_Wait(.pEvent=&g_Event);
* if (evs & 0x01)
* {
* printf("event 0x01 triggered\n");
* }
* if (evs & 0x02)
* {
* printf("event 0x02 triggered\n");
* }
* }
* }
*/
#define CoTask_Wait(...) CoTask_WaitP((CoTaskWaitPara[1]){[0]={.pEvent=NULL,.ms=0,.tick=0,__VA_ARGS__}})
/**
* \brief: Coroutine task wait function, it is recommended to use @ref `CoTask_Wait` instead
* \param pPara: Coroutine task wait parameter pointer
* \return: Coroutine event value, indicates the event value that triggered the coroutine task
* \note: Coroutine task wait function is used to wait for the given event or timeout.
* It will block the current coroutine task.
* The event value is a bit mask, each bit represents an event.
* If multiple events are triggered, the corresponding bits will be set.
*/
uint32_t CoTask_WaitP(CoTaskWaitPara *pPara);
/**
* \brief: Coroutine task wait functions, the version of the macro definition used is often used
* \param m: Coroutine task wait ms, indicates the ms to wait
* \param t: Coroutine task wait tick, indicates the tick to wait
* \param e: Coroutine event pointer, indicates the event to wait
* \return: Coroutine event value, indicates the event value that triggered the coroutine task
*/
#define CoTask_WaitMs(m) CoTask_Wait(.ms=m)
#define CoTask_WaitTick(t) CoTask_Wait(.tick=t)
#define CoTask_WaitEvent(e) CoTask_Wait(.pEvent=e)
#define CoTask_WaitEventMs(e, m) CoTask_Wait(.pEvent=e, .ms=m)
#define CoTask_WaitEventTick(e, t) CoTask_Wait(.pEvent=e, .tick=t)
/**
* \brief: Coroutine timer create function
* \param entry: [Non-default parameter] Coroutine timer entry, indicates the timer entry function
* \param ms: [Default parameter] Coroutine timer ms, indicates the ms interval
* \param tick: [Default parameter] Coroutine timer tick, indicates the tick interval
* \param schedulerId: [Default parameter] Coroutine timer scheduler id, indicates the scheduler id of the coroutine timer
* Negative value means the auto distribution.
* \return: Coroutine timer handle, indicates the created timer
* \note: One of the ms and tick parameters must be set
* \note: Coroutine timer create function is used to create a timer with the given ms or tick interval.
* The timer will call the given entry function periodically with the given ms or tick interval.
* \example:
* CoTimer_t timer = CoTimer_Create(timer_entry, .ms=100); // create a timer with 100ms interval
*/
#define CoTimer_Create(entry, ...) CoTimer_CreateP(entry, (CoTimerCreatePara[1]){[0]={.ms=0,.tick=0,.schedulerId=-1,__VA_ARGS__}})
/**
* \brief: Coroutine timer create function, it is recommended to use @ref `CoTimer_Create` instead
* \param pPara: Coroutine timer create parameter pointer
* \return: Coroutine timer handle, indicates the created timer
* \note: Coroutine timer create function is used to create a timer with the given ms or tick interval.
* The timer will call the given entry function periodically with the given ms or tick interval.
*/
CoTimer_t CoTimer_CreateP(CoTimerEntry_t entry, CoTimerCreatePara *pPara);
/**
* \brief: Coroutine timer create ms function, it is recommended to use @ref `CoTimer_CreateMs` instead
* \param entry: Coroutine timer entry, indicates the timer entry function
* \param m: Coroutine timer ms, indicates the ms interval
* \param t: Coroutine timer tick, indicates the tick interval
* \return: Coroutine timer handle, indicates the created timer
* \note: Coroutine timer create ms function is used to create a timer with the given ms interval.
* The timer will call the given entry function periodically with the given ms interval.
* \example:
* CoTimer_t timer = CoTimer_CreateMs(timer_entry, 100); // create a timer with 100ms interval
*/
#define CoTimer_CreateMs(entry, m) CoTimer_Create(entry, .ms=m)
#define CoTimer_CreateTick(entry, t) CoTimer_Create(entry, .tick=t)
/**
* \brief: Coroutine timer delete function
* \param Timer: Coroutine timer handle, indicates the timer to delete
* \note: Coroutine timer delete function is used to delete the given timer.
* It must be called after @ref `CoTimer_CreateTick` or @ref `CoTimer_CreateMs`.
* \example:
* CoTimer_Delete(timer); // delete the timer
*/
void CoTimer_Delete(CoTimer_t Timer);
/**
* \brief: Coroutine timer self function
* \return: Coroutine timer handle, indicates the current timer
* \note: Coroutine timer self function is used to get the handle of the current timer.
* \example:
* CoTimer_t timer = CoTimer_Self(); // get the current timer
*/
CoTimer_t CoTimer_Self(void);
/**
* \brief: Coroutine timer scheduler id function
* \return: Coroutine timer scheduler id, indicates the scheduler id of the coroutine timer
* \note: Coroutine timer scheduler id function is used to get the scheduler id of the coroutine timer.
*/
int CoTimer_SchedulerId(void);
/**
* \brief: Coroutine event initialize function
* \param pEvent: Coroutine event pointer, indicates the event to initialize
* \note: Coroutine event initialize function is used to initialize the given event.
* It must be called before @ref `CoTask_WaitEvent`.
* \example:
* CoEvent_Init(&g_Event);
*/
void CoEvent_Init(CoEvent *pEvent);
/**
* \brief: Coroutine event notify function
* \param pEvent: Coroutine event pointer, indicates the event to notify
* \param evs: Coroutine event value, indicates the event value to notify
* \note: Coroutine event notify function is used to notify the occurrence of the event.
* It will set the corresponding bits in the event value.
* \example:
* CoEvent_Notify(&g_Event, 0x01); // notify event 0x01
* \example:
* CoEvent_Notify(&g_Event, 0x01 | 0x02); // notify event 0x01 and 0x02
*/
void CoEvent_Notify(CoEvent *pEvent, uint32_t evs);
#ifdef __cplusplus
}
#endif
#endif // !__coroutine_H