// 定时器业务驱动
// 杭州秒寻科技有限公司
// 周涛
// 2023-10-11
#include "includes.h"

static uint32 g_dwOldTicks = 0;                           // 系统前一次读出的Tick值
static TSYS_TIMER_MA g_stTimerTable = {0};                // 定时器管理表
static TSYS_TIMER_NODE g_astTimerNode[SYS_MAX_TIMER_NUM]; // 定时器节点资源

// 初始化定时模块
void timer_init()
{
    // 定时器节点资源初始化
    g_dwOldTicks = 0; // 系统旧Tick值初始化为0
    SYS_MEMSET(g_astTimerNode, 0, sizeof(g_astTimerNode));
    for (uint8 i = 0; i < SYS_MAX_TIMER_NUM; i++)
    {
        // 定时器ID赋值
        g_astTimerNode[i].byTimerId = i;

        // 后向指针处理
        if ((SYS_MAX_TIMER_NUM - 1) == i)
        {
            g_astTimerNode[i].ptNext = NULL; // 最后一个节点的后向指针为NULL
        }
        else
        {
            g_astTimerNode[i].ptNext = (TSYS_TIMER_NODE *)&g_astTimerNode[i + 1];
        }
    }

    // 定时器管理结构初始化
    g_stTimerTable.byIdleNum = SYS_MAX_TIMER_NUM;
    g_stTimerTable.byUseNum = 0;
    g_stTimerTable.ptTimerIdle = (TSYS_TIMER_NODE *)g_astTimerNode; // 第一个节点即为空闲节点
    g_stTimerTable.ptTimerUse = NULL;                               // 定时器节点一个都没有被使用

    return;
}

// 创建定时器(原则上，每个模块创建一个定时器)
// pbyTimerId:定时器Id
// byTimerType:定时器类型
uint8 timer_create_timer(uint8 *pbyTimerId, TIMER_TYPE_E byTimerType)
{
    TSYS_TIMER_NODE *ptTimer = NULL; // 定时器节点指针

    // 判断是否还有空闲定时器
    if (0 == g_stTimerTable.byIdleNum)
    {
        return 0;
    }

    ////处理空闲定时器
    ptTimer = g_stTimerTable.ptTimerIdle; // 提取空闲定时器节点资源
    g_stTimerTable.byIdleNum--;           // 空闲定时器个数--
    if (0 == g_stTimerTable.byIdleNum)
    {
        g_stTimerTable.ptTimerIdle = NULL; // 没有空闲定时器
    }
    else
    {
        g_stTimerTable.ptTimerIdle = ptTimer->ptNext; // 空闲定时器指向下一个定时器
    }

    // 定时器使用个数++
    g_stTimerTable.byUseNum++;

    // 修改定时器非空闲表头指针，使用链表中前向、后向指针
    if (NULL == g_stTimerTable.ptTimerUse)
    { // 定时器还没有被使用
        ptTimer->ptPre = NULL;
        ptTimer->ptNext = NULL;
    }
    else
    { // 定时器已经被使用
        ////把当前定时器放到链表头上
        ptTimer->ptPre = NULL;
        ptTimer->ptNext = g_stTimerTable.ptTimerUse; // 当前将被使用的定时器节点的后向指针指向当前被使用的定时器节点
        g_stTimerTable.ptTimerUse->ptPre = ptTimer;  // 当前被使用的定时器节点的前向指针指向当前将被使用的定时器节点
    }
    g_stTimerTable.ptTimerUse = ptTimer; // 当前将被使用的定时器节点被修改为被使用定时器节点

    // 设置定时器节点信息
    ptTimer->byType = byTimerType;
    ptTimer->byState = ETIMER_STOP;
    ptTimer->dwTickOffset = 0;
    ptTimer->dwTimerLimit = 0;
    ptTimer->pvTimeFunc = NULL;

    // 时器编号
    *pbyTimerId = ptTimer->byTimerId;

    return 1;
}

