/*
 * timeSliceOffset.c
 *
 *  Created on: 2024年6月22日
 *      Author: psx
 */

#include "TimeSliceOffset.h"


static STR_TimeSliceOffset* pTimeSliceList = NULL;         /**< 时间片链表入口(仅入口，最终直接指向设备实体，所需无需申请空间。链表是单向线性链表) */


/**
* @brief        注册
* @param[in]    pTSlice         时间片对象指针
* @param[in]    taskFunc        任务函数的函数指针
* @param[in]    reloadVal       时间片重载值*tick基准即为任务执行间隔
* @param[in]    offset          偏移量，这是错位的精髓
* @return       配置是否成功
* - 0   注册成功
* - 1   配置完成，但对象已存在，无需加入链表
* - -1  pTSlice为空指针，无效对象
* @par          注意事项：
* - reloadVal设置为零即非定时任务，则offset偏移量无效
* @par          示例:
* @code
*
* TimeSliceOffset_Register(&m_timeSlice_1, Task_1, 0, 0);        //0，即非定时任务(每次轮询都会执行)
* TimeSliceOffset_Register(&m_timeSlice_2, Task_2, 10, 0);       //10*1ms，即10ms运行一次
* TimeSliceOffset_Register(&m_timeSlice_3, Task_3, 10, 5);       //10*1ms，即10ms运行一次，与Task_2错开5ms，这样就不会集中到同一个10ms的时间点上
*
* @endcode
*/
int TimeSliceOffset_Register(STR_TimeSliceOffset* pTSlice,    \
                            void (*taskFunc)(void),     \
                            unsigned short reloadVal,   \
                            unsigned short offset)
{
    if(NULL == pTSlice)return -1;                       /* 返回错误：无效对象 */

    pTSlice->reloadVal = reloadVal;
    pTSlice->count = reloadVal + offset;                /* 添加偏移量，使得同一数值的时间片错开 */
    pTSlice->taskFunc = taskFunc;
    if(0 == reloadVal)                                  /* 非定时任务 */
    {
        pTSlice->runFlag = 1;                           /* 非定时任务可运行标志默认为一 */
    }
    else                                                /* 定时任务 */
    {
        pTSlice->runFlag = 0;                           /* 定时任务可运行标志默认为零 */
    }

    /*遍历链表，防止添加重复*/
    for(STR_TimeSliceOffset* pTemp = pTimeSliceList; pTemp != NULL; pTemp = pTemp->pNext)
    {
        if(pTemp == pTSlice)
        {
            return 1;                                   /* 返回成功：配置完成，但对象已存在，无需加入链表 */
        }
    }
    /*加入链表*/
    pTSlice->pNext = pTimeSliceList;
    pTimeSliceList = pTSlice;                           /* 把对象加入到链表头部 */

    return 0;                                           /* 返回成功：注册成功 */
}

/**
* @brief        取消注册
* @return       取消配置是否成功
* - 0   取消配置成功
* - 1   取消配置成功，但对象不存在，无需从链表中删除
* - -1  pTSlice为空指针，无效对象
* @endcode
*/
int TimeSliceOffset_Unregister(STR_TimeSliceOffset* pTSlice)
{
    if (NULL == pTSlice) return -1;                     /* 返回错误：无效对象 */

    /* 遍历链表 */
    for (STR_TimeSliceOffset* pTemp = pTimeSliceList; pTemp != NULL; pTemp = pTemp->pNext) {
        if (pTemp->pNext == pTSlice) {
            pTemp->pNext = pTemp->pNext->pNext;
            return 0;                                   /* 返回成功：取消注册 */
        } else if (pTemp == pTSlice) {
            pTimeSliceList = pTemp->pNext;
//            pTimeSliceList->pNext = pTemp->pNext->pNext;
            return 0;                                   /* 返回成功：取消注册 */
        }
    }
    return 1;                                           /* 返回成功：对象不存在于链表中 */
}

/**
* @brief        启动时间片错位轮询(代替main的while循环)
* @param        null
* @return       null
* @par          注意事项：
* - null
*/
void TimeSliceOffset_Start(void)
{
    while(1)                                            /* 代替main的while循环 */
    {
        /*遍历时间片链表*/
        for(STR_TimeSliceOffset* pTemp = pTimeSliceList; pTemp != NULL; pTemp = pTemp->pNext)
        {
            if(pTemp->runFlag)                          /* 可运行则调用任务函数 */
            {
                if(pTemp->reloadVal)                    /* 重载值不为0，即定时任务 */
                {
                    pTemp->runFlag = 0;                 /* 可运行标志清零，开启新一轮倒计时 */
                }
                pTemp->taskFunc();
            }

        }
    }
}



/**
* @brief        时间片生成(放到systick或定时器中断处理函数内)
* @param        null
* @return       null
* @par          注意事项：
* - null
*/
void TimeSliceOffset_Produce(void)
{
    /*遍历时间片链表*/
    for(STR_TimeSliceOffset* pTemp = pTimeSliceList; pTemp != NULL; pTemp = pTemp->pNext)
    {
        if(pTemp->reloadVal)                            /* 重载值不为0，即定时任务 */
        {
            --pTemp->count;                             /* 计数器递减 */
            if(0 == pTemp->count)                       /* 计数器递减到零 */
            {
                pTemp->runFlag = 1;                     /* 允许执行 */
                pTemp->count = pTemp->reloadVal;        /* 计数器重载 */
            }
        }
    }
}


