/**
 * @file        Services_Mileage.c
 * @brief       里程服务函数
 * @details     里程服务函数，包括大计、小计
 * @author      myliu
 * @date        2022.05.10
 * @version     V1.0
 * @copyright   myiu
 */
#ifndef SERVICE_MILEAGE_H
#define SERVICE_MILEAGE_H

/*
Platform_32Bit
Platform_16Bit
*/

#ifdef Platform_16Bit
#define Millib_uint8_t unsigned char
#define Millib_uint16_t unsigned int
#define Millib_uint32_t unsigned long

#else
#define Millib_uint8_t unsigned char
#define Millib_uint16_t unsigned short
#define Millib_uint32_t unsigned int
#define Millib_uint64_t unsigned long long
#endif

#ifndef Millib_NULL
#define Millib_NULL (void *)0u
#endif /* NULL */

/**@enum     小计里程枚举
 * @brief    用来区分每个小计里程数
 */
typedef enum
{
    EM_TRIP_A,
    EM_TRIP_B,
    EM_TRIP_C,
    EM_TRIP_D,
    EM_TRIP_MAX,
} DataTripEnum_t;

/**@enum     EEPROM存储块枚举类型
 * @brief    用来区分EEPORM存储区域
 */
typedef enum
{
    EM_MILEAGE_BLOCK = 0u, /**< 累计里程 */
    EM_ODO_BLOCK,          /**< 总计里程 */
    EM_TRIP_BLOCK,         /**< 小计里程 */
    EM_Maintenance_BLOCK,  /**< 保养里程 */
    EM_ODOSYNC_CNT_BLOCK,  /**< 里程备份次数 */
    EM_ENGODO_BLOCK,  /**< 发动机总里程 */
} Data_EEPROM_Enum_t;

typedef void (*EEPromWrite)(Data_EEPROM_Enum_t BlockID, Millib_uint32_t u32Data[], Millib_uint16_t u16Len);
typedef Millib_uint8_t (*GetRunValid)(void);

typedef struct
{
    Millib_uint8_t (*Get_Sys_IG_Sts)(void);        /**< 获取系统电源状态，请务必填写函数名或NULL */
    Millib_uint8_t (*Get_Act_V_Speed_Valid)(void); /**< 实际车速有效位，请务必填写函数名或NULL */
    Millib_uint16_t (*Get_Act_V_Speed)(void);      /**< 实际车速，请务必填写函数名或NULL */
    Millib_uint16_t (*Get_TireSize)(void);         /**< 轮胎系数，请务必填写函数名或NULL */
    EEPromWrite EEPromWrite_Cbk;                   /**< 写EEPROM回调函数，请务必填写函数名或NULL */
} Mileage_Func_t;

typedef struct
{
    Millib_uint32_t Mileage; /**< KL30初始化时，从EEPROM读取的数据 */
} Mileage_Init_t;

typedef struct
{
    Millib_uint32_t Stamp;    /**< 在Mileage上记录的里程戳 */
    Millib_uint32_t Offset;   /**< 里程偏移量，暂不使用，预留 */
    Millib_uint32_t MaxValue; /**< 最大的总计里程，单位100m */
} ODO_Init_t;

typedef struct
{
    Millib_uint32_t EngODO;    /**< 在Mileage上记录的里程戳 */
    Millib_uint32_t MaxValue; /**< 最大的总计里程，单位100m */
} EngODO_Init_t;

typedef struct
{
    Millib_uint32_t Stamp;    /**< 在Mileage上记录的里程戳, 需要存储在EEprom */
    Millib_uint32_t Offset;   /**< 小计里程偏移量，, 需要存储在EEprom */
    Millib_uint32_t MaxValue; /**< 最大的小计里程，单位100m */
    Millib_uint8_t IsRestart; /**< 小计里程达到最大值后，是否自动从0开始，重新累计小计里程 */
} Trip_Init_t;

