/*
 * tmos.c
 *
 *  Created on: Feb 29, 2024
 *      Author: Administrator
 */
#include "ch32v30x.h"
#include "tmos.h"
#include "string.h"
#define TASK_ID_MAX 10
#define TASK_EVENT_MAX  16

static uint8_t tmos_num = 0;

typedef struct{
    tmosEvents event;
    tmosTimer timer[TASK_EVENT_MAX];
    tmosTimer time_stamp[TASK_EVENT_MAX];
    pTaskEventHandlerFn TaskEventHandlerFn;
}ST_TASK;

static ST_TASK tmosTask[TASK_ID_MAX];
static tmosTimer time_stamp = 0;



static tmosTimer toms_tick=0;

/* Interrupt Function Declaration */
void TIM1_UP_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));

/*********************************************************************
 * @fn      TIM1_Init
 *
 * @brief   Initialize timer3 for keyboard and mouse scan.
 *
 * @param   arr - The specific period value
 *          psc - The specifies prescaler value
 *
 * @return  none
 */
void TIM1_Init( uint16_t arr, uint16_t psc )
{
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure = { 0 };
    NVIC_InitTypeDef NVIC_InitStructure = { 0 };

    /* Enable Timer3 Clock */
    RCC_APB2PeriphClockCmd( RCC_APB2Periph_TIM1, ENABLE );

    /* Initialize Timer3 */
    TIM_TimeBaseStructure.TIM_Period = arr;
    TIM_TimeBaseStructure.TIM_Prescaler = psc;
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit( TIM1, &TIM_TimeBaseStructure );

    TIM_ITConfig( TIM1, TIM_IT_Update, ENABLE );

    NVIC_InitStructure.NVIC_IRQChannel = TIM1_UP_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init( &NVIC_InitStructure );

    /* Enable Timer3 */
    TIM_Cmd( TIM1, ENABLE );
}

/*********************************************************************
 * @fn      TIM1_IRQHandler
 *
 * @brief   This function handles TIM3 global interrupt request.
 *
 * @return  none
 */
//
void TIM1_UP_IRQHandler( void )
{
    if( TIM_GetITStatus( TIM1, TIM_IT_Update ) != RESET )
    {
        /* Clear interrupt flag */
        TIM_ClearITPendingBit( TIM1, TIM_IT_Update );

        toms_tick++;
    }
}

bStatus_t tmos_init()
{
    tmos_num = 0;

    memset((void*)tmosTask, 0, sizeof(tmosTask));

    toms_tick = 0;
    time_stamp = 0;

    TIM1_Init( 24, SystemCoreClock / 40000 -1 );

    return 0;
}

bStatus_t tmos_set_event( tmosTaskID taskID, tmosEvents event )
{
    tmosTask[taskID].event |= event;
    return 0;
}

bStatus_t tmos_start_task( tmosTaskID taskID, tmosEvents event, tmosTimer time  )
{
    uint8_t i;

    tmosTask[taskID].event |= event;

    for(i=0; i<TASK_EVENT_MAX; i++)
    {
       if((event >> i) & 0x01)
       {
           tmosTask[taskID].timer[i] = time ;
           break;
       }
    }
    return 0;
}

bStatus_t tmos_stop_task( tmosTaskID taskID, tmosEvents event )
{
    uint8_t i;

    tmosTask[taskID].event &= ~event;

    for(i=0; i<TASK_EVENT_MAX; i++)
    {
        if((event >> i) & 0x01)
        {
            tmosTask[taskID].timer[i] = 0;
            break;
        }
    }
    return 0;
}

void TMOS_SystemProcess( void )
{
    uint8_t i,j,tick = 0;
    tmosEvents event;

    if(toms_tick==time_stamp)
        return;

    tick = toms_tick - time_stamp;
    time_stamp = toms_tick;

    for(i = 0; i<tmos_num; i++)
    {
        if(tmosTask[i].event == 0)
        {
            continue;
        }
        else
        {
            //PRINT("task_id=%d\n", i);
            for(j=0; j<TASK_EVENT_MAX; j++)
            {
                event = 1L<<j;

                if(tmosTask[i].event & event)
                {
                    //PRINT("task_event=%d\n", j);
                    if(tmosTask[i].timer[j] > tick)
                    {
                        //PRINT("timer=%d\n", tmosTask[i].timer[j]);
                        tmosTask[i].timer[j]-=tick;
                    }
                    else if(tmosTask[i].timer[j] <= tick)
                    {
                        //PRINT("timer=%d\n", tmosTask[i].timer[j]);

                        tmosTask[i].timer[j] = 0;

                        tmosTask[i].event &= ~event;

                        tmosTask[i].TaskEventHandlerFn((tmosTaskID)i, event);
                    }
                }
            }
        }
    }
}

tmosTaskID TMOS_ProcessEventRegister( pTaskEventHandlerFn eventCb )
{
    if(tmos_num >= TASK_ID_MAX)
    {
        return INVALID_TASK_ID;
    }
    else
    {
        tmosTask[tmos_num++].TaskEventHandlerFn = eventCb;
    }
    return tmos_num - 1;
}
