/**
  ******************************************************************************
  * @file    tsl_touchkey.c
  * @author  MCD Application Team
  * @brief   This file contains all functions to manage TouchKey sensors.
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; COPYRIGHT 2014 STMicroelectronics</center></h2>
  *
  * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
  * You may not use this file except in compliance with the License.
  * You may obtain a copy of the License at:
  *
  *        http://www.st.com/software_license_agreement_liberty_v2
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "tsl_touchkey.h"
#include "tsl_globals.h"

#if TSLPRM_TOTAL_TKEYS > 0

/* Private typedefs ----------------------------------------------------------*/
/* Private defines -----------------------------------------------------------*/

/* Private macros ------------------------------------------------------------*/

#define THIS_MEAS                 TSL_Globals.This_TKey->p_ChD->Meas
#define THIS_DELTA                TSL_Globals.This_TKey->p_ChD->Delta
#define THIS_REF                  TSL_Globals.This_TKey->p_ChD->Ref
#define THIS_REFREST              TSL_Globals.This_TKey->p_ChD->RefRest
#define THIS_CHANNEL_DATA         TSL_Globals.This_TKey->p_ChD
#define THIS_ACQ_STATUS           TSL_Globals.This_TKey->p_ChD->Flags.AcqStatus
#define THIS_OBJ_STATUS           TSL_Globals.This_TKey->p_ChD->Flags.ObjStatus
#define THIS_DATA_READY           TSL_Globals.This_TKey->p_ChD->Flags.DataReady

#define THIS_STATEID              TSL_Globals.This_TKey->p_Data->StateId
#define THIS_CHANGE               TSL_Globals.This_TKey->p_Data->Change
#define THIS_COUNTER_DEB          TSL_Globals.This_TKey->p_Data->CounterDebounce
#define THIS_COUNTER_DTO          TSL_Globals.This_TKey->p_Data->CounterDTO
#define THIS_DXSLOCK              TSL_Globals.This_TKey->p_Data->DxSLock

#define THIS_PROXIN_TH            TSL_Globals.This_TKey->p_Param->ProxInTh
#define THIS_PROXOUT_TH           TSL_Globals.This_TKey->p_Param->ProxOutTh
#define THIS_DETECTIN_TH          TSL_Globals.This_TKey->p_Param->DetectInTh
#define THIS_DETECTOUT_TH         TSL_Globals.This_TKey->p_Param->DetectOutTh
#define THIS_CALIB_TH             TSL_Globals.This_TKey->p_Param->CalibTh

#define THIS_COUNTER_DEB_CALIB    TSL_Globals.This_TKey->p_Param->CounterDebCalib
#define THIS_COUNTER_DEB_PROX     TSL_Globals.This_TKey->p_Param->CounterDebProx
#define THIS_COUNTER_DEB_DETECT   TSL_Globals.This_TKey->p_Param->CounterDebDetect
#define THIS_COUNTER_DEB_RELEASE  TSL_Globals.This_TKey->p_Param->CounterDebRelease
#define THIS_COUNTER_DEB_ERROR    TSL_Globals.This_TKey->p_Param->CounterDebError

#if TSLPRM_DTO > 0
#define DTO_GET_TIME  {TSL_tkey_DTOGetTime();}
#else
#define DTO_GET_TIME
#endif

#if TSLPRM_COEFF_TH > 0
#define TEST_DELTA(OPER,TH)   (THIS_DELTA OPER (uint16_t)((uint16_t)TH << TSLPRM_COEFF_TH))
#define TEST_DELTA_N(OPER,TH) (THIS_DELTA OPER -((uint16_t)((uint16_t)TH << TSLPRM_COEFF_TH)))
#define TEST_DELTA_NEGATIVE   {if (THIS_DELTA < 0) {return;}}
#else
#define TEST_DELTA(OPER,TH)   (THIS_DELTA OPER TH)
#define TEST_DELTA_N(OPER,TH) (THIS_DELTA OPER -(TH))
#define TEST_DELTA_NEGATIVE
#endif

/* Private variables ---------------------------------------------------------*/

static TSL_tNb_T CalibDiv;

/* Private functions prototype -----------------------------------------------*/

void TSL_tkey_DTOGetTime(void);


//==============================================================================
// "Object methods" functions
//==============================================================================

/**
  * @brief  Init parameters with default values from configuration file
  * @param  None
  * @retval None
  */
