#include "tk_cfg.h"
const uint8_t FingerPressDebounceCNT = FINGER_PRESS_DEBOUNCE_CNT;
const uint8_t FingerReleaseDebounceCNT = FINGER_RELEASE_DEBOUNCE_CNT;
const TKCtrPara_TypeDef TKCtrPar =
{
    .releaseRate = RELEASE_RATE,
    .Coeff = FILTER_COEFF,
    .BL_TraceUpTickCnt = BASELINE_TRACE_UP_TICK_CNT,
    .BL_TraceDnTickCnt = BASELINE_TRACE_DN_TICK_CNT,
    .SLIDER_BL_TraceUpTickCnt = SLIDER_BASELINE_TRACE_UP_TICK_CNT,
    .SLIDER_BL_TraceDnTickCnt = SLIDER_BASELINE_TRACE_DN_TICK_CNT,
    .RawCompensateEn = ENABLE,
    .BL_TraceMode = BASELINE_TRACE_MODE_DEF,
    .FILTER_NOISE_DEF = 5,
#if WATER_PROOF_EN
    .FAST_SCAN_CNT_DEF = 0,
#else
    .FAST_SCAN_CNT_DEF = 100,
#endif
    .TkAcqAbandonCNT = 16,
};
const uint8_t BL_TRACE_UP_STEP[16] = {1, 1, 1, 1, 1, 1, 2, 4, 6, 8, 12, 16, 32, 64, 128, 128};
const uint8_t BL_TRACE_DN_STEP[16] = {1, 1, 1, 1, 1, 1, 2, 4, 6, 8, 12, 16, 32, 64, 128, 128};
#if TK_SLIDER_ENABLE
    const uint8_t SliderPressDebounceCNT = SLIDER_PRESS_DEBOUNCE_CNT;
    const uint8_t SliderReleaseDebounceCNT = SLIDER_RELEASE_DEBOUNCE_CNT;
#endif
#if TK_SAMP_SYNC_ENABLE
const SyncSampling_TypeDef SyncSampling =
{
    .Enable = SYNC_SENSITVITY,
    .Win = SYNC_SENSITVITY_WIN,
    .Coeff = SYNC_SENSITVITY_COEFF,
};
#endif
#if APP_TK_ENABLE
#if (TK_CHMAX == 0)
    #error "error! 触摸通道为0，需开启通道"
#endif
#if (TK_SAMP_SYNC_ENABLE == 0 && SYNC_SENSITVITY)
    #error "error! 库未开启同步采样，需替换"
#endif
#if (TK_SLIDER_ENABLE == 0 && SLIDER_OR_WHEEL_CH_TOTAL > 0)
    #error "error! 库未开启滑条换轮，需替换"
#endif
#if (TK_WATERPROOF_ENABLE == 0 && WATER_PROOF_EN)
    #error "error! 库未开启防水使能，需替换"
#endif
#if (TK_WATERDETECT_ENABLE == 0 && WATER_DETECT_EN)
    #error "error! 库未开启检水使能，需替换"
#endif
#if (TK_REF_ENABLE == 0 && REF_CH_EN)
    #error "error! 库未内部参考通道，需替换"
#endif
#if (TK_SLEEP_ENABLE == 0 && SLEEP_EN)
    #error "error! 库未开启休眠使能，需替换"
#endif
#define WIN_TRIMRATIO           60              //窗口校准比例
#define TKLIB_CONFIG            0X80                //库特殊配置    
#pragma pack(4)
typedef struct
{
    uint8_t TouchKeyChSeq[TK_CHMAX];
    uint16_t RawData[TK_CHMAX];
    uint16_t FilteredDataDBG[TK_CHMAX];
    uint16_t BaseLineDataDBG[TK_CHMAX];
    uint16_t FilteredData[TK_CHMAX];
    uint16_t BaseLineData[TK_CHMAX];
    int16_t Differ[TK_CHMAX];
    uint16_t FingerTHD[TK_CHMAX];
    uint16_t TK_AreaConfirmTickCnt[TK_CHMAX];
    uint16_t TK_KeyOutTimeLimitCnt[TK_CHMAX];
    uint8_t TK_DebounceCnt[TK_CHMAX];
    uint16_t FilteredDataMax[TK_CHMAX];
    uint16_t FilteredDataMin[TK_CHMAX];
#if WATER_PROOF_EN
    uint16_t SingleBaseLineData[TK_CHMAX];
    uint16_t SingleFilteredData[TK_CHMAX];
    uint16_t SingleAcqData[TK_CHMAX];
    uint16_t key_ratio[2][TK_CHMAX];
    uint8_t PendingTime[TK_CHMAX];
#endif
#if WATER_DETECT_EN
    int16_t Calibration[WATER_DETECT_CNT - 1];
    uint16_t DetectFilteredData[WATER_DETECT_CNT];
#endif
#if SYNC_SENSITVITY
    uint16_t raw_dat[SYNC_SENSITVITY_COEFF];
    uint16_t raw_dat2[SYNC_SENSITVITY_COEFF];
    uint32_t raw_filter[2][TK_CHMAX];
    uint16_t ref_JumpAmp[2][TK_CHMAX];
#endif
    uint8_t BaseRrimCnt[TK_CHMAX];
    uint8_t filterCount[2][TK_CHMAX];            // filterCount：滤波计数器
} TKMem_TypeDef;
#pragma pack()

#if KEY_CH_TOTAL
const uint8_t KEY_CH_TAB[] =
{
    CH_KEY0,
#if (KEY_CH_TOTAL > 1)
    CH_KEY1,
#endif
#if (KEY_CH_TOTAL > 2)
    CH_KEY2,
#endif
#if (KEY_CH_TOTAL > 3)
    CH_KEY3,
#endif
#if (KEY_CH_TOTAL > 4)
    CH_KEY4,
#endif
#if (KEY_CH_TOTAL > 5)
    CH_KEY5,
#endif
#if (KEY_CH_TOTAL > 6)
    CH_KEY6,
#endif
#if (KEY_CH_TOTAL > 7)
    CH_KEY7,
#endif
#if (KEY_CH_TOTAL > 8)
    CH_KEY8,
#endif
#if (KEY_CH_TOTAL > 9)
    CH_KEY9,
#endif
#if (KEY_CH_TOTAL > 10)
    CH_KEY10,
#endif
#if (KEY_CH_TOTAL > 11)
    CH_KEY11,
#endif
#if (KEY_CH_TOTAL > 12)
    CH_KEY12,
#endif
#if (KEY_CH_TOTAL > 13)
    CH_KEY13,
#endif
#if (KEY_CH_TOTAL > 14)
    CH_KEY14,
#endif
#if (KEY_CH_TOTAL > 15)
    CH_KEY15,
#endif
#if (KEY_CH_TOTAL > 16)
    CH_KEY16,
#endif
#if (KEY_CH_TOTAL > 17)
    CH_KEY17,
#endif
#if (KEY_CH_TOTAL > 18)
    CH_KEY18,
#endif
#if (KEY_CH_TOTAL > 19)
    CH_KEY19,
#endif
#if (KEY_CH_TOTAL > 20)
    CH_KEY20,
#endif
#if (KEY_CH_TOTAL > 21)
    CH_KEY21,
#endif
#if (KEY_CH_TOTAL > 22)
    CH_KEY22,
#endif
#if (KEY_CH_TOTAL > 23)
    CH_KEY23,
#endif
#if (KEY_CH_TOTAL > 24)
    CH_KEY24,
#endif
#if (KEY_CH_TOTAL > 25)
    CH_KEY25
#endif
};
const uint16_t KEY_THD_TAB[] =
{
    KEY0_THD,
#if (KEY_CH_TOTAL > 1)
    KEY1_THD,
#endif
#if (KEY_CH_TOTAL > 2)
    KEY2_THD,
#endif
#if (KEY_CH_TOTAL > 3)
    KEY3_THD,
#endif
#if (KEY_CH_TOTAL > 4)
    KEY4_THD,
#endif
#if (KEY_CH_TOTAL > 5)
    KEY5_THD,
#endif
#if (KEY_CH_TOTAL > 6)
    KEY6_THD,
#endif
#if (KEY_CH_TOTAL > 7)
    KEY7_THD,
#endif
#if (KEY_CH_TOTAL > 8)
    KEY8_THD,
#endif
#if (KEY_CH_TOTAL > 9)
    KEY9_THD,
#endif
#if (KEY_CH_TOTAL > 10)
    KEY10_THD,
#endif
#if (KEY_CH_TOTAL > 11)
    KEY11_THD,
#endif
#if (KEY_CH_TOTAL > 12)
    KEY12_THD,
#endif
#if (KEY_CH_TOTAL > 13)
    KEY13_THD,
#endif
#if (KEY_CH_TOTAL > 14)
    KEY14_THD,
#endif
#if (KEY_CH_TOTAL > 15)
    KEY15_THD,
#endif
#if (KEY_CH_TOTAL > 16)
    KEY16_THD,
#endif
#if (KEY_CH_TOTAL > 17)
    KEY17_THD,
#endif
#if (KEY_CH_TOTAL > 18)
    KEY18_THD,
#endif
#if (KEY_CH_TOTAL > 19)
    KEY19_THD,
#endif
#if (KEY_CH_TOTAL > 20)
    KEY20_THD,
#endif
#if (KEY_CH_TOTAL > 21)
    KEY21_THD,
#endif
#if (KEY_CH_TOTAL > 22)
    KEY22_THD,
#endif
#if (KEY_CH_TOTAL > 23)
    KEY23_THD,
#endif
#if (KEY_CH_TOTAL > 24)
    KEY24_THD,
#endif
#if (KEY_CH_TOTAL > 25)
    KEY25_THD
#endif
};
#if (SYNC_SENSITVITY)
uint16_t SyncWindow[] =
{
    2400,
#if (KEY_CH_TOTAL > 1)
    2400,
#endif
#if (KEY_CH_TOTAL > 2)
    2400,
#endif
#if (KEY_CH_TOTAL > 3)
    2400,
#endif
#if (KEY_CH_TOTAL > 4)
    2400,
#endif
#if (KEY_CH_TOTAL > 5)
    2400,
#endif
#if (KEY_CH_TOTAL > 6)
    2400,
#endif
#if (KEY_CH_TOTAL > 7)
    2400,
#endif
#if (KEY_CH_TOTAL > 8)
    2400,
#endif
#if (KEY_CH_TOTAL > 9)
    2400,
#endif
#if (KEY_CH_TOTAL > 10)
    2400,
#endif
#if (KEY_CH_TOTAL > 11)
    2400,
#endif
#if (KEY_CH_TOTAL > 12)
    2400,
#endif
#if (KEY_CH_TOTAL > 13)
    2400,
#endif
#if (KEY_CH_TOTAL > 14)
    2400,
#endif
#if (KEY_CH_TOTAL > 15)
    2400,
#endif
#if (KEY_CH_TOTAL > 16)
    2400,
#endif
#if (KEY_CH_TOTAL > 17)
    2400,
#endif
#if (KEY_CH_TOTAL > 18)
    2400,
#endif
#if (KEY_CH_TOTAL > 19)
    2400,
#endif
#if (KEY_CH_TOTAL > 20)
    2400,
#endif
#if (KEY_CH_TOTAL > 21)
    2400,
#endif
#if (KEY_CH_TOTAL > 22)
    2400,
#endif
#if (KEY_CH_TOTAL > 23)
    2400,
#endif
#if (KEY_CH_TOTAL > 24)
    2400,
#endif
#if (KEY_CH_TOTAL > 25)
    2400
#endif
};
#endif
#endif
#if (SLIDER_OR_WHEEL_CH_TOTAL > 0)
const uint8_t SLIDERORWHEEL_CH_TAB[][8] =
{
#if SLIDER_OR_WHEEL0_CH_CNT
    {
        SLIDER_OR_WHEEL0_CH0, SLIDER_OR_WHEEL0_CH1, SLIDER_OR_WHEEL0_CH2, SLIDER_OR_WHEEL0_CH3, SLIDER_OR_WHEEL0_CH4,
        SLIDER_OR_WHEEL0_CH5, SLIDER_OR_WHEEL0_CH6, SLIDER_OR_WHEEL0_CH7
    },
#endif
#if SLIDER_OR_WHEEL1_CH_CNT
    {
        SLIDER_OR_WHEEL1_CH0, SLIDER_OR_WHEEL1_CH1, SLIDER_OR_WHEEL1_CH2, SLIDER_OR_WHEEL1_CH3, SLIDER_OR_WHEEL1_CH4,
        SLIDER_OR_WHEEL1_CH5, SLIDER_OR_WHEEL1_CH6, SLIDER_OR_WHEEL1_CH7
    },
#endif
#if SLIDER_OR_WHEEL2_CH_CNT
    {
        SLIDER_OR_WHEEL2_CH0, SLIDER_OR_WHEEL2_CH1, SLIDER_OR_WHEEL2_CH2, SLIDER_OR_WHEEL2_CH3, SLIDER_OR_WHEEL2_CH4,
        SLIDER_OR_WHEEL2_CH5, SLIDER_OR_WHEEL2_CH6, SLIDER_OR_WHEEL2_CH7
    },
#endif
#if SLIDER_OR_WHEEL3_CH_CNT
    {
        SLIDER_OR_WHEEL3_CH0, SLIDER_OR_WHEEL3_CH1, SLIDER_OR_WHEEL3_CH2, SLIDER_OR_WHEEL3_CH3, SLIDER_OR_WHEEL3_CH4,
        SLIDER_OR_WHEEL3_CH5, SLIDER_OR_WHEEL3_CH6, SLIDER_OR_WHEEL3_CH7
    },
#endif
};
static uint8_t SLIDERORWHEEL_TYPE_TAB[4] =
{
#if SLIDER_OR_WHEEL0_CH_CNT
    SLIDER_OR_WHEEL0_TYPE,
#endif
#if SLIDER_OR_WHEEL1_CH_CNT
    SLIDER_OR_WHEEL1_TYPE,
#endif
#if SLIDER_OR_WHEEL2_CH_CNT
    SLIDER_OR_WHEEL2_TYPE,
#endif
#if SLIDER_OR_WHEEL3_CH_CNT
    SLIDER_OR_WHEEL3_TYPE
#endif
};

