#include "Task_Scheduler.h"

typedef struct
{
    tasklib_uint8_t ID2ms;
    tasklib_uint8_t ID5ms;
    tasklib_uint8_t ID10ms;
    tasklib_uint8_t ID20ms;
    tasklib_uint8_t ID50ms;
    tasklib_uint8_t ID100ms;
} st_Sys_Task_Group;

typedef struct
{
    tasklib_uint32_t MainCnt;
    tasklib_uint32_t DstVal1ms;
    tasklib_uint32_t DstVal100ms;
} st_Sys_Tick_Timer;

typedef struct
{
    tasklib_uint16_t  msRocBak;
    st_Sys_Task_Group TaskGroup;
} st_Sys_Scheduling;

st_Sys_TaskGroup          TaskGroup;
st_Sys_Scheduling         SysScheduling;
st_Sys_Tick_Timer         SysTickTimer;
volatile tasklib_uint16_t SysRollingCounter1ms;

void Sys_Init(const st_Sys_TaskGroup *TaskGroup_t)
{
    SysScheduling.msRocBak = 0u;

    SysScheduling.TaskGroup.ID2ms   = 0U;
    SysScheduling.TaskGroup.ID5ms   = 0U;
    SysScheduling.TaskGroup.ID10ms  = 1U;
    SysScheduling.TaskGroup.ID20ms  = 3U;
    SysScheduling.TaskGroup.ID50ms  = 5U;
    SysScheduling.TaskGroup.ID100ms = 7U;

    SysTickTimer.MainCnt     = 0U;
    SysTickTimer.DstVal1ms   = 20U;
    SysTickTimer.DstVal100ms = 2000U;

    SysRollingCounter1ms = 0U;

    TaskGroup.Task2ms         = (( void         *)0);
    TaskGroup.Task5ms         = (( void         *)0);
    TaskGroup.Task10ms        = (( void        *)0);
    TaskGroup.Task20ms        = (( void        *)0);
    TaskGroup.Task50ms        = (( void        *)0);
    TaskGroup.Task100ms       = (( void       *)0);
    TaskGroup.Exact_Task50us  = (( void  *)0);
    TaskGroup.Exact_Task100ms = (( void * )0);

    TaskGroup.Task2ms              = TaskGroup_t->Task2ms;
    TaskGroup.Task5ms              = TaskGroup_t->Task5ms;
    TaskGroup.Task10ms             = TaskGroup_t->Task10ms;
    TaskGroup.Task20ms             = TaskGroup_t->Task20ms;
    TaskGroup.Task50ms             = TaskGroup_t->Task50ms;
    TaskGroup.Task100ms            = TaskGroup_t->Task100ms;
    TaskGroup.Exact_Task50us       = TaskGroup_t->Exact_Task50us;
    TaskGroup.Exact_Task100ms      = TaskGroup_t->Exact_Task100ms;
    TaskGroup.Pseudo_Real_TimeTask = TaskGroup_t->Pseudo_Real_TimeTask;
}

void Sys_Scheduling_Service(void)
{
    tasklib_uint16_t u16msROC;
    tasklib_uint16_t u16Diff;
    u16msROC = SysRollingCounter1ms;
    if ( TaskGroup.Pseudo_Real_TimeTask != (( void * )0) )
    {
        TaskGroup.Pseudo_Real_TimeTask( );
    }
    if ( u16msROC >= SysScheduling.msRocBak )
    {
        u16Diff = u16msROC - SysScheduling.msRocBak;
    }
    else
    {
        u16Diff = 65535u - SysScheduling.msRocBak + u16msROC + 1u;
    }
    if ( u16Diff >= 1U )
    {
        SysScheduling.msRocBak = u16msROC;

        SysScheduling.TaskGroup.ID2ms++;
        if ( SysScheduling.TaskGroup.ID2ms >= 2u )
        {
            SysScheduling.TaskGroup.ID2ms = 0u;
            if ( TaskGroup.Task2ms != (( void * )0) )
            {
                TaskGroup.Task2ms( );
            }
        }
        SysScheduling.TaskGroup.ID5ms++;
        if ( SysScheduling.TaskGroup.ID5ms >= 5u )
        {
            SysScheduling.TaskGroup.ID5ms = 0u;
            if ( TaskGroup.Task5ms != (( void * )0) )
            {
                TaskGroup.Task5ms( );
            }
        }
        SysScheduling.TaskGroup.ID10ms++;
        if ( SysScheduling.TaskGroup.ID10ms >= 10u )
        {
            SysScheduling.TaskGroup.ID10ms = 0u;
            if ( TaskGroup.Task10ms != (( void * )0) )
            {
                TaskGroup.Task10ms( );
            }
        }
        SysScheduling.TaskGroup.ID20ms++;
        if ( SysScheduling.TaskGroup.ID20ms >= 20u )
        {
            SysScheduling.TaskGroup.ID20ms = 0u;
            if ( TaskGroup.Task20ms != (( void * )0) )
            {
                TaskGroup.Task20ms( );
            }
        }
        SysScheduling.TaskGroup.ID50ms++;
        if ( SysScheduling.TaskGroup.ID50ms >= 50u )
        {
            SysScheduling.TaskGroup.ID50ms = 0u;
            if ( TaskGroup.Task50ms != (( void * )0) )
            {
                TaskGroup.Task50ms( );
            }
        }
        SysScheduling.TaskGroup.ID100ms++;
        if ( SysScheduling.TaskGroup.ID100ms >= 100u )
        {
            SysScheduling.TaskGroup.ID100ms = 0u;
            if ( TaskGroup.Task100ms != (( void * )0) )
            {
                TaskGroup.Task100ms( );
            }
        }
    }
}

void Sys_Process_ISR(void)
{

    tasklib_uint16_t Counter;

    if ( TaskGroup.Exact_Task50us != (( void * )0) )
    {
        TaskGroup.Exact_Task50us( );
    }

    SysTickTimer.MainCnt++;

    if ( SysTickTimer.MainCnt >= SysTickTimer.DstVal1ms )
    {
        Counter                = SysRollingCounter1ms;
        SysRollingCounter1ms   = Counter + 1U;
        SysTickTimer.DstVal1ms = SysTickTimer.MainCnt + 20U;
    }

    if ( SysTickTimer.MainCnt >= SysTickTimer.DstVal100ms )
    {
        if ( TaskGroup.Exact_Task100ms != (( void * )0) )
        {
            TaskGroup.Exact_Task100ms( );
        }
        SysTickTimer.DstVal100ms = SysTickTimer.MainCnt + 2000U;
    }

    if ( SysTickTimer.MainCnt & 0xFFFF0000UL )
    {
        SysTickTimer.MainCnt &= 0x0000FFFFUL;
        SysTickTimer.DstVal1ms &= 0x0000FFFFUL;
        SysTickTimer.DstVal100ms &= 0x0000FFFFUL;
    }
}