void TSL_tkey_Init(void)
{
  // Thresholds
#if TSLPRM_USE_PROX > 0
  THIS_PROXIN_TH    = TSLPRM_TKEY_PROX_IN_TH;
  THIS_PROXOUT_TH   = TSLPRM_TKEY_PROX_OUT_TH;
#endif
  THIS_DETECTIN_TH  = TSLPRM_TKEY_DETECT_IN_TH;
  THIS_DETECTOUT_TH = TSLPRM_TKEY_DETECT_OUT_TH;
  THIS_CALIB_TH     = TSLPRM_TKEY_CALIB_TH;

  // Debounce counters
  THIS_COUNTER_DEB_CALIB   = TSLPRM_DEBOUNCE_CALIB;
#if TSLPRM_USE_PROX > 0
  THIS_COUNTER_DEB_PROX    = TSLPRM_DEBOUNCE_PROX;
#endif
  THIS_COUNTER_DEB_DETECT  = TSLPRM_DEBOUNCE_DETECT;
  THIS_COUNTER_DEB_RELEASE = TSLPRM_DEBOUNCE_RELEASE;
  THIS_COUNTER_DEB_ERROR   = TSLPRM_DEBOUNCE_ERROR;

  // Initial state
  TSL_tkey_SetStateCalibration(TSLPRM_CALIB_DELAY);
}


/**
  * @brief  Process the State Machine
  * @param  None
  * @retval None
  */
void TSL_tkey_Process(void)
{
  TSL_StateId_enum_T prev_state_id;

  if ((THIS_DATA_READY != 0) || (THIS_STATEID == TSL_STATEID_OFF))
  {

    THIS_DATA_READY = TSL_DATA_NOT_READY; // The new data is processed

    prev_state_id = THIS_STATEID;

#if TSLPRM_TOTAL_TOUCHKEYS > 0
    if (TSL_Globals.This_Obj->Type == TSL_OBJ_TOUCHKEY)
    {
      // Launch the TKey state function
      TSL_Globals.This_TKey->p_SM[THIS_STATEID].StateFunc();
    }
#endif

#if TSLPRM_TOTAL_TOUCHKEYS_B > 0
    if (TSL_Globals.This_Obj->Type == TSL_OBJ_TOUCHKEYB)
    {
      // Launch the TSL_Params state function
      TSL_Params.p_TKeySM[THIS_STATEID].StateFunc();
    }
#endif

    // Check if the new state has changed
    if (THIS_STATEID == prev_state_id)
    {
      THIS_CHANGE = TSL_STATE_NOT_CHANGED;
    }
    else
    {
      THIS_CHANGE = TSL_STATE_CHANGED;
    }

#if TSLPRM_USE_DXS > 0
    if (THIS_STATEID != TSL_STATEID_DETECT)
    {
      THIS_DXSLOCK = TSL_FALSE;
    }
    if (THIS_STATEID == TSL_STATEID_TOUCH)
    {
      THIS_STATEID = TSL_STATEID_DETECT;
    }
#endif

  }
}


//==============================================================================
// Utility functions
//==============================================================================

/**
  * @brief  Go in Calibration state
  * @param[in] delay Delay before calibration starts (stabilization of noise filter)
  * @retval None
  */
void TSL_tkey_SetStateCalibration(TSL_tCounter_T delay)
{
  THIS_STATEID = TSL_STATEID_CALIB;
  THIS_CHANGE = TSL_STATE_CHANGED;
  THIS_OBJ_STATUS = TSL_OBJ_STATUS_ON;

  switch (TSL_Params.NbCalibSamples)
  {
    case 4:
      CalibDiv = 2;
      break;
    case 16:
      CalibDiv = 4;
      break;
    default:
      TSL_Params.NbCalibSamples =  8;
      CalibDiv = 3;
      break;
  }

  // If a noise filter is used, the counter must be initialized to a value
  // different from 0 in order to stabilize the filter.
  THIS_COUNTER_DEB = (TSL_tCounter_T)(delay + (TSL_tCounter_T)TSL_Params.NbCalibSamples);
  THIS_REF = 0;
}


/**
  * @brief  Go in Off state with sensor "off"
  * @param  None
  * @retval None
  */
void TSL_tkey_SetStateOff(void)
{
  THIS_STATEID = TSL_STATEID_OFF;
  THIS_CHANGE = TSL_STATE_CHANGED;
  THIS_OBJ_STATUS = TSL_OBJ_STATUS_OFF;
}