static uint16_t SLIDERORWHEEL_RESOLUTION_TAB[] =
{
#if SLIDER_OR_WHEEL0_CH_CNT
    SLIDER_OR_WHEEL0_RESOLUTION,
#endif
#if SLIDER_OR_WHEEL1_CH_CNT
    SLIDER_OR_WHEEL1_RESOLUTION,
#endif
#if SLIDER_OR_WHEEL2_CH_CNT
    SLIDER_OR_WHEEL2_RESOLUTION,
#endif
#if SLIDER_OR_WHEEL3_CH_CNT
    SLIDER_OR_WHEEL3_RESOLUTION
#endif
};
const uint16_t SLIDERORWHEEL_THD_TAB[] =
{
#if SLIDER_OR_WHEEL0_CH_CNT
    SLIDER_OR_WHEEL0_THD,
#endif
#if SLIDER_OR_WHEEL1_CH_CNT
    SLIDER_OR_WHEEL1_THD,
#endif
#if SLIDER_OR_WHEEL2_CH_CNT
    SLIDER_OR_WHEEL2_THD,
#endif
#if SLIDER_OR_WHEEL3_CH_CNT
    SLIDER_OR_WHEEL3_THD
#endif
};
#endif
#if WATER_DETECT_EN
const uint8_t WATER_DETECT_CH_TAB[] =
{
#if (WATER_DETECT_CNT > 1)
    WATER_DETECT_CH0,
#endif
#if (WATER_DETECT_CNT > 2)
    WATER_DETECT_CH1,
#endif
#if (WATER_DETECT_CNT > 3)
    WATER_DETECT_CH2,
#endif
#if (WATER_DETECT_CNT > 4)
    WATER_DETECT_CH3,
#endif
#if (WATER_DETECT_CNT > 5)
    WATER_DETECT_CH4,
#endif
#if (WATER_DETECT_CNT > 6)
    WATER_DETECT_CH5,
#endif
#if (WATER_DETECT_CNT > 7)
    WATER_DETECT_CH6,
#endif
#if (WATER_DETECT_CNT > 8)
    WATER_DETECT_CH7
#endif
};
const uint16_t CALIBRATION_VALUE_TAB[] =
{
#if (WATER_DETECT_CNT > 1)
    CALIBRATION_VALUE0,
#endif
#if (WATER_DETECT_CNT > 2)
    CALIBRATION_VALUE1,
#endif
#if (WATER_DETECT_CNT > 3)
    CALIBRATION_VALUE2,
#endif
#if (WATER_DETECT_CNT > 4)
    CALIBRATION_VALUE3,
#endif
#if (WATER_DETECT_CNT > 5)
    CALIBRATION_VALUE4,
#endif
#if (WATER_DETECT_CNT > 6)
    CALIBRATION_VALUE5,
#endif
#if (WATER_DETECT_CNT > 7)
    CALIBRATION_VALUE6,
#endif
#if (WATER_DETECT_CNT > 8)
    CALIBRATION_VALUE7
#endif
};
const uint16_t WATER_THD_TAB[] =
{
#if (WATER_DETECT_CNT > 1)
    WATER_THD0,
#endif
#if (WATER_DETECT_CNT > 2)
    WATER_THD1,
#endif
#if (WATER_DETECT_CNT > 3)
    WATER_THD2,
#endif
#if (WATER_DETECT_CNT > 4)
    WATER_THD3,
#endif
#if (WATER_DETECT_CNT > 5)
    WATER_THD4,
#endif
#if (WATER_DETECT_CNT > 6)
    WATER_THD5,
#endif
#if (WATER_DETECT_CNT > 7)
    WATER_THD6,
#endif
#if (WATER_DETECT_CNT > 8)
    WATER_THD7
#endif
};
#endif
/**
 */
static TKMem_TypeDef TK_Mem;
#if (SLEEP_EN)
    #pragma pack(4)
    LP_InitTypeDef LpHandle;
    #pragma pack()
    #if (RTC_ENABLE == 0)
        #error "error! 触摸休眠需要RTC支持，需要在app_config.h内开启RTC模块"
    #endif
    #if STOP_DEBUG
        static uint8_t sleepchs_idx;
    #endif
#endif
#if DEBUG_ENABLE && (DEBUG_MODE == 0)
static uint8_t app_log_fifo[250];
/**
 * @brief  log_Init
 * @param  初始化打印
 * @retval
 */
void log_init(void)
{
    app_log.base = app_log_fifo;
    app_log.front = app_log.rear = 0;
    app_log.sq_size = sizeof(app_log_fifo);
}
/**
 * @brief  log_putstr
 * @param  发送字符串
 * @retval
 */
void log_putchar(char byte)
{
    /*  队列已满,等待发送   */
    while (((app_log.rear + 1) % app_log.sq_size) == app_log.front)
    {
        if (app_log.app_connect == 0) // 等待超时
            return;
        __WFI();
    }
    app_log.base[app_log.rear] = byte;
    app_log.rear = (app_log.rear + 1) % app_log.sq_size;
}
#endif
/**
 * @brief  TK用户参数初始化
 * @param  None
 * @retval None
 */
