#include "Service_Interval.h"
#include <stdio.h>
#include <string.h>
#include "Components.h"
/**
 * @file        Service_Interval.c
 * @brief       保养里程
 * @details     保养里程
 * @author      myliu
 * @date        2022.05.15
 * @version     V1.0
 * @copyright   myliu
 */

typedef struct
{
    Intlib_uint32_t Interval100m;  /*设定的里程间隔 0.1km */
    Intlib_uint32_t MilAfterReset; /*上次复位后里程值 0.1km */
    Intlib_uint32_t IntervalDayEnable;
    Intlib_uint32_t Interval1s;  /*设定的时间间隔 100ms */
    Intlib_uint32_t CurODO_100m; /*当前里程值 0.1km */
    Intlib_uint32_t CurTimer_1s; /*已走动时间 100ms */
} DataIntervalCalc_t;

typedef struct
{
    Intlib_uint32_t Flag;          /*存储标志 7887A55A */
    Intlib_uint32_t Interval100m;  /*设定的里程间隔 0.1km */
    Intlib_uint32_t Interval1s;    /*设定的时间间隔 1s */
    Intlib_uint32_t MilAfterReset; /*上次复位后里程值 0.1km */
    Intlib_uint32_t TotalTimer;    /*已走动时间 1s */
} DataIntervalSave_t;

static Int_PowerSts        g_PowerSts_Cbk;
static Int_ReadODO         g_ReadODO_Cbk;
static Int_EEPromWrite     g_EEPromWrite_Cbk;
static Int_EEPromRead      g_EEPromRead_Cbk;
static Intlib_uint32_t     g_TimerCnt         = 0u;
static Intlib_uint32_t     g_InitCompleteFlag = 0u;
static DataIntervalCalc_t *g_IntervalCalc;
#pragma ghs section        bss = ".myNonInitArea"
static Intlib_uint32_t     g_ServiceMil100m;
static Intlib_uint32_t     g_ServiceTimer1s;
#pragma ghs section        bss = default

/**
 * @brief 保养服务初始化函数,KL30调用
 * @param[in] pMemSpace 此功能库需要的内存空间,大小为Data_MEM_Block_Maintain,此内存需在休眠唤醒后不丢失
 * @param[in] pInitData 初始化数据,详见Maintain_Init_t
 * @param[in] pFunc     回调函数,详见Maintain_Func_t
 * @return  参数错误类型
 *
 * @warning 必须在EEPROM初始化之后调用
 *
 * @since 1.0.0
 */