/**
  * @brief  Go in Off state with sensor in "Burst mode only"
  * @param  None
  * @retval None
  */
void TSL_tkey_SetStateBurstOnly(void)
{
  THIS_STATEID = TSL_STATEID_OFF;
  THIS_CHANGE = TSL_STATE_CHANGED;
  THIS_OBJ_STATUS = TSL_OBJ_STATUS_BURST_ONLY;
}


/**
  * @brief  Return the current state identifier
  * @param  None
  * @retval State id
  */
TSL_StateId_enum_T TSL_tkey_GetStateId(void)
{
  return(THIS_STATEID);
}


/**
  * @brief  Return the current state mask
  * @param  None
  * @retval State mask
  */
TSL_StateMask_enum_T TSL_tkey_GetStateMask(void)
{
  TSL_StateMask_enum_T state_mask = TSL_STATEMASK_UNKNOWN;

#if TSLPRM_TOTAL_TOUCHKEYS > 0
  if (TSL_Globals.This_Obj->Type == TSL_OBJ_TOUCHKEY)
  {
    state_mask = TSL_Globals.This_TKey->p_SM[THIS_STATEID].StateMask;
  }
#endif

#if TSLPRM_TOTAL_TOUCHKEYS_B > 0
  if (TSL_Globals.This_Obj->Type == TSL_OBJ_TOUCHKEYB)
  {
    state_mask = TSL_Params.p_TKeySM[THIS_STATEID].StateMask;
  }
#endif

  return state_mask;
}


/**
  * @brief  Return the Change flag
  * @param  None
  * @retval Change flag status
  */
TSL_tNb_T TSL_tkey_IsChanged(void)
{
  return(THIS_CHANGE);
}


//==============================================================================
// State machine functions
//==============================================================================

#if TSLPRM_USE_PROX > 0
/**
  * @brief  Debounce Release processing (previous state = Proximity)
  * @param  None
  * @retval None
  */
void TSL_tkey_DebReleaseProxStateProcess(void)
{
  if (THIS_ACQ_STATUS & TSL_ACQ_STATUS_ERROR_MASK) // Acquisition error (min or max)
  {
    THIS_STATEID = TSL_STATEID_PROX; // Go back to the previous state
  }
  else // Acquisition is OK or has NOISE
  {
    if (THIS_DELTA > THIS_PROXOUT_TH)
    {
      THIS_STATEID = TSL_STATEID_PROX; // Go back to the previous state
    }
    else
    {
      if (THIS_COUNTER_DEB > 0) {THIS_COUNTER_DEB--;}
      if (THIS_COUNTER_DEB == 0)
      {
        THIS_STATEID = TSL_STATEID_RELEASE;
      }
      // else stay in Debounce Release
    }
  }
}
#endif // if TSLPRM_USE_PROX > 0


/**
  * @brief  Debounce Release processing (previous state = Detect)
  * @param  None
  * @retval None
  */
void TSL_tkey_DebReleaseDetectStateProcess(void)
{
  if (THIS_ACQ_STATUS & TSL_ACQ_STATUS_ERROR_MASK) // Acquisition error (min or max)
  {
    THIS_STATEID = TSL_STATEID_DETECT; // Go back to the previous state
  }
  else // Acquisition is OK or has NOISE
  {
    if TEST_DELTA(>, THIS_DETECTOUT_TH)
    {
      TEST_DELTA_NEGATIVE;
      THIS_STATEID = TSL_STATEID_DETECT;
    }
    else
    {
#if TSLPRM_USE_PROX > 0
      if (THIS_DELTA > THIS_PROXOUT_TH)
      {
        THIS_STATEID = TSL_STATEID_PROX;
        return;
      }
#endif
      if (THIS_COUNTER_DEB > 0) {THIS_COUNTER_DEB--;}
      if (THIS_COUNTER_DEB == 0)
      {
        THIS_STATEID = TSL_STATEID_RELEASE;
      }
      // else stay in Debounce Release
    }
  }
}


/**
  * @brief  Debounce Release processing (previous state = Touch)
  * Same as Debounce Release Detect processing
  * @param  None
  * @retval None
  */