#define Data_MEM_Block_Mileage ((Millib_uint8_t)12u)
#define Data_MEM_Block_ODO ((Millib_uint8_t)16u)
#define Data_MEM_Block_EngODO ((Millib_uint8_t)8u)
#define Data_MEM_Block_Trip ((Millib_uint8_t)20u)
/*
total size =Data_MEM_Block_Trip*EM_TRIP_MAX
*/

/**
 * @brief 里程服务初始化，KL30调用，必须调用，否则造成空指针
 * @param[in] pMemSpace 内存空间，需要的空间大小至少大于Data_MEM_Block_Mileage，此内存需在休眠唤醒后不丢失
 * @param[in] pInitData 从EEPROM读取上次下电前累计的里程
 * @param[in] pFunc 底层发送回调函数, 详见Mileage_Func_t
 *
 * @warning 此函数必须后于EEPROM初始化，因为要读取EEPROM数据，否则每次都是从0开始
 *
 * @since 1.0.0
 */
void Data_Mileage_KL30_Init(Millib_uint8_t *pMemSpace,
                            Mileage_Init_t *pInitData, Mileage_Func_t *pFunc);
/**
 * @brief 里程服务初始化，唤醒时调用，必须调用，否则造成空指针
 * @param[in] pMemSpace 内存空间，需要的空间大小至少大于Data_MEM_Block_Mileage，此内存需在休眠唤醒后不丢失
 * @param[in] pFunc 底层发送回调函数, 详见Mileage_Func_t
 *
 * @since 1.0.0
 */
void Data_Mileage_Wakeup_Init(Millib_uint8_t *pMemSpace, Mileage_Func_t *pFunc);
/**
 * @brief 里程累计服务，在100ms中断调用
 *
 * @since 1.0.0
 */
void Data_Mileage_ISR(void);
/**
 * @brief   里程读取
 * @return  当前累计里程数，单位100m
 * @warning 此数据非总计里程，总计里程属于此里程数的一部分
 *
 * @since 1.0.0
 */
Millib_uint32_t Data_Mileage_Read(void);

/**
 * @brief   里程读取
 * @return  当前累计里程数，单位mm
 * @warning 此数据非总计里程，总计里程属于此里程数的一部分
 *
 * @since 1.0.0
 */
Millib_uint32_t Data_Mileage_Readmm(void);

/**
 * @brief   写里程
 * @param[in] NewMileage 新里程数，单位100m
 * @return  成功 - 1 失败 - 0
 * @warning 调用此函数前，需要调用Data_Mileage_Clear函数
 *
 * @since 1.0.0
 */
Millib_uint8_t Data_Mileage_Write(Millib_uint32_t NewMileage);
/**
 * @brief   清里程，出厂时使用
 * @warning 此函数包含功能：清Mileage，清ODO以及清trip，调用此函数后，需要复位后，里程才会继续走动
 *
 * @since 1.0.0
 */
void Data_Mileage_Clear(void);
/**
 * @brief   清里程，出厂时使用
 * @warning 此函数包含功能：清Mileage，清ODO以及清Trip，调用此函数，不影响里程的走动
 *
 * @since 1.0.0
 */
void Data_Mileage_Clear_GoOn(void);
/**
 * @brief   将累计的里程存入EEPROM, 10ms任务中调用
 *
 * @since 1.0.0
 */
void Data_Mileage_Write_EEPROM(void);
/**
 * @brief   获取里程库软件版本号
 * @return  版本号 1.01
 * @since 1.0.0
 */
Millib_uint8_t *Get_Data_Mileage_Version(void);

/**
 * @brief 总计里程初始化，KL30调用，必须调用，否则造成空指针
 * @param[in] pMemSpace 内存空间，需要的空间大小至少大于Data_MEM_Block_ODO，此内存需在休眠唤醒后不丢失
 * @param[in] pInitData 详见ODO_Init_t
 * @param[in] Func 写EEPROM回调函数
 *
 * @warning 在Data_Mileage_KL30_Init之后调用
 *
 * @since 1.0.0
 */