void Service_Interval_KL30_Init(Intlib_uint8_t *pMemSpace, Maintain_Init_t *pInitData, Maintain_Func_t *pFunc)
{
    DataIntervalSave_t DataIntervalSave;

    g_PowerSts_Cbk    = pFunc->PowerSts_Cbk;
    g_ReadODO_Cbk     = pFunc->ReadODO_Cbk;
    g_EEPromWrite_Cbk = pFunc->EEPromWrite_Cbk;
    g_EEPromRead_Cbk  = pFunc->EEPromRead_Cbk;

    if ( pMemSpace != Intlib_NULL )
    {
        g_IntervalCalc = ( DataIntervalCalc_t * )pMemSpace;
        if ( pInitData != Intlib_NULL )
        {
            g_IntervalCalc->IntervalDayEnable = pInitData->IntervalDayEnable;

            if ( g_EEPromRead_Cbk != Intlib_NULL )
            {
                g_EEPromRead_Cbk(( Intlib_uint32_t * )&DataIntervalSave, (Intlib_uint16_t)(sizeof(DataIntervalSave_t) / 4));
                if ( DataIntervalSave.Flag != 0x7887A55A )
                {
                    g_IntervalCalc->Interval100m  = pInitData->IntervalKm * 10;
                    g_IntervalCalc->MilAfterReset = g_ReadODO_Cbk( );
                    g_IntervalCalc->Interval1s    = pInitData->IntervalDay * 24 * 60 * 60;
                    g_IntervalCalc->CurTimer_1s   = 0u;

                    DataIntervalSave.Flag          = 0x7887A55A;
                    DataIntervalSave.Interval100m  = g_IntervalCalc->Interval100m;
                    DataIntervalSave.MilAfterReset = g_IntervalCalc->MilAfterReset;
                    DataIntervalSave.Interval1s    = g_IntervalCalc->Interval1s;
                    DataIntervalSave.TotalTimer    = g_IntervalCalc->CurTimer_1s;
                    if ( g_EEPromWrite_Cbk != Intlib_NULL )
                    {
                        g_EEPromWrite_Cbk(( Intlib_uint32_t * )&DataIntervalSave, (Intlib_uint16_t)(sizeof(DataIntervalSave_t) / 4));
                    }
                }
                else
                {
                    g_IntervalCalc->Interval100m  = DataIntervalSave.Interval100m;
                    g_IntervalCalc->MilAfterReset = DataIntervalSave.MilAfterReset;
                    g_IntervalCalc->Interval1s    = DataIntervalSave.Interval1s;
                    g_IntervalCalc->CurTimer_1s   = DataIntervalSave.TotalTimer;
                }
            }
            else
            {
                g_IntervalCalc->Interval100m  = pInitData->IntervalKm * 10;
                g_IntervalCalc->MilAfterReset = g_ReadODO_Cbk( );
                g_IntervalCalc->Interval1s    = pInitData->IntervalDay * 24 * 60 * 60;
                g_IntervalCalc->CurTimer_1s   = 0u;
            }
        }
    }

    g_TimerCnt         = 0u;
    g_InitCompleteFlag = 0x78875AA5ul;
}

/**
 * @brief 保养服务初始化函数,唤醒时调用
 * @param[in] pMemSpace 此功能库需要的内存空间,大小为Data_MEM_Block_Maintain,此内存需在休眠唤醒后不丢失
 * @param[in] pFunc     回调函数,详见Maintain_Func_t
 * @return  参数错误类型
 *
 * @warning 必须在EEPROM初始化之后调用
 *
 * @since 1.0.0
 */
void Service_Interval_Wakeup_Init(Intlib_uint8_t *pMemSpace, Maintain_Func_t *pFunc)
{
    g_PowerSts_Cbk    = pFunc->PowerSts_Cbk;
    g_ReadODO_Cbk     = pFunc->ReadODO_Cbk;
    g_EEPromWrite_Cbk = pFunc->EEPromWrite_Cbk;
    g_EEPromRead_Cbk  = pFunc->EEPromRead_Cbk;

    if ( pMemSpace != Intlib_NULL )
    {
        g_IntervalCalc = ( DataIntervalCalc_t * )pMemSpace;
    }

    g_TimerCnt         = 0u;
    g_InitCompleteFlag = 0x78875AA5ul;
}

/**
 * @brief 保养里程计算函数,100ms任务调用
 *
 * @since 1.0.0
 */