void TSL_tkey_DebReleaseTouchStateProcess(void)
{
  if (THIS_ACQ_STATUS & TSL_ACQ_STATUS_ERROR_MASK) // Acquisition error (min or max)
  {
    THIS_STATEID = TSL_STATEID_TOUCH; // Go back to the previous state
  }
  else // Acquisition is OK or has NOISE
  {
    if TEST_DELTA(>, THIS_DETECTOUT_TH)
    {
      TEST_DELTA_NEGATIVE;
      THIS_STATEID = TSL_STATEID_TOUCH;
    }
    else
    {
#if TSLPRM_USE_PROX > 0
      if (THIS_DELTA > THIS_PROXOUT_TH)
      {
        THIS_STATEID = TSL_STATEID_PROX;
        return;
      }
#endif
      if (THIS_COUNTER_DEB > 0) {THIS_COUNTER_DEB--;}
      if (THIS_COUNTER_DEB == 0)
      {
        THIS_STATEID = TSL_STATEID_RELEASE;
      }
      // else stay in Debounce Release
    }
  }
}


/**
  * @brief  Release state processing
  * @param  None
  * @retval None
  */
void TSL_tkey_ReleaseStateProcess(void)
{
  if (THIS_ACQ_STATUS & TSL_ACQ_STATUS_ERROR_MASK) // Acquisition error (min or max)
  {
    THIS_COUNTER_DEB = THIS_COUNTER_DEB_ERROR;
    if (THIS_COUNTER_DEB == 0)
    {
      THIS_STATEID = TSL_STATEID_ERROR;
    }
    else
    {
      THIS_STATEID = TSL_STATEID_DEB_ERROR_RELEASE;
    }
  }
  else // Acquisition is OK or has NOISE
  {
    if TEST_DELTA(>=, THIS_DETECTIN_TH)
    {
      TEST_DELTA_NEGATIVE;
      THIS_COUNTER_DEB = THIS_COUNTER_DEB_DETECT;
      if (THIS_COUNTER_DEB == 0)
      {
        THIS_STATEID = TSL_STATEID_DETECT;
        DTO_GET_TIME; // Take current time for DTO processing
      }
      else
      {
        THIS_STATEID = TSL_STATEID_DEB_DETECT;
      }
      return;
    }

#if TSLPRM_USE_PROX > 0
    if (THIS_DELTA >= THIS_PROXIN_TH)
    {
      THIS_COUNTER_DEB = THIS_COUNTER_DEB_PROX;
      if (THIS_COUNTER_DEB == 0)
      {
        THIS_STATEID = TSL_STATEID_PROX;
        DTO_GET_TIME; // Take current time for DTO processing
      }
      else
      {
        THIS_STATEID = TSL_STATEID_DEB_PROX;
      }
      return;
    }
#endif

    // Check delta for re-calibration
    // Warning: the threshold value is inverted in the macro
    if TEST_DELTA_N(<=, THIS_CALIB_TH)
    {
      THIS_COUNTER_DEB = THIS_COUNTER_DEB_CALIB;
      if (THIS_COUNTER_DEB == 0)
      {
        TSL_tkey_SetStateCalibration(0);
      }
      else
      {
        THIS_STATEID = TSL_STATEID_DEB_CALIB;
      }
    }
  }
}


/**
  * @brief  Debounce Calibration processing (previous state = Release)
  * @param  None
  * @retval None
  */
void TSL_tkey_DebCalibrationStateProcess(void)
{
  if (THIS_ACQ_STATUS & TSL_ACQ_STATUS_ERROR_MASK) // Acquisition error (min or max)
  {
    THIS_STATEID = TSL_STATEID_RELEASE; // Go back to the previous state
  }
  else // Acquisition is OK or has NOISE
  {
    // Still below recalibration threshold
    // Warning: the threshold value is inverted in the macro
    if TEST_DELTA_N(<=, THIS_CALIB_TH)
    {
      if (THIS_COUNTER_DEB > 0) {THIS_COUNTER_DEB--;}
      if (THIS_COUNTER_DEB == 0)
      {
        TSL_tkey_SetStateCalibration(0);
      }
      // else stay in Debounce Calibration
    }
    else // Go back to previous state
    {
      THIS_STATEID = TSL_STATEID_RELEASE;
    }
  }
}


/**
  * @brief  Calibration state processing
  * @param  None
  * @retval None
  */
