1.简介
基于双向链表的软件定时器是一种常见的实现方式,它可以在操作系统或应用程序中用于管理定时任务。
双向链表是一种数据结构,它包含指向前一个节点和后一个节点的指针。在软件定时器的实现中,每个定时任务可以表示为一个节点,节点中包含定时任务的信息,如定时时间、回调函数等。
软件定时器可以被添加到硬件定时器中,主线程循环中,另开线程中。
2.头文件
#ifndef SOFT_TIMER_H
#define SOFT_TIMER_H
#include "list.h"
typedef int (*timer_callback)(int msg_1, int msg_2); //定时器回调函数
typedef enum _TimerStatusType
{
TST_STOP = 0x00, //停止
TST_RUNNING = 0x01, //运行
TST_TIMEOUT = 0x02, //超时
} TimerStatusType;
typedef enum _TimerModeType
{
TMT_ONE = 0x00, //单次
TMT_LOOP = 0x01, //循环
} TimerModeType;
typedef enum _TimerPriorityType
{
TPT_REALTIME = 0x00, //实时
TPT_LOWLEVEL = 0x01, //低优先级
} TimerPriorityType;
typedef struct _TimerList
{
int timer_id; //定时器编号
TimerPriorityType level; //定时器响应优先级
TimerStatusType status; //定时器状态
TimerModeType mode; //模式
unsigned char r;
timer_callback callback; //注册的回调函数
int msg_1; //回调函数参数1
int msg_2; //回调函数参数2
unsigned long long TimerCycle; //配置的定时周期
unsigned long long nextTime; //响应时间点
struct list_head node; //定时器链表
} TimerList;
typedef struct _TimerListQueue
{
int cnt; //数量
unsigned long long nextTime; //响应时间点
struct list_head listHead; //软件定时器队列头
} TimerListQueue;
void cj_softTimer_interrupt_task();
void cj_softTimer_init();
bool cj_softTimer_creat(timer_callback func, int msg_1, int msg_2, TimerModeType type, TimerPriorityType level, unsigned int id);
bool cj_softTimer_break(unsigned int id);
bool cj_softTimer_start(unsigned int id, unsigned int millisecond);
bool cj_softTimer_stop(unsigned int id);
#endif
3.实现代码
#include "softtimer.h"
#include "cjevent.h"
#include <esp_timer.h>
#include <string.h>
static TimerListQueue s_timerListQueue;
extern EventListQueue g_normalEventQueue;
/* 获取下一次 软件定时器任务中断响应的时间点 */
static unsigned long long getTimerNextResponseTime(TimerListQueue *queue, unsigned int *nodeCnt)
{
TimerList *lister = NULL;
*nodeCnt = 0;
unsigned long long responseTime_min = 0;
list_for_each_entry_reverse(lister, TimerList, &queue->listHead, node)
{
if (lister->status == TST_RUNNING)
{
*nodeCnt += 1;
/* next_valid_min 取链表中 最小的一个*/
if (responseTime_min == 0 || responseTime_min >= lister->nextTime)
{
responseTime_min = lister->nextTime;
}
}
}
if (*nodeCnt > 0)
return responseTime_min;
else
return queue->nextTime;
}
static void updateTimerList_nextTime(TimerListQueue *queue)
{
unsigned long long nextTime;
unsigned int runningSoftTimerCnt = 0;
/* 获取软件定时器链表里面定时器任务中的最小一个的响应时间 */
nextTime = getTimerNextResponseTime(queue, &runningSoftTimerCnt);
if(runningSoftTimerCnt > 0)
{
if (nextTime != queue->nextTime)
{
queue->nextTime = nextTime;
}
}
}
//定时器超时之后的处理函数
static void timerListProcess(TimerListQueue *queue)
{
TimerList *lister = NULL;
list_for_each_entry_reverse(lister, TimerList, &queue->listHead, node)
{
if (lister->status == TST_TIMEOUT)
{
if (lister->callback != NULL)
{
if (lister->level == TPT_LOWLEVEL)
{
/* 低优先级定时器任务可以推入事件管理器中 */
EventStaus status;
status.fun = lister->callback;
status.status_1 = lister->msg_1;
status.status_2 = lister->msg_2;
addToEventList(&g_normalEventQueue, ET_TIMER, &status, NULL);
}
else
{
/* 高优先级 定时器任务 */
lister->callback(lister->msg_1, lister->msg_2);
}
}
/* 判断是否是循环定时器任务 */
if(lister->mode == TMT_LOOP)
{
lister->status = TST_RUNNING;
lister->nextTime = get_now_time() + lister->TimerCycle;
}
else
{
lister->status = TST_STOP;
}
}
}
/* 更新定时器链表里下次响应的时间 */
updateTimerList_nextTime(queue);
return;
}
//中断处理函数
static void timer_callback_fun()
{
TimerList *lister = NULL;
bool isNeedProcess = false;
unsigned long long nowTime = get_now_time();
list_for_each_entry_reverse(lister, TimerList, &s_timerListQueue.listHead, node)
{
if (lister->status == TST_RUNNING)
{
if (nowTime >= lister->nextTime)
{
lister->status = TST_TIMEOUT;
isNeedProcess = true;
}
}
}
if (isNeedProcess)
{
timerListProcess(&s_timerListQueue);
}
}
void cj_softTimer_interrupt_task()
{
if(s_timerListQueue.nextTime > get_now_time())
{
return;
}
else
{
timer_callback_fun();
}
return;
}
void cj_softTimer_init()
{
/* 初始化链表头 */
memset(&s_timerListQueue.listHead, 0, sizeof(struct list_head));
INIT_LIST_HEAD(&s_timerListQueue.listHead);
/* 其他参数初始化 */
s_timerListQueue.cnt = 0;
s_timerListQueue.nextTime = get_now_time();
}
bool cj_softTimer_creat(timer_callback func, int msg_1, int msg_2,
TimerModeType type, TimerPriorityType level, unsigned int id)
{
TimerList *lister = NULL;
list_for_each_entry_reverse(lister, TimerList, &s_timerListQueue.listHead, node)
{
/* 发现id号存在 则直接返回失败 */
if (lister->timer_id == id)
{
printf("timer id = %d is aready creat !\n", id);
return false;
}
}
TimerList *newTimer = (TimerList *)malloc(sizeof(TimerList));
memset(newTimer, 0, sizeof(TimerList));
newTimer->timer_id = id;
newTimer->level = level;
newTimer->status = TST_STOP;
newTimer->mode = type;
newTimer->callback = func;
newTimer->msg_1 = msg_1;
newTimer->msg_2 = msg_2;
s_timerListQueue.cnt += 1;
list_add(&(newTimer->node), &(s_timerListQueue.listHead));
return true;
}
bool cj_softTimer_break(unsigned int id)
{
TimerList *lister = NULL;
list_for_each_entry_reverse(lister, TimerList, &s_timerListQueue.listHead, node)
{
if (lister->timer_id == id)
{
s_timerListQueue.cnt -= 1;
list_del(&lister->node);
free(lister);
return true;
}
}
return false;
}
bool cj_softTimer_start(unsigned int id, unsigned int millisecond)
{
TimerList *lister = NULL;
list_for_each_entry_reverse(lister, TimerList, &s_timerListQueue.listHead, node)
{
if (lister->timer_id == id)
{
if(lister->status == TST_RUNNING)
{
/* 当前如果正在运行 不允许重复启动 */
printf("timer id = %d is ready running !\n", id);
return false;
}
break;;
}
}
if(lister == NULL)
return false;
unsigned long long timer_now = get_now_time();
unsigned long long us_second = millisecond * 1000;
lister->TimerCycle = us_second;
lister->nextTime = timer_now + us_second;
lister->status = TST_RUNNING;
/* 跟新下次中断的时间 */
updateTimerList_nextTime(&s_timerListQueue);
return true;
}
bool cj_softTimer_stop(unsigned int id)
{
TimerList *lister = NULL;
list_for_each_entry_reverse(lister, TimerList, &s_timerListQueue.listHead, node)
{
if (lister->timer_id == id)
{
lister->status = TST_STOP;
return true;
}
}
return false;
}
4.示例
int temp_callBack(int msg_1, int msg_2)
{
printf("hello world !\n");
return 0;
}
int main()
{
...;
cj_softTimer_init();
cj_softTimer_creat(temp_callBack, 0, 0, TMT_LOOP, TPT_LOWLEVEL, 0);
cj_softTimer_start(0, 2000);
while(1)
{
cj_softTimer_interrupt_task();
...;
}
}