void TK_UserParaInit(void)
{
#if WATER_PROOF_EN
    static TouchKeyWaterProof_TypeDef WaterProofHandle;
#endif
#if (SYNC_SENSITVITY)
    static TouchKeySync_TypeDef TouchKeySyncHanle;
#endif
    uint8_t offset = 0;
#if (SLIDER_OR_WHEEL_CH_TOTAL > 0)
    uint8_t j, k, n;
#endif
    TKCtr.KeyOutTimeLimitEn = 0;
    /*  数据指针设置        */
    TouchKeyDatas.BaseLineData = TK_Mem.BaseLineData;
    TouchKeyDatas.BaseLineDataDBG = TK_Mem.BaseLineDataDBG;
    TouchKeyDatas.Differ = TK_Mem.Differ;
    TouchKeyDatas.FilteredData = TK_Mem.FilteredData;
    TouchKeyDatas.FilteredDataDBG = TK_Mem.FilteredDataDBG;
    TouchKeyDatas.FingerTHD = TK_Mem.FingerTHD;
    TouchKeyDatas.RawData = TK_Mem.RawData;
    TouchKeyDatas.FilteredDataMax = TK_Mem.FilteredDataMax;
    TouchKeyDatas.FilteredDataMin = TK_Mem.FilteredDataMin;
    TK_TickCouter.TK_DebounceCnt = TK_Mem.TK_DebounceCnt;
    TouchKeyChInfor.TouchKeyChSeq = TK_Mem.TouchKeyChSeq;
    TK_TickCouter.TK_AreaConfirmTickCnt = TK_Mem.TK_AreaConfirmTickCnt;
    TK_TickCouter.TK_KeyOutTimeLimitCnt = TK_Mem.TK_KeyOutTimeLimitCnt;
    TouchKeyDatas.BaseRrimCnt = TK_Mem.BaseRrimCnt;
    TouchKeyDatas.filterCount[0] = TK_Mem.filterCount[0];
    TouchKeyDatas.filterCount[1] = TK_Mem.filterCount[1];
#if (WATER_PROOF_EN)
    WaterProofHandle.SingleAcqData = TK_Mem.SingleAcqData;
    WaterProofHandle.SingleFilteredData = TK_Mem.SingleFilteredData;
    WaterProofHandle.SingleBaseLineData = TK_Mem.SingleBaseLineData;
    WaterProofHandle.key_ratio[0] = TK_Mem.key_ratio[0];
    WaterProofHandle.key_ratio[1] = TK_Mem.key_ratio[1];
    WaterProofHandle.PendingTime = TK_Mem.PendingTime;
    PTouchKeyWaterProof = &WaterProofHandle;
#endif
#if (WATER_DETECT_EN)
    WaterDetectInfor.DetectFilteredData = TK_Mem.DetectFilteredData;
    WaterDetectInfor.Calibration = TK_Mem.Calibration;
#endif
#if (SYNC_SENSITVITY)
    TouchKeySyncHanle.raw_dat = TK_Mem.raw_dat;
    TouchKeySyncHanle.raw_dat2 = TK_Mem.raw_dat2;
    TouchKeySyncHanle.raw_filter[0] = TK_Mem.raw_filter[0];
    TouchKeySyncHanle.raw_filter[1] = TK_Mem.raw_filter[1];
    TouchKeySyncHanle.ref_JumpAmp[0] = TK_Mem.ref_JumpAmp[0];
    TouchKeySyncHanle.ref_JumpAmp[1] = TK_Mem.ref_JumpAmp[1];
    /*  空指针设定  */
    TouchKeySyncHanle.SyncWindow = NULL;//SyncWindow
    PTouchKeySync = &TouchKeySyncHanle;
#endif
    TouchKeyDatas.Noise_Def = NULL;//Noise_Def
    /* 触摸扫描总数量  */
    TouchKeyChInfor.TouchAcqChCnt = TK_CHMAX;
    TouchKeyChInfor.TouchAcqChCntDbg = TK_CHMAX;
#if KEY_CH_TOTAL
    /*  初始化按键  */
    TKCtr.TouchKeyChCnt = KEY_CH_TOTAL;
    for (offset = 0; offset < TKCtr.TouchKeyChCnt; offset++)
    {
        TouchKeyChInfor.TouchKeyChSeq[offset] = KEY_CH_TAB[offset];
        TouchKeyDatas.FingerTHD[offset] = KEY_THD_TAB[offset];
    }
#if KEY_OUT_MAX_TICK_CNT
    TKCtr.KeyOutTimeLimitEn |= 0X01;
    TKCtr.KeyOutTimeLimitCNT = KEY_OUT_MAX_TICK_CNT; // 长按超时时间，单位5ms
#endif
#endif
    /*  初始化防水      */
#if WATER_PROOF_EN
    ShieldInfor.WaterProof_En = WATER_PROOF_EN;
    ShieldInfor.WaterProof_Chs = WATER_SHIELD_CH;
    ShieldInfor.DusterCloth_En = DUSTERCLOTH_EN;
    ShieldInfor.DusterCloth_THD = DUSTERCLOTH_THD;
    ShieldInfor.Noise = 5;              // 保护通道数据变化量在 -NoiseTHD ~ +NoiseTHD范围之间认为数据平稳
    ShieldInfor.Timeout = 500;          // 抹布超时时间
    ShieldInfor.WaitTime = 20;
    /*  设置通道        */
    ShieldInfor.ShieldStartChIdx = offset;
    TouchKeyChInfor.TouchKeyChSeq[offset] = SHIELD_CHS;
    TouchKeyDatas.FingerTHD[offset] = DUSTERCLOTH_THD;
    offset += 1;
#else
    ShieldInfor.WaterProof_En = 0;
#endif
    /*  初始化滑轮  */
#if (SLIDER_OR_WHEEL_CH_TOTAL > 0)
#if SLIDER_OUT_MAX_TICK_CNT
    TKCtr.KeyOutTimeLimitEn |= 0X02;
    TKCtr.SliderOutTimeLimitCNT = SLIDER_OUT_MAX_TICK_CNT; // 长按超时时间，单位5ms
#endif
    SliderChInfor.SliderWheelType = SLIDERORWHEEL_TYPE_TAB;
    SliderChInfor.SliderWheelResloution = SLIDERORWHEEL_RESOLUTION_TAB;
    SliderChInfor.SliderWheelxStart = TK_CH_NONE;
    SliderChInfor.SliderWheelxStop = TK_CH_NONE;
    SliderChInfor.SliderKenable = 0;
    for (k = 0; k < SLIDER_MAX; k++)
    {
        TKCtr.SliderOrWheelPosition[k] = -1;
        SliderChInfor.SliderWheelxChCnt[k] = 0;
        if (SLIDERORWHEEL_TYPE_TAB[k] == TK_APP_WHEEL || SLIDERORWHEEL_TYPE_TAB[k] == TK_APP_SLIDER)
        {
            /*  记录开始坐标        */
            if (SliderChInfor.SliderWheelxStart == TK_CH_NONE)
            {
                SliderChInfor.SliderWheelxStart = offset;
                SliderChInfor.SliderWheelxStop = SliderChInfor.SliderWheelxStart + SLIDER_OR_WHEEL_CH_TOTAL;
            }
            SliderChInfor.SliderWheelxStartChIdx[k] = offset;
            for (j = 0; j < 8; j++)
            {
                if (SLIDERORWHEEL_CH_TAB[k][j] == TK_CH_NONE)
                {
                    break;
                }
                SliderChInfor.SliderWheelxChCnt[k]++;
            }
            n = offset;
            for (j = 0; j < SliderChInfor.SliderWheelxChCnt[k]; j++)
            {
                TouchKeyChInfor.TouchKeyChSeq[offset] = SLIDERORWHEEL_CH_TAB[k][j];
                TouchKeyDatas.FingerTHD[offset] = 0;
                SliderChInfor.SliderKenable |= (1 << SLIDERORWHEEL_CH_TAB[k][j]);
                offset += 1;
            }
            TouchKeyDatas.FingerTHD[n] = SLIDERORWHEEL_THD_TAB[k];
        }
    }
    SliderChInfor.SliderWheelxCnt = SLIDER_OR_WHEEL_CH_TOTAL;
#else
    SliderChInfor.SliderWheelxStart = TK_CH_NONE;
    SliderChInfor.SliderWheelxStop = TK_CH_NONE;
    SliderChInfor.SliderWheelxCnt = 0;
#endif
    /*  初始化内部参考  */
#if (REF_CH_EN)
    TKCtr.InsideOffset = offset;
    TouchKeyChInfor.TouchKeyChSeq[offset] = EXTERNAL_CHS;
    TouchKeyDatas.FingerTHD[offset] = REF_CH_THD;
    offset += 1;
#else
    TKCtr.InsideOffset = TK_CH_NONE;
#endif
    /*  初始化触摸检水  */
#if WATER_DETECT_EN
    WaterDetectInfor.ChsOffset = offset;
    WaterDetectInfor.ChsEnd = WaterDetectInfor.ChsOffset + WATER_DETECT_CNT;
    WaterDetectInfor.ChsCnt = WATER_DETECT_CNT;
    WaterDetectInfor.TrimRatio = 50;
    WaterDetectInfor.Swdiv = WATER_SW_DIV;
    WaterDetectInfor.Win = CONFIG_WATER_WIN;
    TouchKeyChInfor.TouchKeyChSeq[offset] = WATER_REF_CH;
    TouchKeyDatas.FingerTHD[offset] = 0;
    offset += 1;
    for (uint8_t i = 0; i < (WATER_DETECT_CNT - 1); i++)
    {
        TouchKeyChInfor.TouchKeyChSeq[offset] = WATER_DETECT_CH_TAB[i];
        TouchKeyDatas.FingerTHD[offset] = WATER_THD_TAB[i];
        WaterDetectInfor.Calibration[i] = CALIBRATION_VALUE_TAB[i];
        offset += 1;
    }
#else
    WaterDetectInfor.ChsCnt = 0;
    WaterDetectInfor.ChsOffset = TK_CH_NONE;
#endif
    /*  初始化休眠调试  */
#if (SLEEP_EN && STOP_DEBUG)
    sleepchs_idx = offset;
    TouchKeyChInfor.TouchKeyChSeq[offset] = SLEEP_CHS;
    TouchKeyDatas.FingerTHD[offset] = LP_NORMRMALDELTA;
    offset += 1;
    TouchKeyChInfor.TouchAcqChCnt -= 1;
#endif
}
/**
 * @brief  TK寄存器初始化
 * @param  None
 * @retval None
 */
void TK_RegisterCfg(void)
{
    TK_Handle.CopaMode = COPA_ENABLE;
    /*  设置补偿输出通道，只设置按键    */
#if (WATER_PROOF_EN)
    TK_Handle.CopaChs = 0;
    for (uint8_t i = 0; i < TKCtr.TouchKeyChCnt; i++)
    {
        TK_Handle.CopaChs |= (1 << TouchKeyChInfor.TouchKeyChSeq[i]);
    }
    if (ShieldInfor.WaterProof_En)
    {
        if (ShieldInfor.WaterProof_Chs < MAX_CHS)
        {
            TK_Handle.CopaChs |= (1 << ShieldInfor.WaterProof_Chs);
        }
    }
#else
    TK_Handle.CopaChs = TKCtr.TK_KeyEnable;
#endif
    TK_Handle.Kenable = TKCtr.TK_KeyEnable;
    TK_Handle.Win = CONFIG_WIN;
#if (SLIDER_OR_WHEEL_CH_TOTAL > 0)
    SliderChInfor.SliderWin = SLIDER_CONFIG_WIN;
#endif
#if CONFIG_IDAC0
    TK_Handle.TrimRatio = WIN_TRIMRATIO;
#else
    TK_Handle.TrimRatio = 0;
#endif
    /*  低功耗初始化    */
#if (SLEEP_EN)
    TKCtr.SleepEn = 1; // 允许休眠
    LpHandle.LpKchs = TKCtr.TK_KeyEnable;
    LpHandle.LpWin = (CONFIG_LP_WIN / 24) * 24;
#if ((RTC_IRQ_ENABLE == 0 || RTC_SEC_IRQ_ENABLE == 0) && STOP_DEBUG)
    /*##- Configure RTC NVIC */
    NVIC_SetPriority(RTC_IRQn, 3);
    NVIC_EnableIRQ(RTC_IRQn);
    /* Enable second interrupt */
    LL_RTC_EnableIT_SEC(RTC);
    /* Enable RTC EXTI interrupt */
    LL_EXTI_EnableIT(LL_EXTI_LINE_19);
#else
    /* Enable TK second interrupt */
    LL_RTC_EnableIT_TK_SEC(RTC);
#endif
    DBGMCU->CR &= ~(0X03 << 0);
    TKCtr.SleepTime = 0;
#else
    TKCtr.SleepEn = 0; // 禁止休眠
#endif
}
/**
 * @brief 原始数据补偿
 * @param  None
 * @retval None
 */
uint16_t TK_RawDataCompensate(uint8_t chs, uint16_t raw)
{
    chs = chs;
    return raw;
}
/**
 * @brief 数据滤波处理，开启同步采样时生效
 * @param  None
 * @retval None
 */
void FilterExDeal(uint8_t chs)
{
#if 0
    if (PTouchKeySync != NULL)
    {
        if (PTouchKeySync->ref_JumpAmp[0][chs] > TouchKeyDatas.FingerTHD[chs])
        {
            TouchKeyDatas.filterCount[0][chs] = 1;
        }
    }
#endif
}
#if WATER_PROOF_EN
const uint16_t Ratio_Tbl[][2] =
{
    {45, 90}, //KEY0
#if (KEY_CH_TOTAL > 1)
    {45, 90},
#endif
#if (KEY_CH_TOTAL > 2)
    {45, 90},
#endif
#if (KEY_CH_TOTAL > 3)
    {45, 90},
#endif
#if (KEY_CH_TOTAL > 4)
    {45, 90},
#endif
#if (KEY_CH_TOTAL > 5)
    {45, 90},
#endif
#if (KEY_CH_TOTAL > 6)
    {45, 90},
#endif
#if (KEY_CH_TOTAL > 7)
    {45, 90},
#endif
#if (KEY_CH_TOTAL > 8)
    {45, 90},
#endif
#if (KEY_CH_TOTAL > 9)
    {45, 90},
#endif
#if (KEY_CH_TOTAL > 10)
    {45, 90},
#endif
#if (KEY_CH_TOTAL > 11)
    {45, 90},
#endif
#if (KEY_CH_TOTAL > 12)
    {45, 90},
#endif
#if (KEY_CH_TOTAL > 13)
    {45, 90},
#endif
#if (KEY_CH_TOTAL > 14)
    {45, 90},
#endif
#if (KEY_CH_TOTAL > 15)
    {45, 90},
#endif
#if (KEY_CH_TOTAL > 16)
    {45, 90},
#endif
#if (KEY_CH_TOTAL > 17)
    {45, 90},
#endif
#if (KEY_CH_TOTAL > 18)
    {45, 90},
#endif
#if (KEY_CH_TOTAL > 19)
    {45, 90},
#endif
#if (KEY_CH_TOTAL > 20)
    {45, 90},
#endif
#if (KEY_CH_TOTAL > 21)
    {45, 90},
#endif
#if (KEY_CH_TOTAL > 22)
    {45, 90},
#endif
#if (KEY_CH_TOTAL > 23)
    {45, 90},
#endif
#if (KEY_CH_TOTAL > 24)
    {45, 90},
#endif
#if (KEY_CH_TOTAL > 25)
    {45, 90}
#endif
};
#endif
/**
 * @brief TK按键特殊处理
 * @param  None
 * @retval None
 */