void TSL_tkey_CalibrationStateProcess(void)
{
  TSL_tMeas_T new_meas;

#if TSLPRM_CALIB_DELAY > 0
  // Noise filter stabilization time
  if (THIS_COUNTER_DEB > (TSL_tCounter_T)TSL_Params.NbCalibSamples)
  {
    THIS_COUNTER_DEB--;
    return; // Skip the sample
  }
#endif

  if (THIS_ACQ_STATUS & TSL_ACQ_STATUS_ERROR_MASK) // Acquisition error (min or max)
  {
    THIS_COUNTER_DEB = THIS_COUNTER_DEB_ERROR;
    if (THIS_COUNTER_DEB == 0)
    {
      THIS_STATEID = TSL_STATEID_ERROR;
    }
    else
    {
      THIS_STATEID = TSL_STATEID_DEB_ERROR_CALIB;
    }
  }
  else // Acquisition is OK or has NOISE
  {

    // Get the new measure or Calculate it
#if TSLPRM_USE_MEAS > 0
    new_meas = THIS_MEAS;
#else // Calculate it
    new_meas = TSL_acq_ComputeMeas(THIS_REF, THIS_DELTA);
#endif

    // Verify the first Reference value
    if (THIS_COUNTER_DEB == (TSL_tCounter_T)TSL_Params.NbCalibSamples)
    {
      if (TSL_acq_TestFirstReferenceIsValid(THIS_CHANNEL_DATA, new_meas))
      {
        THIS_REF = new_meas;
      }
      else
      {
        THIS_REF = 0;
        return;
      }
    }
    else
    {
      // Add the measure in temporary Reference
      THIS_REF += new_meas;

      // Check reference overflow
      if (THIS_REF < new_meas)
      {
        THIS_REF = 0; // Suppress the bad reference
        THIS_STATEID = TSL_STATEID_ERROR;
        return;
      }
    }

    // Check that we have all the needed measurements
    if (THIS_COUNTER_DEB > 0) {THIS_COUNTER_DEB--;}
    if (THIS_COUNTER_DEB == 0)
    {
      // Divide temporary Reference by the number of samples
      THIS_REF >>= CalibDiv;
      THIS_REFREST = 0;
      THIS_DELTA = 0;
      THIS_STATEID = TSL_STATEID_RELEASE;
    }
  }
}


#if TSLPRM_USE_PROX > 0
/**
  * @brief  Debounce Proximity processing (previous state = Release)
  * @param  None
  * @retval None
  */
void TSL_tkey_DebProxStateProcess(void)
{
  if (THIS_ACQ_STATUS & TSL_ACQ_STATUS_ERROR_MASK) // Acquisition error (min or max)
  {
    THIS_STATEID = TSL_STATEID_RELEASE;
  }
  else // Acquisition is OK or has NOISE
  {
    if TEST_DELTA(>=, THIS_DETECTIN_TH)
    {
      TEST_DELTA_NEGATIVE;
      THIS_COUNTER_DEB = THIS_COUNTER_DEB_DETECT;
      if (THIS_COUNTER_DEB == 0)
      {
        THIS_STATEID = TSL_STATEID_DETECT;
        DTO_GET_TIME; // Take current time for DTO processing
      }
      else
      {
        THIS_STATEID = TSL_STATEID_DEB_DETECT;
      }
      return;
    }

    if (THIS_DELTA >= THIS_PROXIN_TH)
    {
      if (THIS_COUNTER_DEB > 0) {THIS_COUNTER_DEB--;}
      if (THIS_COUNTER_DEB == 0)
      {
        THIS_STATEID = TSL_STATEID_PROX;
        DTO_GET_TIME; // Take current time for DTO processing
      }
      // else stay in Debounce Proximity
    }
    else
    {
      THIS_STATEID = TSL_STATEID_RELEASE;
    }
  }
}
#endif


#if TSLPRM_USE_PROX > 0
/**
  * @brief  Debounce Proximity processing (previous state = Detect)
  * @param  None
  * @retval None
  */