// 删除定时器
// byTimerId:定时器编号
uint8 timer_delete_timer(uint8 byTimerId)
{
    TSYS_TIMER_NODE *ptTimer = NULL;     // 定时器节点指针
    TSYS_TIMER_NODE *ptTimerPre = NULL;  // 前一定时器节点指针
    TSYS_TIMER_NODE *ptTimerNext = NULL; // 后一定时器节点指针

    // 判断定时器编号是否正确
    if (byTimerId >= SYS_MAX_TIMER_NUM)
    {
        return 0;
    }

    // 判断定时器是否已经创建
    if (ETIMER_IDLE == g_astTimerNode[byTimerId].byState)
    {
        return 0;
    }

    // 判断定时器使用个数是否等于0
    if (0 == g_stTimerTable.byUseNum)
    {
        return 0;
    }

    // 提取删除的定时器节点
    ptTimer = (TSYS_TIMER_NODE *)&g_astTimerNode[byTimerId];

    // 定时器使用个数--
    g_stTimerTable.byUseNum--;

    // 修改定时器使用头指针
    if (0 == g_stTimerTable.byUseNum)
    { // 无可使用的定时器了
        g_stTimerTable.ptTimerUse = NULL;
    }
    else
    {                                  // 还有可使用的定时器
        ptTimerPre = ptTimer->ptPre;   // 前向节点
        ptTimerNext = ptTimer->ptNext; // 后向节点

        if ((NULL != ptTimerPre) && (NULL != ptTimerNext))
        { // 删除的定时器处于链表中间
            ptTimerPre->ptNext = ptTimerNext;
            ptTimerNext->ptPre = ptTimerPre;
        }
        else if (NULL == ptTimerPre)
        { // 删除的定时器处于链表头
            ptTimerNext->ptPre = NULL;
            g_stTimerTable.ptTimerUse = ptTimerNext;
        }
        else if (NULL == ptTimerNext)
        { // 删除的定时器处于链表尾
            ptTimerPre->ptNext = NULL;
        }
        else
        { // 不可能出现的情况
            return 0;
        }
    }

    // 初始化删除的定时器节点信息
    SYS_MEMSET(&g_astTimerNode[byTimerId], 0, sizeof(TSYS_TIMER_NODE));
    g_astTimerNode[byTimerId].byTimerId = byTimerId; // 定时器编号不能清空

    // 将该定时器节点加入到空闲链表中
    if (NULL == g_stTimerTable.ptTimerIdle)
    {
        g_stTimerTable.ptTimerIdle = ptTimer;
    }
    else
    {
        ptTimer->ptNext = g_stTimerTable.ptTimerIdle;
        g_stTimerTable.ptTimerIdle = ptTimer;
    }

    // 定时器空闲个数++
    g_stTimerTable.byIdleNum++;

    return 1;
}

// 启动定时器
// byTimerId:定时器编号
// dwMilliseconds:定时器时长，单位毫秒（步进100毫秒）
// pvFunc:超时回调函数
uint8 timer_start_timer(uint8 byTimerId, uint32 dwMilliseconds, TIMER_CALLBACK_FUNC pvFunc)
{
    uint32 dwTickOffset = 0; // 系统Tick偏移量
    uint32 dwTimerTicks = 0; // 系统Tick值
    // 判断定时器编号是否正确
    if (byTimerId >= SYS_MAX_TIMER_NUM)
    {
        return 0;
    }

    // 判断定时触发处理函数指针是否空
    if (NULL == pvFunc)
    {
        return 0;
    }

    // 判断该定时器是否已经创建
    if (ETIMER_IDLE == g_astTimerNode[byTimerId].byState)
    {
        return 0;
    }

    // 计算定时tick值
    dwTickOffset = dwMilliseconds / 500; // 定时器500毫秒计数一次
    if (0 != (dwMilliseconds % 500))
    {
        dwTickOffset++;
    }

    // 读取当前系统的tick值
    driver_timer_timer3_get_ticks(&dwTimerTicks);
    g_astTimerNode[byTimerId].byState = ETIMER_START;
    g_astTimerNode[byTimerId].dwTickOffset = dwTickOffset;
    g_astTimerNode[byTimerId].dwTimerLimit = dwTimerTicks + dwTickOffset;
    g_astTimerNode[byTimerId].pvTimeFunc = pvFunc;

    return 1;
}

// 停止定时器
// byTimerId:定时器编号
uint8 timer_stop_timer(uint8 byTimerId)
{
    // 判断定时器编号是否正确
    if (byTimerId >= SYS_MAX_TIMER_NUM)
    {
        return 0;
    }

    // 判断该定时器是否已经创建
    if (ETIMER_IDLE == g_astTimerNode[byTimerId].byState)
    {
        return 0;
    }

    // 定时器状态设为停止
    g_astTimerNode[byTimerId].byState = ETIMER_STOP;

    return 1;
}

// 定时器服务处理函数
void timer_process_func(void *pvPara)
{
    uint32 dwTimerTicks = 0;         // 系统Tick值
    TSYS_TIMER_NODE *ptTimer = NULL; // 定时器节点指针

    pvPara = NULL;

    if (NULL == g_stTimerTable.ptTimerUse)
    { // 定时器使用头指针为空，则不处理
        return;
    }

    // 读取当前系统的tick值
    driver_timer_timer3_get_ticks(&dwTimerTicks);

    if (dwTimerTicks == g_dwOldTicks)
    { // 两次tick值相同，则不处理
        return;
    }

    g_dwOldTicks = dwTimerTicks; // 保存系统当前Tick值

    // 遍历所有已使用定时器
    ptTimer = g_stTimerTable.ptTimerUse; // 提取定时器使用头指针
    while (ptTimer != NULL)
    {
        // 定时器处于启动状态才处理
        if (ETIMER_START == ptTimer->byState)
        {
            // 系统当前定时器的Tick值>=定时器预期Tick值
            if (g_dwOldTicks >= ptTimer->dwTimerLimit)
            {
                // 单次触发定时器
                if (ETIMER_ONCE == ptTimer->byType)
                {
                    ptTimer->byState = ETIMER_STOP; // 设置为停止状态
                }
                else
                { // 自动循环定时器,则赋值下次触发的Tick值
                    ptTimer->dwTimerLimit = g_dwOldTicks + ptTimer->dwTickOffset;
                }

                ptTimer->pvTimeFunc(); // 调用定时触发处理函数
            }
        }

        // 指向下一个定时器
        ptTimer = ptTimer->ptNext;
    }

    return;
}