TK_Keyflag_Type APP_TouchKeyFlagsMask(void)
{
#if (SLEEP_EN)
    TKCtr.SleepTime = 0; // 按键变化，计时清0
#endif
#if WATER_PROOF_EN
    static uint8_t last_key = TK_CH_NONE;
    static uint16_t last_Differ;
    TK_Keyflag_Type KeyFlags = 0;
    uint8_t now_key = TK_CH_NONE;
    int16_t Differ = 0;
    uint16_t ratio;
#if MAX_TRIGGER_KEY_CNT
    uint32_t num = 0;
#endif
    for (uint32_t i = 0; i < TKCtr.TouchKeyChCnt; i++)
    {
        if (TKCtr.KeyFlagsPending & (((TK_Keyflag_Type)0X01) << i))
        {
            /*  获取变化量最大的通道    */
            if (Differ < TouchKeyDatas.Differ[i])
            {
                Differ = TouchKeyDatas.Differ[i];
                now_key = i;
            }
#if MAX_TRIGGER_KEY_CNT
            num++;
#endif
        }
    }
    /*  按键触发        */
    if (now_key != TK_CH_NONE)
    {
        if (last_key != now_key)
        {
            ratio = PTouchKeyWaterProof->key_ratio[0][now_key];
#if DUSTERCLOTH_EN
            if (TouchKeyDatas.Differ[ShieldInfor.ShieldStartChIdx] > DUSTERCLOTH_THD)
            {
                ShieldInfor.WaterState = 3;
                ShieldInfor.WaterProof_Time = 500;
                return 0;
            }
#endif
            /*  水流    */
            if (ratio > Ratio_Tbl[now_key][1] && ShieldInfor.WaterProof_En)
            {
                ShieldInfor.WaterState = 2;
                log_printf("ratio type2:%d %d\r\n", now_key, ratio);
            }
            /*  覆水    */
            else if (ratio < Ratio_Tbl[now_key][0] && ShieldInfor.WaterProof_En)
            {
#if WATER_PROOF_MODE
                ShieldInfor.WaterState = 2;
#else
                ShieldInfor.WaterState = 1;
#endif
                log_printf("ratio type1:%d %d\r\n", now_key, ratio);
            }
            else
            {
                log_printf("ratio type0:%d %d\r\n", now_key, ratio);
                ShieldInfor.WaterState = 0;
#if MAX_TRIGGER_KEY_CNT
                /*  多按键同时触发更新环境值    */
                if (num > MAX_TRIGGER_KEY_CNT)
                {
                    for (uint32_t i = 0; i < TKCtr.TouchKeyChCnt; i++)
                    {
                        if (TKCtr.KeyFlagsPending & (((TK_Keyflag_Type)0X01) << i))
                            TK_UpdatBaseLineData(i);
                    }
                }
#endif
#if (SIGLE_KEY_TRIGGER)
                ShieldInfor.WaterState = 1;
#endif
            }
        }
        /*  无水状态*/
        if (ShieldInfor.WaterState == 0)
        {
            KeyFlags = TKCtr.KeyFlagsPending;
            last_key = now_key;
        }
        /*  有水状态*/
        else if (ShieldInfor.WaterState == 1)
        {
            if (last_key == TK_CH_NONE)
            {
                last_Differ = TouchKeyDatas.Differ[now_key];
                last_key = now_key;
                KeyFlags = ((TK_Keyflag_Type)0X01)  << now_key;
            }
            else
            {
                if (TKCtr.KeyFlagsPending & (((TK_Keyflag_Type)0X01) << last_key))
                {
                    Differ = last_Differ - TouchKeyDatas.Differ[last_key];
                    if (Differ > 15)
                    {
                        last_Differ = TouchKeyDatas.Differ[now_key];
                        last_key = now_key;
                        KeyFlags = ((TK_Keyflag_Type)0X01)  << now_key;
                    }
                    else
                    {
                        KeyFlags = ((TK_Keyflag_Type)0X01)  << last_key;
                    }
                }
                else
                {
                    KeyFlags = ((TK_Keyflag_Type)0X01)  << now_key;
                    last_key = now_key;
                }
            }
        }
        else
        {
            last_key = TK_CH_NONE;
        }
    }
    else
    {
        last_key = TK_CH_NONE;
    }
    return KeyFlags;
#else
#if MAX_TRIGGER_KEY_CNT
    uint32_t num = 0;
    for (uint32_t i = 0; i < TKCtr.TouchKeyChCnt; i++)
    {
        if (TKCtr.KeyFlagsPending & (((TK_Keyflag_Type)0X01) << i))
            num++;
    }
    /*  多按键同时触发更新环境值    */
    if (num > MAX_TRIGGER_KEY_CNT)
    {
        for (uint32_t i = 0; i < TKCtr.TouchKeyChCnt; i++)
        {
            if (TKCtr.KeyFlagsPending & (((TK_Keyflag_Type)0X01) << i))
                TK_UpdatBaseLineData(i);
        }
    }
#endif
#if (SIGLE_KEY_TRIGGER)
    /*  单键触发        */
    static uint8_t last_key = TK_CH_NONE;
    static uint16_t last_Differ;
    TK_Keyflag_Type KeyFlags = 0;
    uint8_t now_key = TK_CH_NONE;
    int16_t Differ = 0;
    for (uint32_t i = 0; i < TKCtr.TouchKeyChCnt; i++)
    {
        if (TKCtr.KeyFlagsPending & (((TK_Keyflag_Type)0X01) << i))
        {
            if (Differ < TouchKeyDatas.Differ[i])
            {
                Differ = TouchKeyDatas.Differ[i];
                now_key = i;
            }
        }
    }
    /*  按键触发        */
    if (now_key != TK_CH_NONE)
    {
        if (last_key == TK_CH_NONE)
        {
            last_Differ = TouchKeyDatas.Differ[now_key];
            last_key = now_key;
            KeyFlags = ((TK_Keyflag_Type)0X01)  << now_key;
        }
        else
        {
            if (TKCtr.KeyFlagsPending & (((TK_Keyflag_Type)0X01) << last_key))
            {
                Differ = last_Differ - TouchKeyDatas.Differ[last_key];
                if (Differ > 15)
                {
                    last_Differ = TouchKeyDatas.Differ[now_key];
                    last_key = now_key;
                    KeyFlags = ((TK_Keyflag_Type)0X01)  << now_key;
                }
                else
                {
                    KeyFlags = ((TK_Keyflag_Type)0X01)  << last_key;
                }
            }
            else
            {
                KeyFlags = ((TK_Keyflag_Type)0X01)  << now_key;
                last_key = now_key;
            }
        }
    }
    else
    {
        KeyFlags = 0;
    }
    return KeyFlags;
#else
    return TKCtr.KeyFlagsPending;
#endif
#endif
}
#if TK_LED_SACN
/*******************************************************************************
 * 函数名   : void TK_LedCallback(uint8_t State)
 * 描述     : LED扫描
 * 输入参数  : 无
 * 返回参数  : 无
 *******************************************************************************/
void TK_LedCallback(uint8_t State)
{
#if (TK_SMG_ENABLE && APP_SMG_ENABLE)
    TK_SMG_Scan(State);
#endif
#if (TK_LED_ENABLE && APP_LED_ENABLE)
    TK_LED_Scan(State);
#endif
}
#endif
/*******************************************************************************
 * 函数名   : uint8_t TK_ScanDone(void)
 * 描述     : 触摸本次扫描完成
 * 输入参数  : 无
 * 返回参数  :  0           无操作
                1           重新更新基线
 *******************************************************************************/
uint8_t TK_ScanDone(void)
{
#if SLEEP_EN
    if (TKCtr.SleepTime >= ENTER_SLEEPTIME && TKCtr.SleepEn == 1 && LpHandle.LpKchs)
    {
        /*  休眠前查看differ值  */
        uint8_t n;
        for (n = 0; n < TouchKeyChInfor.TouchAcqChCnt; n++)
        {
            if (TouchKeyDatas.Differ[n] > (TouchKeyDatas.FingerTHD[n] >> 3))
            {
                break;
            }
        }
        if (n == TouchKeyChInfor.TouchAcqChCnt)
        {

            return 2;
        }
    }
#endif
    return 0;
}
#if (WATER_DETECT_EN == 0)
/*******************************************************************************
 * 函数名   : uint8_t SyncSamplingCallback(uint8_t *raw_cnt,uint16_t *raw_ref)
 * 描述     : 占位，无需处理
 * 输入参数  : 无
 * 返回参数  : 无
 *******************************************************************************/
uint8_t WaterDetect_Evt(uint8_t Evt, uint8_t chs)
{
    return 0;
}
#else
/*******************************************************************************
 * 函数名   : void DeterctCallback(void)
 * 描述     : 触摸检水回调
 * 输入参数  : 无
 * 返回参数  : 无
 *******************************************************************************/
void DetectCallback(void)
{
	static uint8_t fiter_cnt[WATER_DETECT_CNT][2];
    uint16_t Water = 0;
    uint8_t i;
    uint16_t THD;
    uint8_t Offset = WaterDetectInfor.ChsOffset;//
    for (i = 1; i < WaterDetectInfor.ChsCnt; i++)
    {
        if (WaterDetectInfor.DetectFilteredData[i] > (WaterDetectInfor.DetectFilteredData[0]))
            Water = WaterDetectInfor.DetectFilteredData[i] - (WaterDetectInfor.DetectFilteredData[0]);
        else
            Water = 0;
        THD = TouchKeyDatas.FingerTHD[Offset + i];
		if(TKCtr.DetectOut & (1 << (i - 1)))
		{
			if (Water < (THD - WATER_NOISE))
			{
				fiter_cnt[i][1] = 0;
				fiter_cnt[i][0]++;
				if(fiter_cnt[i][0] > 9)
				{
					fiter_cnt[i][0] = 0;
					TKCtr.DetectOut &= ~(1 << (i - 1));
					TKCtr.KeyFlagsPending &= ~(1 << (i + WaterDetectInfor.ChsOffset));
					TKCtr.KeyFlags &= ~(1 << (i + WaterDetectInfor.ChsOffset));
				}
			}
		}
		else if (Water > (THD))
        {
			fiter_cnt[i][0] = 0;
			fiter_cnt[i][1]++;
			if(fiter_cnt[i][1] > 49)
			{
				fiter_cnt[i][1] = 0;
				TKCtr.DetectOut |= (1 << (i - 1));
				TKCtr.KeyFlagsPending |= (1 << (i + WaterDetectInfor.ChsOffset));
				TKCtr.KeyFlags |= (1 << (i + WaterDetectInfor.ChsOffset));
			}
        }
        else 
        {
            fiter_cnt[i][0] = 0;
			fiter_cnt[i][1] = 0;
        }
#if 1
        /*  比例打印，用于设置校准值    */
        uint16_t ratio = TouchKeyDatas.FilteredData[WaterDetectInfor.ChsOffset] * 1000 / TouchKeyDatas.FilteredData[WaterDetectInfor.ChsOffset + i];
        log_printf("Detect ratio[%d]:%d\r\n", (i - 1), ratio);
#endif
    }
}
#endif
/*******************************************************************************
 * 函数名   : void PrintfTask(void)
 * 描述     : 触摸打印调试接口
 * 输入参数  : 无
 * 返回参数  : 无
 *******************************************************************************/
void PrintfTask(void)
{
#if 0
    for (uint32_t i = 0; i < TKCtr.TouchKeyChCnt; i++)
    {
        log_printf("Differ[%d]:%d\r\n", i, TouchKeyDatas.Differ[i]);
    }
#endif
#if TK_TICK_USAGE && DEBUG_ENABLE
    extern uint16_t log_time;
    /*  平均每次扫描完成中断占用的时间以及数据处理占用的时间    */
    if (log_time > 1000)
    {
        uint16_t isr_ms = user_isr_tick / fac_us;
        uint16_t fsm_ms = user_fsm_tick / fac_us;
        log_printf("isr:%dus fsm:%dus\n", isr_ms, fsm_ms);
        log_time = 0;
    }
#endif
}
/*******************************************************************************
*           以下函数皆为条件编译，无需处理
*
*
*
 *******************************************************************************/
#if (SLIDER_OR_WHEEL_CH_TOTAL == 0)
/*******************************************************************************
 * 函数名   : void APP_TouchSliderOrWheelProc(void)
 * 描述     : 占位，无需处理
 * 输入参数  : 无
 * 返回参数  : 无
 *******************************************************************************/
void APP_TouchSliderOrWheelProc(void)
{

}
#endif
#if (WATER_PROOF_EN == 0)
/*******************************************************************************
 * 函数名   : uint8_t WaterProof_Evt(uint8_t Evt,uint8_t chs)
 * 描述     : 占位，无需处理
 * 输入参数  : 无
 * 返回参数  : 无
 *******************************************************************************/
uint8_t WaterProof_Evt(uint8_t Evt, uint8_t chs)
{
    return 0;
}
/*******************************************************************************
 * 函数名   : uint8_t WaterProof_Isr(uint8_t Isr)
 * 描述     : 占位，无需处理
 * 输入参数  : 无
 * 返回参数  : 无
 *******************************************************************************/
uint8_t WaterProof_Isr(uint8_t Isr)
{
    return 0;
}
#endif
#if (SYNC_SENSITVITY == 0)
/*******************************************************************************
 * 函数名   : uint8_t SyncSamplingCallback(uint8_t *raw_cnt,uint16_t *raw_ref)
 * 描述     : 占位，无需处理
 * 输入参数  : 无
 * 返回参数  : 无
 *******************************************************************************/
uint8_t SyncSamplingCallback(uint8_t *raw_cnt, uint16_t *raw_ref)
{
    return 0;
}
#endif
#if (KEY_CH_TOTAL == 0)
/*******************************************************************************
 * 函数名   : APP_TouchKeyDataProc
 * 描述     : 占位，无需处理
 * 输入参数  : 无
 * 返回参数  : 无
 *******************************************************************************/