void TSL_tkey_DebProxDetectStateProcess(void)
{
  if (THIS_ACQ_STATUS & TSL_ACQ_STATUS_ERROR_MASK) // Acquisition error (min or max)
  {
    THIS_STATEID = TSL_STATEID_DETECT;
  }
  else // Acquisition is OK or has NOISE
  {
    if TEST_DELTA(>, THIS_DETECTOUT_TH)
    {
      TEST_DELTA_NEGATIVE;
      THIS_STATEID = TSL_STATEID_DETECT;
      return;
    }

    if (THIS_DELTA > THIS_PROXOUT_TH)
    {
      if (THIS_COUNTER_DEB > 0) {THIS_COUNTER_DEB--;}
      if (THIS_COUNTER_DEB == 0)
      {
        THIS_STATEID = TSL_STATEID_PROX;
        DTO_GET_TIME; // Take current time for DTO processing
      }
      // else stay in Debounce Proximity
    }
    else
    {
      THIS_COUNTER_DEB = THIS_COUNTER_DEB_RELEASE;
      if (THIS_COUNTER_DEB == 0)
      {
        THIS_STATEID = TSL_STATEID_RELEASE;
      }
      else
      {
        THIS_STATEID = TSL_STATEID_DEB_RELEASE_DETECT;
      }
    }
  }
}
#endif


#if TSLPRM_USE_PROX > 0
/**
  * @brief  Debounce Proximity processing (previous state = Touch)
  * @param  None
  * @retval None
  */
void TSL_tkey_DebProxTouchStateProcess(void)
{
  if (THIS_ACQ_STATUS & TSL_ACQ_STATUS_ERROR_MASK) // Acquisition error (min or max)
  {
    THIS_STATEID = TSL_STATEID_TOUCH;
  }
  else // Acquisition is OK or has NOISE
  {
    if TEST_DELTA(>, THIS_DETECTOUT_TH)
    {
      TEST_DELTA_NEGATIVE;
      THIS_STATEID = TSL_STATEID_TOUCH;
      return;
    }

    if (THIS_DELTA > THIS_PROXOUT_TH)
    {
      if (THIS_COUNTER_DEB > 0) {THIS_COUNTER_DEB--;}
      if (THIS_COUNTER_DEB == 0)
      {
        THIS_STATEID = TSL_STATEID_PROX;
        DTO_GET_TIME; // Take current time for DTO processing
      }
      // else stay in Debounce Proximity
    }
    else
    {
      THIS_COUNTER_DEB = THIS_COUNTER_DEB_RELEASE;
      if (THIS_COUNTER_DEB == 0)
      {
        THIS_STATEID = TSL_STATEID_RELEASE;
      }
      else
      {
        THIS_STATEID = TSL_STATEID_DEB_RELEASE_TOUCH;
      }
    }
  }
}
#endif


#if TSLPRM_USE_PROX > 0
/**
  * @brief  Proximity state processing
  * @param  None
  * @retval None
  */
void TSL_tkey_ProxStateProcess(void)
{
#if TSLPRM_DTO > 0
  TSL_tTick_sec_T tick_detected;
#endif

  if (THIS_ACQ_STATUS & TSL_ACQ_STATUS_ERROR_MASK) // Acquisition error (min or max)
  {
    THIS_COUNTER_DEB = THIS_COUNTER_DEB_ERROR;
    if (THIS_COUNTER_DEB == 0)
    {
      THIS_STATEID = TSL_STATEID_ERROR;
    }
    else
    {
      THIS_STATEID = TSL_STATEID_DEB_ERROR_PROX;
    }
  }
  else // Acquisition is OK or has NOISE
  {
    if TEST_DELTA(>=, THIS_DETECTIN_TH)
    {
      TEST_DELTA_NEGATIVE;
      THIS_COUNTER_DEB = THIS_COUNTER_DEB_DETECT;
      if (THIS_COUNTER_DEB == 0)
      {
        THIS_STATEID = TSL_STATEID_DETECT;
        DTO_GET_TIME; // Take current time for DTO processing
      }
      else
      {
        THIS_STATEID = TSL_STATEID_DEB_DETECT;
      }
      return;
    }

    if (THIS_DELTA <= THIS_PROXOUT_TH)
    {
      THIS_COUNTER_DEB = THIS_COUNTER_DEB_RELEASE;
      if (THIS_COUNTER_DEB == 0)
      {
        THIS_STATEID = TSL_STATEID_RELEASE;
      }
      else
      {
        THIS_STATEID = TSL_STATEID_DEB_RELEASE_PROX;
      }
      return;
    }

    // Stay in Proximity state
#if TSLPRM_DTO > 0
    //------------------------------------
    // Detection Time Out (DTO) processing
    //------------------------------------
    if ((TSL_Params.DTO > 1) && (TSL_Params.DTO < 64))
    {
      tick_detected = THIS_COUNTER_DTO; // Get the detected time previously saved
      // Enter in calibration state if the DTO duration has elapsed
      if (TSL_tim_CheckDelay_sec(TSL_Params.DTO, &tick_detected) == TSL_STATUS_OK)
      {
        TSL_tkey_SetStateCalibration(0);
      }
    }
#endif

  }
}
#endif