void Data_ODO_KL30_Init(Millib_uint8_t *pMemSpace, ODO_Init_t *pInitData, EEPromWrite Func);
/**
 * @brief 总计里程初始化，唤醒调用，必须调用，否则造成空指针
 * @param[in] pMemSpace 内存空间，需要的空间大小至少大于Data_MEM_Block_ODO，此内存需在休眠唤醒后不丢失
 * @param[in] Func 写EEPROM回调函数
 *
 * @warning 在Data_Mileage_Wakeup_Init之后调用
 *
 * @since 1.0.0
 */
void Data_ODO_Wakeup_Init(Millib_uint8_t *pMemSpace, EEPromWrite Func);
/**
 * @brief 总计里程计算服务，为了其他服务获取总计里程无0.1m的偏差，需要此服务函数
 *
 * @warning 在100ms任务重调用
 *
 * @since 1.0.0
 */
void Data_ODO_Processing(void);
/**
 * @brief   总计里程读取
 * @return  当前总计里程数，单位100m
 * @warning 此数据为上次Data_ODO_Clear后，到调用此函数为止，累计的Mileage，属于Mileage的一部分
 *
 * @since 1.0.0
 */
Millib_uint32_t Data_ODO_Read(void);

/**
 * @brief   清总计里程，车厂使用
 * @warning 此函数只是将总计里程的里程戳标记为当前的Mileage，不属于完全清除，如出厂请调用Data_Mileage_Clear
 *
 * @since 1.0.0
 */
void Data_ODO_Clear(void);

/**
 * @brief   总计里程偏移量读取
 * @return  当前偏移量，单位100m
 * @warning 里程备份时使用
 *
 * @since 1.0.0
 */
Millib_uint32_t Data_Offset_Read(void);

/**
 * @brief   总计里程偏移量修改
 * @return  当前偏移量，单位100m
 * @warning 里程备份时使用
 *
 * @since 1.0.0
 */
void Data_ODO_Modify(Millib_uint32_t Offset);

/**
 * @brief 发动机总计里程初始化，KL30调用，必须调用，否则造成空指针
 * @param[in] pMemSpace 内存空间，需要的空间大小至少大于Data_MEM_Block_EngODO，此内存需在休眠唤醒后不丢失
 * @param[in] pInitData 详见EngODO_Init_t
 * @param[in] pFunc1 累计发动机总里程的条件
 * @param[in] pFunc2 写EEPROM回调函数
 *
 * @warning 在Data_Mileage_KL30_Init之后调用
 *
 * @since 1.0.0
 */
void Data_EngODO_KL30_Init(Millib_uint8_t *pMemSpace, EngODO_Init_t *pInitData, GetRunValid pFunc1, EEPromWrite pFunc2);

/**
 * @brief 发动机总计里程初始化，唤醒调用，必须调用，否则造成空指针
 * @param[in] pMemSpace 内存空间，需要的空间大小至少大于Data_MEM_Block_EngODO，此内存需在休眠唤醒后不丢失
 * @param[in] pFunc1 累计发动机总里程的条件
 * @param[in] pFunc2 写EEPROM回调函数
 *
 * @warning 在Data_Mileage_Wakeup_Init之后调用
 *
 * @since 1.0.0
 */
void Data_EngODO_Wakeup_Init(Millib_uint8_t *pMemSpace, GetRunValid pFunc1, EEPromWrite pFunc2);
/**
 * @brief 发动机总计里程计算服务，为了其他服务获取总计里程无0.1m的偏差，需要此服务函数
 *
 * @warning 在100ms任务重调用
 *
 * @since 1.0.0
 */
void Data_EngODO_Processing(void);

/**
 * @brief   发动机总计里程读取
 * @return  当前总计里程数，单位100m
 * @warning 此数据为上次Data_ODO_Clear后，到调用此函数为止，累计的Mileage，属于Mileage的一部分
 *
 * @since 1.0.0
 */