void APP_TouchKeyDataProc(void)
{

}
/*******************************************************************************
 * 函数名   : APP_TouchKeyFlagsGenerate
 * 描述     : 占位，无需处理
 * 输入参数  : 无
 * 返回参数  : 无
 *******************************************************************************/
void APP_TouchKeyFlagsGenerate(void)
{

}
#endif
#if CONFIG_IDAC0
    void TK_CsdIdacTrim(void);
#endif
#if (PWMM_PRS_LFSRW == 0)
    #define LFSRP 0X00
#elif (PWMM_PRS_LFSRW == 1 ||PWMM_PRS_LFSRW == 2 || PWMM_PRS_LFSRW == 3 || PWMM_PRS_LFSRW == 5 || PWMM_PRS_LFSRW == 14)
    #define LFSRP 0X03
#elif (PWMM_PRS_LFSRW == 4 ||PWMM_PRS_LFSRW == 10)
    #define LFSRP 0X05
#elif (PWMM_PRS_LFSRW == 6 ||PWMM_PRS_LFSRW == 9)
    #define LFSRP 0X09
#elif (PWMM_PRS_LFSRW == 7)
    #define LFSRP 0X1D
#elif (PWMM_PRS_LFSRW == 8)
    #define LFSRP 0X11
#elif (PWMM_PRS_LFSRW == 11)
    #define LFSRP 0X53
#elif (PWMM_PRS_LFSRW == 12)
    #define LFSRP 0X1B
#elif (PWMM_PRS_LFSRW == 13)
    #define LFSRP 0X443
#elif (PWMM_PRS_LFSRW == 15)
    #define LFSRP 0X100B
#endif
/**
 * @brief  TK 初始化
 * @param  none
 *
 * @retval TK_Status
 */
void TK_LibInit(void)
{
    uint32_t CR1 = 0;
    uint32_t CR2 = 0;
    TK_Handle.Win = (TK_Handle.Win / 24) * 24;
#if (SLIDER_OR_WHEEL_CH_TOTAL > 0)
    SliderChInfor.SliderWin = (SliderChInfor.SliderWin / 24) * 24;
#endif
#if SYNC_SENSITVITY
    if (PTouchKeySync->SyncWindow != NULL)
    {
        for (uint8_t i = 0; i < TKCtr.TouchKeyChCnt; i++)
        {
            PTouchKeySync->SyncWindow[i] = (PTouchKeySync->SyncWindow[i] / 24) * 24;
        }
    }
#endif
#if WATER_DETECT_EN
    WaterDetectInfor.Win = (WaterDetectInfor.Win / 24) * 24;
#endif
    SET_BIT(RCC->APBENR2, RCC_APBENR2_TKEN);
    SET_BIT(RCC->APBRSTR2, RCC_APBRSTR2_TKRST);
    delay_us(10);
    CLEAR_BIT(RCC->APBRSTR2, RCC_APBRSTR2_TKRST);
    TK->CR1 = TK_CR1_EN;
    delay_us(10);
#if (HSI_FREQUENCE == 48000000l)
    CR1 |= TK_DIV2 << TK_CR1_DIV_Pos;      // 48M/2 = 24M
    CR1 |= TK_STDIV24 << TK_CR1_STDIV_Pos; // 48M/24 = 2M
#else
    CR1 |= TK_DIV0 << TK_CR1_DIV_Pos;     // 24M/1 = 24M
    CR1 |= TK_STDIV12 << TK_CR1_STDIV_Pos;// 24M/12 = 2M
#endif
#if SW_MODE
    CR2 |= TK_CR2_PWMM;
    CR2 |= PWMM_PRS_LFSRW << TK_CR2_LFSRW_Pos;
    TK->PRSR = PWMM_PRS_SEED << TK_PRSR_SEED_Pos | LFSRP;
#endif
#if EXTCMOD
    CR1 |= TK_CR1_EXTCMODEN;
#if LIB_09X
    SET_BIT(TK->CR2, TK_CR2_CMODTKEN);
#else
    TK->KR |= TK_KR_KEN_25;
#endif
#else
    CR1 |= TK_CR1_INTCMODEN;
#endif
    CR1 |= TK_CR1_CMPHYSEN;
    CR1 |= TK_CFT0 << TK_CR1_CFT_Pos;
    if (TK_Handle.CopaMode == 1)
        CR1 |= TK_CR1_COPAMODE;
    TK->UCR = TK_Handle.CopaChs;
#if LIB_09X
    CR1 |= CONFIG_VCC1 << TK_CR1_VCC1SEL_Pos;
#else
    CR1 |= CONFIG_VCC1 << TK_CR1_VCC1CR_Pos;
#endif
    CR1 |= (COPADATA_OUTPUT & 0X03) << TK_CR1_COPADATA_Pos;
    CR2 |= CONFIG_VREF << TK_CR2_KVREF_Pos;
    CR2 |= TK_SHORTSW_NUM_0 << TK_CR2_SHORTSW_NUM_Pos;
#if LIB_09X
    TK->STR = 0 << TK_STR_SETTIME_Pos;
#else
    TK->STR1 = 0 << TK_STR1_SETTIME_Pos;
#endif
    TK->SDR = SW_DIV;
#if (LIB_09X == 0)
    CR1 |= 0X01 << TK_CR1_MODE_Pos;
#endif
    TK->WR = TK_Handle.Win;
    TK->KR = TK_Handle.Kenable;
    CR1 |= TK_CR1_BUFFEREN;
    CR2 |= TK_CR2_MIDACEN;
    TK->CR1 |= CR1;
    TK->CR2 |= CR2;
#if WATER_PROOF_EN
    WaterDetect_Evt(4, 0);
#endif
    TK->ICR |= TK_ICR_EVTINTCLR | TK_ICR_ERRINTCLR;
    TK->IER |= TK_IER_EVTINTEN | TK_IER_ERRINTEN;
    NVIC_SetPriority(TK_IRQn, 3);
    NVIC_EnableIRQ(TK_IRQn);
#if CONFIG_IDAC0
    TK_CsdIdacTrim();
#else
    SET_BIT(TK->CR1, TK_CR1_MIDACSTEP);
    MODIFY_REG(TK->IDACR, TK_IDACR_MIDAC, 200 << TK_IDACR_MIDAC_Pos);
#endif
}
/********************************************************
**  函数名  void TK_SetSenseStart(uint32_t Chs, uint8_t TrimStep, uint8_t Midac)
**  描述    ：
**  传入    ：无
**  返回    ：无
*********************************************************/
void TK_SetSenseStart(uint32_t Chs, uint8_t TrimStep, uint8_t Midac)
{
    CLEAR_BIT(TK->CR2, TK_CR2_RSTB);
    while (READ_BIT(TK->CR2, TK_CR2_RSTB) != TK_CR2_RSTB)
    {
        ;
    }
#if CONFIG_IDAC0
    if (TrimStep)
        SET_BIT(TK->CR1, TK_CR1_MIDACSTEP);
    else
        CLEAR_BIT(TK->CR1, TK_CR1_MIDACSTEP);
    MODIFY_REG(TK->IDACR, TK_IDACR_MIDAC, Midac << TK_IDACR_MIDAC_Pos);
#endif
    TK->CSR = Chs;
    if (TK->CR1 & TK_CR1_COPAMODE)
    {
#if (COPADATA_OUTPUT == 4)
        TK->KR = Chs;
#else
        TK->KR = TK->UCR;
#endif
    }
    else
    {
        TK->KR = TK_Handle.Kenable;
    }
#if EXTCMOD
	 TK->KR |= TK_KR_KEN_25;
#endif
#if INTEREN_SWITCH
    if (Chs == 0)
        SET_BIT(TK->CR1, TK_CR1_INTEREN);
#endif
    SET_BIT(TK->CR2, TK_CR2_CTRLSOURCE);
    SET_BIT(TK->CR2, TK_CR2_START);
}
/*******************************************************************************
 * 函数名   : TK_MultiChAcqStart
 * 描述     : 开启触摸多通道采集
 * 输入参数  : 无
 * 返回参数  : 无
 *******************************************************************************/
void TK_SingleChAcqStart(uint8_t n, uint8_t type)
{
    uint32_t chs = n;
    uint8_t TrimStep, Idac;
#if WATER_PROOF_EN
    if (type == 1)
    {
        chs = TouchKeyChInfor.TouchKeyChSeq[n];
        if (chs == INSIDE_CHS)
        {
            TrimStep = (TK_Handle.RefStep & 0X01);
            Idac = TK_Handle.RefIdac[0];
            chs = 0;
        }
        else if (chs == SHIELD_CHS)
        {
            TrimStep = 1;
            Idac = TK_Handle.ShieldIdac[1];
            if (ShieldInfor.WaterProof_Chs < MAX_CHS)
            {
                chs = (1 << ShieldInfor.WaterProof_Chs);
            }
            else
            {
                chs = TKCtr.TK_KeyEnable;
            }
        }
        else
        {
            TrimStep = (PTouchKeyWaterProof->CopaOutLowTrimStep >> chs) & 0X01;
            Idac = PTouchKeyWaterProof->CopaOutLowTrimIdac[chs];
            chs = 1 << chs;
        }
    }
    else
#endif
    {
        chs = TouchKeyChInfor.TouchKeyChSeq[n];
        if (chs == INSIDE_CHS)
        {
            if (TK->SDR == SW_DIV)
            {
                TrimStep = (TK_Handle.RefStep & 0X01);
                Idac = TK_Handle.RefIdac[0];
            }
            else
            {
                TrimStep = (TK_Handle.RefStep & 0X02);
                Idac = TK_Handle.RefIdac[1];
            }
            chs = 0;
        }
#if WATER_PROOF_EN
        else if (chs == SHIELD_CHS)
        {
            TrimStep = 1;
            Idac = TK_Handle.ShieldIdac[0];
            if (ShieldInfor.WaterProof_Chs < MAX_CHS)
            {
                chs = (1 << ShieldInfor.WaterProof_Chs);
            }
            else
            {
                chs = TKCtr.TK_KeyEnable;
            }
        }
#endif
        else
        {
            TrimStep = (TK_Handle.TrimStep >> chs) & 0X01;
            Idac = TK_Handle.TrimIdac[chs];
            chs = 1 << chs;
        }
    }
#if SYNC_SENSITVITY
    if (SyncSampling.Enable == 1)
    {
        if (n < TKCtr.TouchKeyChCnt)
        {
            if (PTouchKeySync->SyncWindow != NULL)
                TK->WR = PTouchKeySync->SyncWindow[n];
            else
                TK->WR = SyncSampling.Win; // 设置窗口值
        }
    }
#endif
    TK_SetSenseStart(chs, TrimStep, Idac);
}
#if CONFIG_IDAC0
/********************************************************
**  函数名  void TK_CsdIdacTrim(void)
**  描述    ：
**  传入    ：无
**  返回    ：无
*********************************************************/
void TK_CsdIdacTrim(void)
{
    uint32_t win = TK_Handle.Win * TK_Handle.TrimRatio / 100;
    uint32_t max_win = TK_Handle.Win * (TK_Handle.TrimRatio + 5) / 100;
    uint32_t i;
    TK_Handle.TrimStep = 0;
    for (i = 0; i < MAX_CHS; i++)
    {
        if (TK_Handle.Kenable & (0X01 << i))
        {
#if (SLIDER_OR_WHEEL_CH_TOTAL > 0)
            if (SliderChInfor.SliderKenable & (0X01 << i))
            {
                CLEAR_BIT(TK->CR1, TK_CR1_COPAMODE);
                TK->SDR = SLIDER_SW_DIV;
            }
            else
#endif
            {
                if (TK_Handle.CopaMode == 1)
                    SET_BIT(TK->CR1, TK_CR1_COPAMODE);
                else
                    CLEAR_BIT(TK->CR1, TK_CR1_COPAMODE);
                TK->SDR = SW_DIV;
            }
            if (TK_CsdIdacTrimChs((0X01 << i), 0, (uint8_t *)&TK_Handle.TrimIdac[i], win, max_win) == TK_ERROR)
            {
                TK_Handle.TrimStep |= 1 << i;
                TK_CsdIdacTrimChs((0X01 << i), 1, (uint8_t *)&TK_Handle.TrimIdac[i], win, max_win);
            }
        }
    }
#if WATER_PROOF_EN
    TK->SDR = SW_DIV;
    TK_CsdIdacTrimChs(TK_Handle.CopaChs, 1, (uint8_t *)&TK_Handle.ShieldIdac[0], win, max_win);
    WaterProof_Evt(8, SW_DIV);
#endif
#if WATER_DETECT_EN
    WaterDetect_Evt(0, SW_DIV);
#endif
    win = TK_Handle.Win * (TK_Handle.TrimRatio - 15) / 100;
    max_win = TK_Handle.Win * (TK_Handle.TrimRatio - 10) / 100;
    TK->SDR = SW_DIV;
    TK_Handle.RefStep = 0;
    if (TK_CsdIdacTrimChs(0, 0, (uint8_t *)&TK_Handle.RefIdac[0], win, max_win) == TK_ERROR)
    {
        TK_Handle.RefStep |= 0X01;
        TK_CsdIdacTrimChs(0, 1, (uint8_t *)&TK_Handle.RefIdac[0], win, max_win);
    }
#if (SLIDER_OR_WHEEL_CH_TOTAL > 0)
    TK->SDR = SLIDER_SW_DIV;
    if (TK_CsdIdacTrimChs(0, 0, (uint8_t *)&TK_Handle.RefIdac[1], win, max_win) == TK_ERROR)
    {
        TK_Handle.RefStep |= 0X02;
        TK_CsdIdacTrimChs(0, 1, (uint8_t *)&TK_Handle.RefIdac[1], win, max_win);
    }
#endif
#if SLEEP_EN
    win = LpHandle.LpWin * 9 / 10;
    CLEAR_BIT(TK->CR1, TK_CR1_COPAMODE);
    MODIFY_REG(TK->CR2, TK_CR2_KVREF, CONFIG_LPVREF << TK_CR2_KVREF_Pos);
    TK->WR = LpHandle.LpWin;
    TK->SDR = CONFIG_LP_SW_DIV;
    TK_CsdIdacTrimChs(LpHandle.LpKchs, 1, (uint8_t *)&LpHandle.LpDac, win, LpHandle.LpWin);
#endif
    if (TK_Handle.CopaMode == 1)
        SET_BIT(TK->CR1, TK_CR1_COPAMODE);
    else
        CLEAR_BIT(TK->CR1, TK_CR1_COPAMODE);
    TK->WR = TK_Handle.Win;
    TK->SDR = SW_DIV;
    MODIFY_REG(TK->CR2, TK_CR2_KVREF, CONFIG_VREF << TK_CR2_KVREF_Pos);
}
#if (TKLIB_CONFIG & 0X80)
/*******************************************************************************
 * 函数名   : TK_WinDetection
 * 描述     : 占位，无需处理
 * 输入参数  : 无
 * 返回参数  : 无
 *******************************************************************************/