/**
  * @brief  Debounce Detect processing (previous state = Release or Proximity)
  * @param  None
  * @retval None
  */
void TSL_tkey_DebDetectStateProcess(void)
{
  if (THIS_ACQ_STATUS & TSL_ACQ_STATUS_ERROR_MASK) // Acquisition error (min or max)
  {
    THIS_STATEID = TSL_STATEID_RELEASE;
  }
  else // Acquisition is OK or has NOISE
  {
    if TEST_DELTA(>=, THIS_DETECTIN_TH)
    {
      TEST_DELTA_NEGATIVE;
      if (THIS_COUNTER_DEB > 0) {THIS_COUNTER_DEB--;}
      if (THIS_COUNTER_DEB == 0)
      {
        THIS_STATEID = TSL_STATEID_DETECT;
        DTO_GET_TIME; // Take current time for DTO processing
      }
      // else stay in Debounce Detect
    }
    else
    {
#if TSLPRM_USE_PROX > 0
      if (THIS_DELTA >= THIS_PROXIN_TH)
      {
        THIS_COUNTER_DEB = THIS_COUNTER_DEB_PROX;
        if (THIS_COUNTER_DEB == 0)
        {
          THIS_STATEID = TSL_STATEID_PROX;
          DTO_GET_TIME; // Take current time for DTO processing
        }
        else
        {
          THIS_STATEID = TSL_STATEID_DEB_PROX;
        }
      }
      else
      {
        THIS_STATEID = TSL_STATEID_RELEASE;
      }
#else
      THIS_STATEID = TSL_STATEID_RELEASE;
#endif
    }
  }
}


/**
  * @brief  Detect state processing
  * @param  None
  * @retval None
  */
void TSL_tkey_DetectStateProcess(void)
{
#if TSLPRM_DTO > 0
  TSL_tTick_sec_T tick_detected;
#endif

  if (THIS_ACQ_STATUS & TSL_ACQ_STATUS_ERROR_MASK) // Acquisition error (min or max)
  {
    THIS_COUNTER_DEB = THIS_COUNTER_DEB_ERROR;
    if (THIS_COUNTER_DEB == 0)
    {
      THIS_STATEID = TSL_STATEID_ERROR;
    }
    else
    {
      THIS_STATEID = TSL_STATEID_DEB_ERROR_DETECT;
    }
  }
  else // Acquisition is OK or has NOISE
  {
    if TEST_DELTA(>, THIS_DETECTOUT_TH)
    {
      TEST_DELTA_NEGATIVE;
#if TSLPRM_DTO > 0
      //------------------------------------
      // Detection Time Out (DTO) processing
      //------------------------------------
      if ((TSL_Params.DTO > 1) && (TSL_Params.DTO < 64))
      {
        tick_detected = THIS_COUNTER_DTO; // Get the detected time previously saved
        // Enter in calibration state if the DTO duration has elapsed
        if (TSL_tim_CheckDelay_sec(TSL_Params.DTO, &tick_detected) == TSL_STATUS_OK)
        {
          TSL_tkey_SetStateCalibration(0);
        }
      }
#endif
      return; // Normal operation, stay in Detect state
    }

#if TSLPRM_USE_PROX > 0
    if (THIS_DELTA > THIS_PROXOUT_TH)
    {
      THIS_COUNTER_DEB = THIS_COUNTER_DEB_PROX;
      if (THIS_COUNTER_DEB == 0)
      {
        THIS_STATEID = TSL_STATEID_PROX;
        DTO_GET_TIME; // Take current time for DTO processing
      }
      else
      {
        THIS_STATEID = TSL_STATEID_DEB_PROX_DETECT;
      }
      return;
    }
#endif

    THIS_COUNTER_DEB = THIS_COUNTER_DEB_RELEASE;
    if (THIS_COUNTER_DEB == 0)
    {
      THIS_STATEID = TSL_STATEID_RELEASE;
    }
    else
    {
      THIS_STATEID = TSL_STATEID_DEB_RELEASE_DETECT;
    }

  }
}


/**
  * @brief  Touch state processing
  * Same as Detect state
  * @param  None
  * @retval None
  */