Millib_uint32_t Data_EngODO_Read(void);

/**
 * @brief   发动机总计里程写
 * @return  当前发动机总计里程数，单位100m
 * @warning 此数据为上次Data_EngODO_Clear后，累计的Mileage
 *
 * @since 1.0.0
 */
void Data_EngODO_Write(Millib_uint32_t newEngODO);

/**
 * @brief   清发动机总计里程，车厂使用
 * @warning 此函数只是将发送机总计里程清除，如需工厂清除，需要调用Data_Mileage_Clear
 *
 * @since 1.0.0
 */
void Data_EngODO_Clear(void);

/**
 * @brief 小计里程初始化，KL30调用，必须调用，否则造成空指针
 * @param[in] pMemSpace 内存空间，需要的空间大小至少大于Data_MEM_Block_Trip*EM_TRIP_MAX，此内存需在休眠唤醒后不丢失
 * @param[in] pInitData Trip_Init_t
 * @param[in] TotalTrip 小计总数，（例如：1个小计， 2个小计，3个小计）
 * @param[in] Func 写EEPROM回调函数
 *
 * @warning 在Data_Mileage_KL30_Init之后调用
 *
 * @since 1.0.0
 */
void Data_Trip_KL30_Init(Millib_uint8_t *pMemSpace, Trip_Init_t *pInitData, Millib_uint8_t TotalTrip, EEPromWrite pFunc);
/**
 * @brief 小计里程初始化，唤醒调用，必须调用，否则造成空指针
 * @param[in] pMemSpace 内存空间，需要的空间大小至少大于Data_MEM_Block_Trip*EM_TRIP_MAX，此内存需在休眠唤醒后不丢失
 * @param[in] TotalTrip 小计总数，（例如：1个小计， 2个小计，3个小计）
 * @param[in] Func 写EEPROM回调函数
 *
 * @warning 在Data_Mileage_Wakeup_Init之后调用
 *
 * @since 1.0.0
 */
void Data_Trip_Wakeup_Init(Millib_uint8_t *pMemSpace, Millib_uint8_t TotalTrip, EEPromWrite pFunc);
/**
 * @brief 小计里程计算服务，为了其他服务获取小计里程无0.1m的偏差，需要此服务函数
 *
 * @warning 在100ms任务重调用
 *
 * @since 1.0.0
 */
void Data_Trip_Processing(void);
/**
 * @brief   清小计里程
 * @param[in] TripN DataTripEnum_t
 * @warning 此函数只是将小计里程的里程戳标记为当前的Mileage，不属于完全清除，如出厂请调用Data_Mileage_Clear
 *
 * @since 1.0.0
 */
void Data_Clear_Trip(DataTripEnum_t TripN);
/**
 * @brief   清小计里程
 * @warning 此函数只是将小计里程的里程戳标记为当前的Mileage，不属于完全清除，如出厂请调用Data_Mileage_Clear
 *
 * @since 1.0.0
 */
void Data_Clear_Trip_All(void);
/**
 * @brief   小计里程读取
 * @param[in] TripN DataTripEnum_t
 * @return  当前小计里程数，单位100m
 * @warning 此数据为上次Data_ODO_Clear后，到调用此函数为止，累计的Mileage，属于Mileage的一部分
 *
 * @since 1.0.0
 */
Millib_uint32_t Data_Read_Trip(DataTripEnum_t TripN);

/**
 * @brief   设置小计里程
 * @param[in] TripN DataTripEnum_t
 * @param[in] NewMileage 设置的里程数
 * @return  1 - 成功/ 0 - 失败
 * @warning 设置后会存储EEPROM
 *
 * @since 1.0.0
 */
Millib_uint8_t Data_Write_Trip(DataTripEnum_t TripN, Millib_uint32_t NewMileage);

#endif