uint8_t TK_WinDetection(void)
{
    return 0;
}
#else
/*******************************************************************************
 * 函数名   : TK_WinDetection
 * 描述     :
 * 输入参数  : 无
 * 返回参数  : 无
 *******************************************************************************/
uint8_t TK_WinDetection(void)
{
    static uint8_t WinDetection = 0;
    static uint32_t WinDetectionIdx = 0;
    static uint16_t max_val;
    static uint16_t min_val;
    if (TK_Handle.TrimRatio < 20)
        return 0;
    uint8_t ret = 0;
    uint8_t i;
    uint16_t Win_Val;
    uint16_t min_check;
#if (WATER_PROOF_EN && (SLIDER_OR_WHEEL_CH_TOTAL > 0))
    for (i = 0; i < (TKCtr.TouchKeyChCnt + ShieldInfor.WaterProof_En + SliderChInfor.SliderWheelxCnt); i++)
#elif WATER_PROOF_EN
    for (i = 0; i < (TKCtr.TouchKeyChCnt + ShieldInfor.WaterProof_En); i++)
#elif (SLIDER_OR_WHEEL_CH_TOTAL > 0)
    for (i = 0; i < (TKCtr.TouchKeyChCnt + SliderChInfor.SliderWheelxCnt); i++)
#else
    for (i = 0; i < TKCtr.TouchKeyChCnt; i++)
#endif
    {
        if (TouchKeyChInfor.TouchKeyChSeq[i] >= MAX_CHS)
        {
            continue;
        }
#if WATER_PROOF_EN
        if (i < (TKCtr.TouchKeyChCnt + ShieldInfor.WaterProof_En))
#else
        if (i < TKCtr.TouchKeyChCnt)
#endif
        {
#if SYNC_SENSITVITY
            if (SyncSampling.Enable == 1)
            {
                if (PTouchKeySync->SyncWindow != NULL)
                    Win_Val = PTouchKeySync->SyncWindow[i];
                else
                    Win_Val = SyncSampling.Win;
                Win_Val *= SyncSampling.Coeff;
            }
            else
#endif
            {
                Win_Val = TK_Handle.Win;
            }
        }
#if (SLIDER_OR_WHEEL_CH_TOTAL > 0)
        else if (SliderChInfor.SliderWheelxStop != TK_CH_NONE)
        {
            if (i < SliderChInfor.SliderWheelxStop)
                Win_Val = SliderChInfor.SliderWin;
        }
#endif
//      min_check = Win_Val * (TK_Handle.TrimRatio - (TK_Handle.TrimRatio - 15) - 5) / 100; // 检测窗口
        min_check = Win_Val * 5 / 100;
        if (WinDetectionIdx == 0)
        {
            if (TouchKeyDatas.FilteredData[i] < min_check)
            {
                max_val = TouchKeyDatas.FilteredData[i];
                min_val = TouchKeyDatas.FilteredData[i];
                WinDetectionIdx |= 1 << i;
                WinDetection = 0;
            }
        }
        else if (WinDetectionIdx & (1 << i))
        {
            if (max_val < TouchKeyDatas.FilteredData[i])
                max_val = TouchKeyDatas.FilteredData[i];
            if (min_val > TouchKeyDatas.FilteredData[i])
                min_val = TouchKeyDatas.FilteredData[i];
            if (max_val - min_val > (TouchKeyDatas.FingerTHD[i] << 1))
            {
                WinDetectionIdx = 0;
                WinDetection = 0;
            }
            if (TouchKeyDatas.FilteredData[i] < min_check)
            {
                WinDetection++;
                if (WinDetection == 100)
                {
                    WinDetectionIdx = 0;
                    WinDetection = 0;
                    log_printf("reset tk:%d %d\n", i, TouchKeyDatas.FilteredData[i]);
                    ret = 1;
                }
            }
            else
            {
                WinDetectionIdx = 0;
                WinDetection = 0;
            }
        }
    }
    return ret;
}
#endif
#else
TK_Status TK_CsdIdacTrimChs(uint32_t chs, uint8_t TrimStep, uint8_t *idac, uint16_t win, uint16_t max_win)
{
    return TK_ERROR;
}
#endif
/*******************************************************************************
 * 函数名   : void TK_FastScanSet(void)
 * 描述     :
 * 输入参数  : 无
 * 返回参数  : 无
 *******************************************************************************/
void TK_FastScanSet(void)
{
    uint8_t i;
#if (SLIDER_OR_WHEEL_CH_TOTAL > 0)
    int16_t dif;
    uint8_t j, ofs;
    int16_t dif_total;
    uint32_t sn_bits;
#endif
#if WATER_PROOF_EN
    for (i = 0; i < TKCtr.TouchKeyChCnt + ShieldInfor.WaterProof_En; i++)
#else
    for (i = 0; i < TKCtr.TouchKeyChCnt; i++)
#endif
    {
        SetChsBits(i);
    }
#if (SLIDER_OR_WHEEL_CH_TOTAL > 0)
    if (SliderChInfor.SliderWheelxCnt == 0)
        return;
    for (i = 0; i < SLIDER_MAX; i++)
    {
        uint16_t temp;
        if (SliderChInfor.SliderWheelxChCnt[i] == 0)
            continue;
        dif_total = 0;
        sn_bits = 0;
        ofs = SliderChInfor.SliderWheelxStartChIdx[i];
        for (j = 0; j < SliderChInfor.SliderWheelxChCnt[i]; j++, ofs++)
        {
            if (TKCtr.TK_FastScanBits & (1 << ofs))
            {
                temp = TouchKeyDatas.FilteredData[ofs];
            }
            else
            {
                temp = TouchKeyDatas.RawData[ofs];
            }
            dif = temp - TouchKeyDatas.BaseLineData[ofs];
            if (dif < 0)
                dif = 0;
            dif_total += dif;
            sn_bits |= (1 << ofs);
        }
        ofs = SliderChInfor.SliderWheelxStartChIdx[i];
        if ((TKCtr.TK_FastScanBits & sn_bits) == sn_bits)
        {
            if (dif_total < (TouchKeyDatas.FingerTHD[ofs] >> 1))
            {
                TKCtr.TK_FastScanBits &= ~sn_bits;
            }
        }
        else
        {
            if (dif_total > TouchKeyDatas.FingerTHD[ofs])
            {
                TKCtr.TK_FastScanBits |= sn_bits;
            }
        }
    }
#endif
}
/*******************************************************************************
 * 函数名   : uint8_t TK_GetNextChPartial(uint8_t idx)
 * 描述     :
 * 输入参数  : 无
 * 返回参数  : 无
 *******************************************************************************/
uint8_t TK_GetNextChPartial(uint8_t idx)
{
    if (idx == 0XFF)
    {
        return 0XFF;
    }
#if REF_CH_EN
    else if (TKCtr.InsideOffset == idx)
    {
        CLEAR_BIT(TK->CR1, TK_CR1_COPAMODE);
        TK->WR = 6000;
        TK->SDR = SW_DIV;
        RawDatasAcquisitionState = STATE_REF_CH_ACQING;
        return idx;
    }
#endif
#if WATER_DETECT_EN
    else if (WaterDetectInfor.ChsOffset == idx)
    {
        CLEAR_BIT(TK->CR1, TK_CR1_COPAMODE);
        TK->WR = WaterDetectInfor.Win;
        TK->SDR = WaterDetectInfor.Swdiv;
        RawDatasAcquisitionState = STATE_DETECT_CH_ACQING;
        return idx;
    }
#endif
#if WATER_PROOF_EN
    else if (idx < (TKCtr.TouchKeyChCnt + ShieldInfor.WaterProof_En))
#else
    else if (idx < TKCtr.TouchKeyChCnt)
#endif
    {
        if (TK_Handle.CopaMode == 1)
            SET_BIT(TK->CR1, TK_CR1_COPAMODE);
        else
            CLEAR_BIT(TK->CR1, TK_CR1_COPAMODE);
        TK->WR = TK_Handle.Win;
        TK->SDR = SW_DIV;
        RawDatasAcquisitionState = STATE_MULTI_CH_ACQING;
        return idx;
    }
#if (SLIDER_OR_WHEEL_CH_TOTAL > 0)
    else
    {
        CLEAR_BIT(TK->CR1, TK_CR1_COPAMODE);
        TK->WR = SliderChInfor.SliderWin;
        TK->SDR = SLIDER_SW_DIV;
        RawDatasAcquisitionState = STATE_SLIDER_CH_ACQING;
        return idx;
    }
#else
    return 0XFF;
#endif
}
/*******************************************************************************
 * 函数名   : uint8_t TK_GetNextChPartial(uint8_t idx)
 * 描述     :
 * 输入参数  : 无
 * 返回参数  : 无
 *******************************************************************************/
void InnerDifCalc(void)
{
#if REF_CH_EN
    uint8_t n = TKCtr.InsideOffset;
    TKCtr.InsideDif = Inside_Dif(TouchKeyDatas.FilteredData[n], &TouchKeyDatas.BaseLineData[n]);
    if (TK_TickCouter.TK_AreaConfirmTickCnt[n] == 0)
    {
        TK_TickCouter.TK_AreaConfirmTickCnt[n] = 2;
        Inside_In(TouchKeyDatas.FilteredData[n]);
    }
#endif
#if WATER_PROOF_EN
    WaterProof_Evt(1, 0);
#endif
}
/*******************************************************************************
 * 函数名   : TK_Filtering
 * 描述     :
 * 输入参数  : 无
 * 返回参数  : 无
 *******************************************************************************/