void TSL_tkey_TouchStateProcess(void)
{
#if TSLPRM_DTO > 0
  TSL_tTick_sec_T tick_detected;
#endif

  if (THIS_ACQ_STATUS & TSL_ACQ_STATUS_ERROR_MASK) // Acquisition error (min or max)
  {
    THIS_COUNTER_DEB = THIS_COUNTER_DEB_ERROR;
    if (THIS_COUNTER_DEB == 0)
    {
      THIS_STATEID = TSL_STATEID_ERROR;
    }
    else
    {
      THIS_STATEID = TSL_STATEID_DEB_ERROR_TOUCH;
    }
  }
  else // Acquisition is OK or has NOISE
  {
    if TEST_DELTA(>, THIS_DETECTOUT_TH)
    {
      TEST_DELTA_NEGATIVE;
#if TSLPRM_DTO > 0
      //------------------------------------
      // Detection Time Out (DTO) processing
      //------------------------------------
      if ((TSL_Params.DTO > 1) && (TSL_Params.DTO < 64))
      {
        tick_detected = THIS_COUNTER_DTO; // Get the detected time previously saved
        // Enter in calibration state if the DTO duration has elapsed
        if (TSL_tim_CheckDelay_sec(TSL_Params.DTO, &tick_detected) == TSL_STATUS_OK)
        {
          TSL_tkey_SetStateCalibration(0);
        }
      }
#endif
      return; // Normal operation, stay in Touch state
    }

#if TSLPRM_USE_PROX > 0
    if (THIS_DELTA > THIS_PROXOUT_TH)
    {
      THIS_COUNTER_DEB = THIS_COUNTER_DEB_PROX;
      if (THIS_COUNTER_DEB == 0)
      {
        THIS_STATEID = TSL_STATEID_PROX;
        DTO_GET_TIME; // Take current time for DTO processing
      }
      else
      {
        THIS_STATEID = TSL_STATEID_DEB_PROX_TOUCH;
      }
      return;
    }
#endif

    THIS_COUNTER_DEB = THIS_COUNTER_DEB_RELEASE;
    if (THIS_COUNTER_DEB == 0)
    {
      THIS_STATEID = TSL_STATEID_RELEASE;
    }
    else
    {
      THIS_STATEID = TSL_STATEID_DEB_RELEASE_TOUCH;
    }

  }
}


/**
  * @brief  Debounce error state processing
  * @param  None
  * @retval None
  */
void TSL_tkey_DebErrorStateProcess(void)
{
  volatile TSL_StateMask_enum_T mask;

  if (THIS_ACQ_STATUS & TSL_ACQ_STATUS_ERROR_MASK) // Acquisition error (min or max)
  {
    if (THIS_COUNTER_DEB > 0) {THIS_COUNTER_DEB--;}
    if (THIS_COUNTER_DEB == 0)
    {
      THIS_STATEID = TSL_STATEID_ERROR;
    }
  }
  else // Acquisition is OK or has NOISE
  {
    // Get state mask
    mask = TSL_tkey_GetStateMask();
    // Mask Error and Debounce bits
    mask &= (TSL_StateMask_enum_T)(~(TSL_STATE_DEBOUNCE_BIT_MASK | TSL_STATE_ERROR_BIT_MASK));
    // Go back to the previous state
    switch (mask)
    {
      case TSL_STATEMASK_RELEASE :
        THIS_STATEID = TSL_STATEID_RELEASE;
        break;
      case TSL_STATEMASK_PROX :
        THIS_STATEID = TSL_STATEID_PROX;
        break;
      case TSL_STATEMASK_DETECT :
        THIS_STATEID = TSL_STATEID_DETECT;
        break;
      case TSL_STATEMASK_TOUCH :
        THIS_STATEID = TSL_STATEID_TOUCH;
        break;
      default:
        TSL_tkey_SetStateCalibration(0);
        break;
    }
  }
}


//==============================================================================
// Private functions
//==============================================================================

/**
  * @brief  Get the current time in second and affect it to the DTO counter (Private)
  * @param  None
  * @retval None
  */
void TSL_tkey_DTOGetTime(void)
{
  disableInterrupts();
  THIS_COUNTER_DTO = (TSL_tCounter_T)TSL_Globals.Tick_sec;
  enableInterrupts();
}

#endif
// #if TSLPRM_TOTAL_TKEYS > 0

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