void Service_Interval_Processing(void)
{
    DataIntervalSave_t DataIntervalSave;
    Intlib_uint32_t IntervalKm = 0;

    if ( g_PowerSts_Cbk( ) == Int_PowerON )
    {
        if(g_IntervalCalc != Intlib_NULL)
        {    
            g_IntervalCalc->CurODO_100m = g_ReadODO_Cbk( );
            if ( g_IntervalCalc->CurODO_100m >= g_IntervalCalc->MilAfterReset )
            {
                IntervalKm = g_IntervalCalc->CurODO_100m - g_IntervalCalc->MilAfterReset;
            }
            else
            {
                IntervalKm = 0;
            }

            if ( g_IntervalCalc->Interval100m >= IntervalKm )
            {
                g_ServiceMil100m = g_IntervalCalc->Interval100m - IntervalKm;
            }
            else
            {
                g_ServiceMil100m = 0u;
            }

            if ( g_IntervalCalc->IntervalDayEnable )
            {
                if ( g_IntervalCalc->Interval1s >= g_IntervalCalc->CurTimer_1s )
                {
                    g_ServiceTimer1s = g_IntervalCalc->Interval1s - g_IntervalCalc->CurTimer_1s;
                }
                else
                {
                    g_ServiceTimer1s = 0u;
                }
            }
        }
    }
    else
    {
        g_IntervalCalc->CurODO_100m = g_ReadODO_Cbk( );
        if ( g_IntervalCalc->CurODO_100m >= g_IntervalCalc->MilAfterReset )
        {
            IntervalKm = g_IntervalCalc->CurODO_100m - g_IntervalCalc->MilAfterReset;
        }
        else
        {
            IntervalKm = 0;
        }
        if ( g_IntervalCalc->Interval100m >= IntervalKm )
        {
            g_ServiceMil100m = g_IntervalCalc->Interval100m - IntervalKm;
        }
        else
        {
            g_ServiceMil100m = 0u;
        }
    }

    if ( g_IntervalCalc->IntervalDayEnable )
    {
        if((g_IntervalCalc->CurTimer_1s % 216000) == 0)
        {
            DataIntervalSave.Flag          = 0x7887A55A;
            DataIntervalSave.Interval100m  = g_IntervalCalc->Interval100m;
            DataIntervalSave.MilAfterReset = g_IntervalCalc->MilAfterReset;
            DataIntervalSave.Interval1s = g_IntervalCalc->Interval1s;
            DataIntervalSave.TotalTimer = g_IntervalCalc->CurTimer_1s;
            g_EEPromWrite_Cbk(( Intlib_uint32_t * )&DataIntervalSave, (Intlib_uint16_t)(sizeof(DataIntervalSave_t) / 4));
        }
    }
}

/**
 * @brief 保养天数计算函数,100ms中断调用,如不支持此功能,可不调用
 *
 * @since 1.0.0
 */
void Service_Interval_TimerISR(void)
{
    if ( g_InitCompleteFlag == 0x78875AA5ul )
    {
        if(g_IntervalCalc != Intlib_NULL)
        {
            if ( g_IntervalCalc->IntervalDayEnable ) /*配置为显示保养天数*/
            {
                g_TimerCnt++;
                if ( g_TimerCnt >= 10 )
                {
                    g_TimerCnt = 0u;
                    if ( g_IntervalCalc->CurTimer_1s <= 0xFFFFFFFFul )
                    {
                        g_IntervalCalc->CurTimer_1s++;
                    }
                }
            }
        }
    }
}

/**
 * @brief 保养天数添加睡眠时间,请参数例程使用,如不支持此功能,可不调用
 *        Sleep之后停止计时  唤醒后 把这一阶段的时间差补正回来
 *
 * @since 1.0.0
 */
void Service_Interval_TimerSleepFix(Intlib_uint32_t FixTimer)
{
    if ( g_InitCompleteFlag == 0x78875AA5ul )
    {
        if(g_IntervalCalc != Intlib_NULL)
        {
            if ( g_IntervalCalc->IntervalDayEnable )
            {
                if ( g_IntervalCalc->CurTimer_1s <= 0xFFFFFFFFul )
                {
                    g_IntervalCalc->CurTimer_1s += (FixTimer / 10);
                }
            }
        }
    }
}

/**
 * @brief 设置保养里程间隔,单位km
 * @param[in] IntervalKm 保养里程间隔,单位km
 *
 * @since 1.0.0
 */