void TK_Filtering(void)
{
    uint32_t i;
    for (i = 0; i < TouchKeyChInfor.TouchAcqChCnt; i++)
    {
#if REF_CH_EN
        if (i == TKCtr.InsideOffset)
            TouchKeyDatas.FilteredData[i] = (TouchKeyDatas.FilteredData[i] * 6 / 10 + TouchKeyDatas.RawData[i] * 4 / 10);
        else
#endif
        {
            FilterExDeal(i);
            TouchKeyDatas.FilteredData[i] = IIR_Filter(TouchKeyDatas.FilteredData[i], TouchKeyDatas.RawData[i], i, 0);
#if WATER_PROOF_EN
            WaterProof_Evt(3, i);
#endif
        }
    }
#if WATER_DETECT_EN
    WaterDetect_Evt(2, 0);
#endif
}
/*******************************************************************************
 * 函数名   : TK_TimerHandler
 * 描述     : 定时器回调,使用SysTick时基
 * 输入参数  : 无
 * 返回参数  : 无
 *******************************************************************************/
void TK_TimerHandler(uint8_t ms)
{
    static uint8_t ms_cnt;
    ms_cnt += ms;
    if (ms_cnt >= 5)
    {
        ms_cnt = 0;
        for (uint8_t i = 0; i < TouchKeyChInfor.TouchAcqChCnt; i++)
        {
            if (TK_TickCouter.TK_AreaConfirmTickCnt[i])
            {
                TK_TickCouter.TK_AreaConfirmTickCnt[i]--;
            }
            if (TK_TickCouter.TK_KeyOutTimeLimitCnt[i])
            {
                TK_TickCouter.TK_KeyOutTimeLimitCnt[i]--;
            }
#if WATER_PROOF_EN
            if (ShieldInfor.WaterProof_En)
            {
                if (PTouchKeyWaterProof->PendingTime[i])
                    PTouchKeyWaterProof->PendingTime[i]--;
            }
#endif
        }
#if (SLIDER_OR_WHEEL_CH_TOTAL > 0)
        for (uint8_t i = 0; i < SLIDER_MAX; i++)
        {
            if (SliderChInfor.TK_WheelConfirmTickCnt[i])
            {
                SliderChInfor.TK_WheelConfirmTickCnt[i]--;
            }
        }
#endif
#if SLEEP_EN
        if (TKCtr.SleepEn == 1)
            TKCtr.SleepTime++;
        else
            TKCtr.SleepTime = 0;
#endif
    }
    if (app_log.app_connect)
        app_log.app_connect--;
#if WATER_PROOF_EN
    if (ShieldInfor.WaterProof_Time)
    {
        ShieldInfor.WaterProof_Time--;
        if (ShieldInfor.WaterProof_Time == 0)
            ShieldInfor.WaterState = 0;
    }
#endif
}
#endif
#if (REF_CH_EN && APP_TK_ENABLE)
#define INSIDE_CNT 50
static uint16_t Inside_Raw[INSIDE_CNT];
static uint16_t Inside_Cnt;
/**
 * @brief 内部参考通道数据初始化
 * @param  None
 * @retval None
 */
void Inside_Init(uint16_t raw)
{
    for (uint32_t i = 0; i < INSIDE_CNT; i++)
    {
        Inside_Raw[i] = raw;
    }
}
/**
 * @brief 内部参考通道入队
 * @param  None
 * @retval None
 */
void Inside_In(uint16_t raw)
{
    Inside_Cnt++;
    if (Inside_Cnt >= INSIDE_CNT)
        Inside_Cnt = 0;
    Inside_Raw[Inside_Cnt] = raw;
}
/**
 * @brief 内部参考通道出队
 * @param  None
 * @retval None
 */
uint16_t Inside_Dif(uint16_t raw, uint16_t *base)
{
    uint32_t max = 0;
    uint32_t del;
    for (uint32_t i = 0; i < INSIDE_CNT; i++)
    {
        if (raw > Inside_Raw[i])
            del = raw - Inside_Raw[i];
        else
            del = Inside_Raw[i] - raw;
        if (del > max)
        {
            max = del;
            *base = Inside_Raw[i];
        }
    }
    return max;
}
/**
 * @brief 内部参考通道差值比较
 * @param  None
 * @retval None
 */
void InsideTrigger(uint16_t InsideDif, uint16_t Thd)
{
    if (InsideDif > Thd) // 数据变化量超过门限值
    {
        for (uint32_t i = 0; i < TKCtr.TouchKeyChCnt; i++)
        {
            if (TKCtr.KeyFlagsPending & (((TK_Keyflag_Type)0X01) << i))
                TK_UpdatBaseLineData(i);
        }
    }
}
#endif
#if (SLEEP_EN && APP_TK_ENABLE)
/**
 * @brief 触摸配置休眠
 * @param  None
 * @retval None
 */
static uint8_t LpInit = 0;
static TK_Status TK_LpInit(void)
{
#define st_clk 2 // ST时钟为2M，则2个计数为1us
    if (READ_BIT(TK->CR2, TK_CR2_START))
        return TK_BUSY;
    /*  清空计数值  */
    CLEAR_BIT(TK->CR2, TK_CR2_RSTB);
    while (READ_BIT(TK->CR2, TK_CR2_RSTB) != TK_CR2_RSTB)
    {
        ;
    }
    TK->CR1 &= ~TK_CR1_EN;
    TK->CSR = (uint32_t)LpHandle.LpKchs;
    TK->KR = (uint32_t)LpHandle.LpKchs;
    if (LpInit == 0)
    {
        CLEAR_BIT(TK->CR1, TK_CR1_COPAMODE);
        MODIFY_REG(TK->CR2, TK_CR2_KVREF, CONFIG_LPVREF << TK_CR2_KVREF_Pos);
#if CONFIG_IDAC0
        SET_BIT(TK->CR1, TK_CR1_MIDACSTEP);
        MODIFY_REG(TK->IDACR, TK_IDACR_MIDAC, LpHandle.LpDac << TK_IDACR_MIDAC_Pos);
#endif
        TK->SDR = CONFIG_LP_SW_DIV;
        TK->WR = LpHandle.LpWin;
        SET_BIT(TK->CR2, TK_CR2_LPABNORMAL);
        TK->LPTR = 50 * st_clk;
        TK->LPDR = LpHandle.NormalDelta << TK_LPDR_ABNORMALDELTA_Pos | LpHandle.NormalDelta << TK_LPDR_NORMALDELTA_Pos;
    }
    LpInit = 1;
    TK->CDR = LpHandle.Baseline;
    SET_BIT(TK->CR2, TK_CR2_CTRLSOURCE);
    SET_BIT(TK->CR2, TK_CR2_LPEN);
    TK_Handle.LpIsr = 0;
    return TK_OK;
}
/**
 * @brief 触摸退出休眠
 * @param  None
 * @retval None
 */
static void TK_LpDeInit(void)
{
    LpInit = 0;
    TK->CR1 |= TK_CR1_EN;
    TK->SDR = SW_DIV;
    TK->WR = TK_Handle.Win;
    MODIFY_REG(TK->CR2, TK_CR2_KVREF, CONFIG_VREF << TK_CR2_KVREF_Pos);
    TK->KR = (uint32_t)LpHandle.LpKchs;
    TK->CSR = 0;
    if (TK_Handle.CopaMode == 1)
        SET_BIT(TK->CR1, TK_CR1_COPAMODE);
    else
        CLEAR_BIT(TK->CR1, TK_CR1_COPAMODE);
    CLEAR_BIT(TK->CR2, TK_CR2_LPEN);
}
/*******************************************************************************
 * 函数名   : PWR_EnterStopMode
 * 描述     : 执行STOP模式
 * 输入参数  : 无
 * 返回参数  : 无
 *******************************************************************************/
static void PWR_EnterStopMode(void)
{
#if STOP_DEBUG
    /* Request Wait For Interrupt */
    __WFI();
#else
#define WakeUpHsiEnableTime LL_PWR_WAKEUP_HSION_IMMEDIATE
#define SramRetentionVolt LL_PWR_SRAM_RETENTION_VOLT_STOP
#define FlashDelay LL_PWR_WAKEUP_FLASH_DELAY_5US
    MODIFY_REG(PWR->CR1, (PWR_CR1_HSION_CTRL | PWR_CR1_SRAM_RETV_CTRL | PWR_CR1_FLS_SLPTIME),
               (WakeUpHsiEnableTime | SramRetentionVolt | FlashDelay));
    /* Config Regulator */
    MODIFY_REG(PWR->CR1, PWR_CR1_LPR, LL_PWR_LPR_MODE_LPR);
    /* Set SLEEPDEEP bit of Cortex System Control Register */
    SET_BIT(SCB->SCR, ((uint32_t)SCB_SCR_SLEEPDEEP_Msk));
    /* Request Wait For Event */
    __SEV();
    __WFE();
    __WFE();
    /* Reset SLEEPDEEP bit of Cortex System Control Register */
    CLEAR_BIT(SCB->SCR, ((uint32_t)SCB_SCR_SLEEPDEEP_Msk));
#endif
}
#if (RTC_IRQ_ENABLE && RTC_SEC_IRQ_ENABLE || STOP_DEBUG)
/*******************************************************************************
 * 函数名   : void TK_SetSenseStart_LP(void)
 * 描述     : 调试模式手动启动转换
 * 输入参数  : 无
 * 返回参数  : 无
 *******************************************************************************/
static void TK_SetSenseStart_LP(void)
{
    TK->CR1 |= TK_CR1_EN;
    /*  正常转换        */
    CLEAR_BIT(TK->CR2, TK_CR2_RSTB);
    while (READ_BIT(TK->CR2, TK_CR2_RSTB) != TK_CR2_RSTB)
    {
        ;
    }
    TK->WR = LpHandle.LpWin;
    TK->SDR = CONFIG_LP_SW_DIV;
    TK->CSR = (uint32_t)LpHandle.LpKchs;
    TK->KR = (uint32_t)LpHandle.LpKchs;
    SET_BIT(TK->CR2, TK_CR2_CTRLSOURCE);
    SET_BIT(TK->CR2, TK_CR2_START);
    TK_Handle.LpIsr = 0;
    while (TK_Handle.LpIsr == 0)
    {
        /* Request Wait For Interrupt */
        __WFI();
    }
}
#endif
/**
 * @brief  获取唤醒通道
 * @param  none
 *
 * @retval
 */
static uint32_t TK_GetWakeChs(void)
{
    uint32_t WakeChs = 0;
    LpHandle.WakeDelay = 1;
    TKCtr.TK_state = TK_EXITSLEEP;
    RawDatasAcquisitionState = STATE_IDLE;
    while (1)
    {
        /*  空闲状态启动转换        */
        if (RawDatasAcquisitionState == STATE_IDLE)
        {
            TK_MultiChAcqStart();
        }
        /*  多通道转换完成      */
        else if (RawDatasAcquisitionState == STATE_MULTI_CH_ACQ_DONE)
        {
            uint8_t i;
            uint16_t Differ;
            /*  比较通道数据，看下是哪个通道唤醒的  */
            // 按键唤醒
            for (i = 0; i < TKCtr.TouchKeyChCnt; i++)
            {
                /*  */
                if (TouchKeyDatas.RawData[i] > TouchKeyDatas.BaseLineData[i])
                {
                    Differ = TouchKeyDatas.RawData[i] - TouchKeyDatas.BaseLineData[i];
                    TouchKeyDatas.BaseLineData[i]++;
                }
                else if (TouchKeyDatas.RawData[i] < TouchKeyDatas.BaseLineData[i])
                {
                    Differ = TouchKeyDatas.BaseLineData[i] - TouchKeyDatas.RawData[i];
                    TouchKeyDatas.BaseLineData[i]--;
                }
                else
                {
                    Differ = 0;
                }
                if (Differ >= (TouchKeyDatas.FingerTHD[i] >> 1))
                {
                    WakeChs |= (0X01 << i);
                }
            }
#if (SLIDER_OR_WHEEL_CH_TOTAL > 0)
            // 滑条唤醒
            uint8_t n, Offset, max, max_l, max_r;
            uint16_t del_val[8] = {0};
            uint16_t max_val, sum;
            for (n = 0; n < SLIDER_MAX; n++)
            {
                if (SliderChInfor.SliderWheelxChCnt[n] != 0)
                {
                    Offset = SliderChInfor.SliderWheelxStartChIdx[n];
                    for (i = Offset, max = 0, max_val = 0; i < SliderChInfor.SliderWheelxChCnt[n] + Offset;
                            i++)
                    {
                        if (TouchKeyDatas.RawData[i] > TouchKeyDatas.BaseLineData[i])
                        {
                            Differ = TouchKeyDatas.RawData[i] - TouchKeyDatas.BaseLineData[i];
                            TouchKeyDatas.BaseLineData[i]++;
                        }
                        else if (TouchKeyDatas.RawData[i] < TouchKeyDatas.BaseLineData[i])
                        {
                            Differ = TouchKeyDatas.BaseLineData[i] - TouchKeyDatas.RawData[i];
                            TouchKeyDatas.BaseLineData[i]--;
                        }
                        else
                        {
                            Differ = 0;
                        }
                        if (Differ > 0)
                            del_val[i - Offset] = Differ;
                        else
                            del_val[i - Offset] = 0;
                        if (del_val[i - Offset] > max_val)
                        {
                            max_val = del_val[i - Offset];
                            max = i - Offset;
                        }
                    }
                    if (max > 0)
                        max_l = max - 1;
                    else
                        max_l = SliderChInfor.SliderWheelxChCnt[n] - 1;
                    if (max < (SliderChInfor.SliderWheelxChCnt[n] - 1))
                        max_r = max + 1;
                    else
                        max_r = 0;
                    sum = del_val[max_r] + del_val[max] + del_val[max_l];
                    if (sum >= (TouchKeyDatas.FingerTHD[Offset] >> 1))
                    {
                        WakeChs |= (0X01 << Offset);
                    }
                }
            }
#endif
            break;
        }
        /*  进入SLEEP模式，如果不进入休眠则需要添加volatile，不然RawDatasAcquisitionState访问会异常*/
        else
        {
            __WFI();
        }
    }
	TK_Filtering();
    TKCtr.TK_state = TK_ENTERSLEEP;
    return WakeChs;
}
/*******************************************************************************
 * 函数名   : TK_EnterStop
 * 描述     : 进入低功耗模式
 * 输入参数  : 无
 * 返回参数  : 无
 *******************************************************************************/
void TK_EnterStop(void)
{
	LL_RTC_InitTypeDef rtc_initstruct;
#if ((RTC_IRQ_ENABLE && RTC_SEC_IRQ_ENABLE) || STOP_DEBUG)
    uint8_t base_up = 0;
    uint8_t base_dn = 0;
#endif
	uint16_t base_tick = 0;
	uint8_t Wake_Cnt = 0;
    uint16_t Differ;
	LpHandle.Baseline = 0;
    /*  开始执行修眠    */
    EnterStop_Callback();
    do
    {
        if (TK_Handle.LpCdr == 0)
        {
            LpHandle.NormalDelta = 0;
        }
        else
        {
#if (RTC_IRQ_ENABLE && RTC_SEC_IRQ_ENABLE)
            LpHandle.NormalDelta = 0;
#else
			if(Wake_Cnt)
			{
				LpHandle.NormalDelta = 0;
			}
			else
			{
				LpHandle.NormalDelta = LP_NORMRMALDELTA;
			}
#endif
        }
        if (TK_LpInit() == TK_OK)
        {
            PWR_EnterStopMode();
#if ((RTC_IRQ_ENABLE && RTC_SEC_IRQ_ENABLE) || STOP_DEBUG)
            TK_SetSenseStart_LP();
#if STOP_DEBUG // 调试模式更新数据
            TouchKeyDatas.FilteredDataDBG[sleepchs_idx] = TK_Handle.LpCdr;
            TouchKeyDatas.BaseLineDataDBG[sleepchs_idx] = LpHandle.Baseline;
            DebugDataUpdate();
#endif
#endif
            if (TK_Handle.LpIsr != 0) // 触摸唤醒
            {
                if (TK_Handle.LpCdr > LpHandle.Baseline)
                    Differ = TK_Handle.LpCdr - LpHandle.Baseline;
                else
                    Differ = LpHandle.Baseline - TK_Handle.LpCdr;
				/*	第一次进入休眠	*/
				if(LpHandle.Baseline == 0)
				{
					Wake_Cnt = 0;
					base_tick = 1000;
				}
				/*	获取变化量	*/
				else if (Differ >= LP_NORMRMALDELTA)
				{
#if CONFIG_LP_FITER_CNT > 1
					/*	第一次唤醒快速扫描	*/
					if(Wake_Cnt == 0)
					{
						rtc_initstruct.AsynchPrescaler = LSI_VALUE * (CONFIG_LP_FITER_TICK) / 1000 - 1;
						rtc_initstruct.OutPutSource = LL_RTC_CALIB_OUTPUT_NONE;
						if (LL_RTC_Init(RTC, &rtc_initstruct) != SUCCESS)
						{
							;
						}
					}
#endif
					Wake_Cnt++;
				}
				else
				{
#if CONFIG_LP_FITER_CNT > 1
					/*	误唤醒恢复间隔	*/
					if(Wake_Cnt)
					{
						rtc_initstruct.AsynchPrescaler = LSI_VALUE * (RTC_SEC_TIME) / 1000 - 1;
						rtc_initstruct.OutPutSource = LL_RTC_CALIB_OUTPUT_NONE;
						if (LL_RTC_Init(RTC, &rtc_initstruct) != SUCCESS)
						{
							;
						}
					}
#endif
					Wake_Cnt = 0;
				}
                if (Wake_Cnt >= CONFIG_LP_FITER_CNT || base_tick > 500)
                {
#if CONFIG_LP_FITER_CNT > 1
					/*	恢复RTC时间	*/
					if(Wake_Cnt)
					{
						rtc_initstruct.AsynchPrescaler = LSI_VALUE * (RTC_SEC_TIME) / 1000 - 1;
						rtc_initstruct.OutPutSource = LL_RTC_CALIB_OUTPUT_NONE;
						if (LL_RTC_Init(RTC, &rtc_initstruct) != SUCCESS)
						{
							;
						}
					}
#endif
					Wake_Cnt = 0;
					base_tick = 0;
                    TK_LpDeInit();
                    log_printf("LpCdr:%d %d\n", TK_Handle.LpCdr, LpHandle.Baseline);
                    LpHandle.Baseline = TK_Handle.LpCdr;
                    LpHandle.WakeChs = TK_GetWakeChs();
                    if (LpHandle.WakeChs != 0)
                    {
                        TKCtr.TK_state = TK_GO;
                    }
                    log_printf("WakeChs:%X\n", LpHandle.WakeChs);
                }
                else if(Wake_Cnt == 0)
                {
                    base_tick++;
#if ((RTC_IRQ_ENABLE && RTC_SEC_IRQ_ENABLE) || STOP_DEBUG)
                    /*  更新并联通道基线        */
                    if (LpHandle.Baseline < TK_Handle.LpCdr)
                    {
                        base_up++;
                        base_dn = 0;
                        if (base_up > 14)
                        {
                            base_up = 0;
                            LpHandle.Baseline++;
                        }
                    }
                    else if (LpHandle.Baseline > TK_Handle.LpCdr)
                    {
                        base_dn++;
                        base_up = 0;
                        if (base_dn > 4)
                        {
                            base_dn = 0;
                            LpHandle.Baseline--;
                        }
                    }
#endif
                }
            }
            LoopStop_Callback();
        }
        else
        {
            TKCtr.TK_state = TK_GO;
        }
        if (app_log.app_connect)
            app_log.app_connect--;
    }
    while (TKCtr.TK_state != TK_GO);
    TK_LpDeInit();
    ExitStop_Callback();
}
/**
 * @brief 进入休眠调用函数
 * @param  None
 * @retval None
 */
void EnterStop_Callback(void)
{
    log_printf("EnterStop_Callback\n");
    /* Disable SysTick Interrupt */
    CLEAR_BIT(SysTick->CTRL, SysTick_CTRL_TICKINT_Msk);
    EXTI_Flag = 0;
#if APP_ADC_ENABLE
    /*  等待序列转换完成*/
    while (LL_ADC_REG_IsConversionOngoing(ADC1) == 1)
    {
        ;
    }
    LL_ADC_Disable(ADC1);
    MODIFY_REG(ADC->CCR, ADC_CCR_VREFBUF_EN | ADC_CCR_VREFBUF_SEL, 0);
#endif
#if (APP_TIM1_ENABLE || APP_TIM1_PWM_ENABLE)
    LL_TIM_DeInit(TIM1);
#endif
#if (APP_TIM14_ENABLE || APP_TIM14_PWM_ENABLE)
    LL_TIM_DeInit(TIM14);
#endif
#if APP_SMG_ENABLE
    SMG_Sleep();
#endif
}
/**
 * @brief 退出休眠调用函数
 * @param  None
 * @retval None
 */
void ExitStop_Callback(void)
{
    log_printf("ExitStop_Callback\n");
    /*  触摸唤醒        */
    if (LpHandle.WakeChs != 0)
    {
        TKCtr.SleepTime = 0;
    }
    /*  外部中断唤醒标志位  */
    if (EXTI_Flag != 0)
    {
        TKCtr.SleepTime = 0;
    }
#if APP_SMG_ENABLE
    SMG_Wake();
#endif
#if APP_ADC_ENABLE
    ADC_Init();
#endif
#if APP_TIM1_ENABLE
    /*  定时器1初始化   */
    TIM1_Init();
#elif APP_TIM1_PWM_ENABLE
    /*  定时器1用做PWM输出初始化    */
    TIM1_PWM_Init();
#endif
#if APP_TIM14_ENABLE
    /*  定时器14初始化  */
    TIM14_Init();
#elif APP_TIM14_PWM_ENABLE
    /*  定时器14用做PWM输出初始化   */
    TIM14_PWM_Init();
#endif
    /* Enable SysTick Interrupt */
    SET_BIT(SysTick->CTRL, SysTick_CTRL_TICKINT_Msk);
}
/**
 * @brief 定时唤醒回调函数
 * @param  None
 * @retval None
 */
void LoopStop_Callback(void)
{
    /*  外部中断唤醒标志位,退出休眠 */
    if (EXTI_Flag != 0)
    {
        TKCtr.TK_state = TK_GO;
    }
#if APP_IWDG_ENABLE
    /* 喂看门狗 */
    LL_IWDG_ReloadCounter(IWDG);
#endif
}
#endif
#if DEBUG_ENABLE
#include <stdarg.h>
// 将整数转换为字符串并输出（支持负数）
static void log_num(int num, uint8_t dec)
{
    char buffer[16]; // 缓冲区大小足够处理 -32768 到 32767
    uint8_t i = 0;
    uint8_t is_negative = 0;
    uint8_t data;
    // 处理 0 的特殊情况
    if (num == 0)
    {
        log_putchar('0');
        return;
    }
    if (num < 0 && dec == 10)
    {
        is_negative = 1;
        num = -num;
    }
    // 从低位到高位生成数字
    while (num > 0)
    {
        data = (num % dec);
        if (data <= 9)
            buffer[i++] = data + '0';
        else
            buffer[i++] = (data - 10) + 'A';
        num /= dec;
    }
    // 输出负数符号
    if (is_negative)
    {
        log_putchar('-');
    }
    // 反向输出数字
    while (i > 0)
    {
        log_putchar(buffer[--i]);
    }
}

// 简化版 printf
void log_printf(const char *fmt, ...)
{
    va_list args;
    va_start(args, fmt);
    while (*fmt)
    {
        if (*fmt == '%')
        {
            fmt++;
            switch (*fmt)
            {
            case 'd':
            {
                int num = va_arg(args, int);
                log_num(num, 10);
            }
            break;
            case 's':
            {
                char *str = va_arg(args, char*);
                while (*str) log_putchar(*str++);
            }
            break;
            case 'c':
            {
                char c = va_arg(args, int); // char 在可变参数中提升为 int
                log_putchar(c);
            }
            break;
            case '%':
            {
                log_putchar('%');
            }
            break;
            case 'x':   // 十六进制输出
            case 'X':   // 十六进制输出
            {
                unsigned int num = va_arg(args, unsigned int);
                log_num(num, 16);
            }
            break;
            default:
            {
                log_putchar('%'); // 输出未识别的格式符
                log_putchar(*fmt);
            }
            break;
            }
        }
        else
        {
            log_putchar(*fmt);
        }
        fmt++;
    }
    va_end(args);
}
#endif