void Service_Interval_SetKm(Intlib_uint32_t IntervalKm)
{
    DataIntervalSave_t DataIntervalSave;
    DataIntervalSave_t ReadDataIntervalSave;
    Intlib_uint8_t u8Errcount = 0;
    if (g_IntervalCalc != Intlib_NULL)
    {
        g_IntervalCalc->Interval100m = IntervalKm * 10;
        g_IntervalCalc->MilAfterReset = g_ReadODO_Cbk();

        DataIntervalSave.Flag = 0x7887A55A;
        DataIntervalSave.Interval100m = g_IntervalCalc->Interval100m;
        DataIntervalSave.MilAfterReset = g_IntervalCalc->MilAfterReset;
        if (g_IntervalCalc->IntervalDayEnable)
        {
            DataIntervalSave.Interval1s = g_IntervalCalc->Interval1s;
            DataIntervalSave.TotalTimer = g_IntervalCalc->CurTimer_1s;
        }
        else
        {
            DataIntervalSave.Interval1s = 0u;
            DataIntervalSave.TotalTimer = 0u;
        }

        while (u8Errcount < 3)
        {
            if (g_EEPromWrite_Cbk != Intlib_NULL)
            {
                g_EEPromWrite_Cbk((Intlib_uint32_t *)&DataIntervalSave, (Intlib_uint16_t)(sizeof(DataIntervalSave_t) / 4));
            }

            if (g_EEPromRead_Cbk != Intlib_NULL)
            {
                g_EEPromRead_Cbk((Intlib_uint32_t *)&ReadDataIntervalSave, (Intlib_uint16_t)(sizeof(DataIntervalSave_t) / 4));
            }

            if (memcmp(&DataIntervalSave, &ReadDataIntervalSave, sizeof(DataIntervalSave_t)) == 0)
            {
                break;
            }
            u8Errcount++;
            if(u8Errcount >= 3)
            {
                break;
            }
            Gen_TimeDelay(10 * 1000u, 50u);
        }
    }
}
Intlib_uint32_t Get_Interval_SetKm(void)
{
    Intlib_uint32_t Temp = 0;
    if(g_IntervalCalc != Intlib_NULL)
    {
        Temp = g_IntervalCalc->Interval100m;
    }
    else 
    {
        Temp = 30000u;
    }
    return Temp;
}
/**
 * @brief 设置保养天数间隔,单位天,每个月按30天计算,如不支持此功能,可不调用
 * @param[in] IntervalDay 保养天数间隔,单位天
 *
 * @since 1.0.0
 */
void Service_Interval_SetDay(Intlib_uint32_t IntervalDay)
{
    DataIntervalSave_t DataIntervalSave;

    if ( g_IntervalCalc != Intlib_NULL )
    {
        g_IntervalCalc->CurTimer_1s = 0u;
        g_IntervalCalc->Interval1s  = IntervalDay * 24 * 60 * 60;

        DataIntervalSave.Flag          = 0x7887A55A;
        DataIntervalSave.Interval100m  = g_IntervalCalc->Interval100m;
        DataIntervalSave.MilAfterReset = g_IntervalCalc->MilAfterReset;
        DataIntervalSave.Interval1s    = g_IntervalCalc->Interval1s;
        DataIntervalSave.TotalTimer    = g_IntervalCalc->CurTimer_1s;

        if ( g_EEPromWrite_Cbk != Intlib_NULL )
        {
            g_EEPromWrite_Cbk(( Intlib_uint32_t * )&DataIntervalSave, (Intlib_uint16_t)(sizeof(DataIntervalSave_t) / 4));
        }
    }
}

/**
 * @brief 获取剩余保养里程,单位100m
 * @return  剩余保养里程,单位100m
 *
 * @since 1.0.0
 */
Intlib_uint32_t Service_Interval_GetMil100m(void)
{
    if((g_ServiceMil100m % 10) > 0)
    {
        return g_ServiceMil100m + 10u;
    }
    else 
    {
        return g_ServiceMil100m;
    }
}

/**
 * @brief 获取剩余保养天数,单位天,如不支持此功能,可不调用
 * @return  剩余保养天数,单位天
 *
 * @since 1.0.0
 */
Intlib_uint32_t Service_Interval_GetDay(void)
{
    Intlib_uint32_t ServiceIntervalDay = 0u;

    ServiceIntervalDay = (g_ServiceTimer1s / 60 / 60 / 24) + 1;

    return ServiceIntervalDay;
}