/*
 * Copyright (c) 2013 - 2016, Freescale Semiconductor, Inc.
 * Copyright 2016-2017 NXP
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * o Redistributions of source code must retain the above copyright notice, this list
 *   of conditions and the following disclaimer.
 *
 * o Redistributions in binary form must reproduce the above copyright notice, this
 *   list of conditions and the following disclaimer in the documentation and/or
 *   other materials provided with the distribution.
 *
 * o Neither the name of the copyright holder nor the names of its
 *   contributors may be used to endorse or promote products derived from this
 *   software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#include <string.h>
#include "nt_drv_tsi_driver.h"
#include "nt_module_tsi.h"
#if FSL_FEATURE_SOC_TSI_COUNT
/*******************************************************************************
 * Definitions
 ******************************************************************************/
extern IRQn_Type tsi_irq_ids[FSL_FEATURE_SOC_TSI_COUNT];
extern void TSI_DRV_IRQHandler0(void);
/*******************************************************************************
 * Variables
 ******************************************************************************/
volatile tsi_lpwr_status_flags_t tsi_lpwr_status;

/*******************************************************************************
 * Code
 ******************************************************************************/

/*FUNCTION**********************************************************************
*
* Function Name : NT_TSI_DRV_Init
* Description   : Encapsulates TSI v5 init.
*
*END**************************************************************************/
void NT_TSI_DRV_InitSpecific(TSI_Type *base, const tsi_config_t *config)
{
    TSI_InitSelfCapMode(base, &config->configSelfCap);
    TSI_EnableModule(base, true);
}

/*FUNCTION**********************************************************************
*
* Function Name : NT_TSI_DRV_EnableElectrode
* Description   : Enables/Disables the electrode for measuring.
*
*END**************************************************************************/
tsi_status_t NT_TSI_DRV_EnableElectrode(uint32_t instance, const uint32_t channel, const bool enable)
{
    NT_ASSERT(instance < FSL_FEATURE_SOC_TSI_COUNT);
    NT_ASSERT(channel < TF_TSI_TOTAL_CHANNEL_COUNT);
    
    nt_tsi_state_t * tsiState = g_tsiStatePtr[instance];

    /* OS: Critical section. Access to global variable */
    if (knt_Status_OSA_Success != NT_OSA_MutexLock(&tsiState->lock, OSA_WAIT_FOREVER))
    {
        return kStatus_TSI_Error;
    }

    if (tsiState->status != kStatus_TSI_Initialized)
    {
      /* OS: End of critical section. */
        NT_OSA_MutexUnlock(&tsiState->lock);
        
        return tsiState->status;
    }

    /* Check the condition for low power mode. */
    if((tsiState->opMode == tsi_OpModeLowPower) || (tsiState->opMode == tsi_OpModeProximity))
    {
        tsiState->opModesData[tsiState->opMode].enabledElectrodes = 0;
    }

    if(enable)
    {
        tsiState->opModesData[tsiState->opMode].enabledElectrodes |= (1ULL << channel);
    }
    else
    {
        tsiState->opModesData[tsiState->opMode].enabledElectrodes &= ~(1ULL << channel);
    }
    
    /* Check self/mutual setting feasibility */
    if(channel > (TF_TSI_SELF_CAP_CHANNEL_COUNT-1U))
    {
        NT_ASSERT(!(tsiState->opModesData[tsiState->opMode].enabledElectrodes & (1ULL<<((channel-TF_TSI_SELF_CAP_CHANNEL_COUNT)/TF_TSI_MUTUAL_CAP_RX_CHANNEL_COUNT))));
        NT_ASSERT(!(tsiState->opModesData[tsiState->opMode].enabledElectrodes & (1ULL<<(((channel-TF_TSI_SELF_CAP_CHANNEL_COUNT)%TF_TSI_MUTUAL_CAP_RX_CHANNEL_COUNT)+TF_TSI_MUTUAL_CAP_RX_CHANNEL_COUNT))));
    }

    /* OS: End of critical section. */
    NT_OSA_MutexUnlock(&tsiState->lock);

    return kStatus_TSI_Success;
}

/*FUNCTION**********************************************************************
*
* Function Name : NT_TSI_DRV_GetCounter
* Description   : Function returns the counter value of selected channel
*
*END**************************************************************************/
tsi_status_t NT_TSI_DRV_GetCounter(uint32_t instance, const uint32_t channel, uint16_t * counter)
{
    NT_ASSERT(instance < FSL_FEATURE_SOC_TSI_COUNT);
    NT_ASSERT(channel < TF_TSI_TOTAL_CHANNEL_COUNT);
    NT_ASSERT(counter);

    nt_tsi_state_t * tsiState = g_tsiStatePtr[instance];
      
    if(!((1ULL << channel) & (tsiState->opModesData[tsiState->opMode].enabledElectrodes)))   /* Check the channel number. */
    {
        return kStatus_TSI_InvalidChannel;
    }

    *counter = tsiState->counters[channel];

    return kStatus_TSI_Success;
}

/*FUNCTION**********************************************************************
*
* Function Name : NT_TSI_DRV_Measure
* Description   : This function gets (measure) capacitance of enabled electrodes
*               from the TSI module using a non-blocking method.
*
*END**************************************************************************/
tsi_status_t NT_TSI_DRV_Measure(uint32_t instance)
{
    NT_ASSERT(instance < FSL_FEATURE_SOC_TSI_COUNT);

    TSI_Type * base = g_tsiBase[instance];
    nt_tsi_state_t * tsiState = g_tsiStatePtr[instance];
    uint64_t    pen;
    uint32_t    first_pen;
    uint32_t    mutual_rx, mutual_tx;
    
    /* OS: Critical section. Access to global variable */
    if (knt_Status_OSA_Success != NT_OSA_MutexLock(&tsiState->lock, OSA_WAIT_FOREVER))
    {
        return kStatus_TSI_Error;
    }

    if (tsiState->status != kStatus_TSI_Initialized)
    {
        /* OS: End of critical section. */
        NT_OSA_MutexUnlock(&tsiState->lock);

        return tsiState->status;
    }

    if(!tsiState->opModesData[tsiState->opMode].enabledElectrodes)
    {
        /* OS: End of critical section. */
        NT_OSA_MutexUnlock(&tsiState->lock);

        return kStatus_TSI_InvalidChannel;
    }
    
    tsiState->status = kStatus_TSI_Busy;

    /* If there is a self-cap electrode used, initialize self-cap sensing*/
    if(tsiState->opModesData[tsiState->opMode].enabledElectrodes & 0x01FFFFFFU)
    {
        /* Find electrode with the lowest index */
        first_pen = 0U;
        pen = tsiState->opModesData[tsiState->opMode].enabledElectrodes;
        while (((pen >> first_pen) & 0x1U) == 0U) {
            first_pen++;
        }
    
        /* OS: End of critical section. */
        NT_OSA_MutexUnlock(&tsiState->lock);

        /* Init self-cap sensing */
        TSI_EnableModule(base, false);
        TSI_InitSelfCapMode(base, &tsiState->opModesData[tsiState->opMode].config.configSelfCap);
        TSI_SetSelfCapMeasuredChannel(base, first_pen);
        TSI_EnableHardwareTriggerScan(base, false);
        TSI_EnableModule(base, true);
        TSI_StartSoftwareTrigger(base);
    }
    /* If there are no self-cap electrodes used, initialize mutual-cap sensing*/
    else
    {
        /* Find electrode with the lowest index */
        first_pen = TF_TSI_SELF_CAP_CHANNEL_COUNT;
        pen = tsiState->opModesData[tsiState->opMode].enabledElectrodes;
        while (((pen >> first_pen) & 0x1U) == 0U) {
            first_pen++;
        }
        
        /*Parse electrode number into rx, tx components*/
        mutual_tx = (first_pen - TF_TSI_SELF_CAP_CHANNEL_COUNT) / TF_TSI_MUTUAL_CAP_RX_CHANNEL_COUNT;
        mutual_rx = (first_pen - TF_TSI_SELF_CAP_CHANNEL_COUNT) % TF_TSI_MUTUAL_CAP_RX_CHANNEL_COUNT;
        
        /* OS: End of critical section. */
        NT_OSA_MutexUnlock(&tsiState->lock);

        /* Init mutual-cap sensing */
        TSI_EnableModule(base, false);
        TSI_InitMutualCapMode(base, &tsiState->opModesData[tsiState->opMode].config.configMutual);
        TSI_SetMutualCapTxChannel(base, (tsi_mutual_tx_channel_t)mutual_tx);
        TSI_SetMutualCapRxChannel(base, (tsi_mutual_rx_channel_t)mutual_rx);
        TSI_EnableHardwareTriggerScan(base, false);
        TSI_EnableModule(base, true);
        TSI_StartSoftwareTrigger(base);
    }
    
    return kStatus_TSI_Success;
}

/*FUNCTION**********************************************************************
*
* Function Name : NT_TSI_DRV_EnableLowPower
* Description   : Enables/Disables the low power module.
*
*END**************************************************************************/
tsi_status_t NT_TSI_DRV_EnableLowPower(uint32_t instance)
{
    NT_ASSERT(instance < FSL_FEATURE_SOC_TSI_COUNT);

    TSI_Type * base = g_tsiBase[instance];
    nt_tsi_state_t * tsiState = g_tsiStatePtr[instance];
    tsi_status_t status;

    /* OS: Critical section. Access to global variable */
    if (knt_Status_OSA_Success != NT_OSA_MutexLock(&tsiState->lock, OSA_WAIT_FOREVER))
    {
        return kStatus_TSI_Error;
    }
        
    if ((status = NT_TSI_DRV_ChangeMode(instance, tsi_OpModeLowPower)) != kStatus_TSI_Success)
    {
        /* OS: End of critical section. */
        NT_OSA_MutexUnlock(&tsiState->lock);

        return status;
    }

    if(tsiState->opModesData[tsiState->opMode].enabledElectrodes == 0)
    {
      /* OS: End of critical section. */
        NT_OSA_MutexUnlock(&tsiState->lock);

        return kStatus_TSI_InvalidChannel;
    }
    
    tsiState->status = kStatus_TSI_LowPower;
    
    /* Enable TSI to run in STOP and VLPS mode */
    TSI_EnableModule(base, false);
    TSI_EnableLowPower(base, true);
    TSI_EnableModule(base, true);
    
    /* OS: End of critical section. */
    NT_OSA_MutexUnlock(&tsiState->lock);

    return kStatus_TSI_Success;
}


/*FUNCTION**********************************************************************
*
* Function Name : NT_TSI_DRV_ChangeMode
* Description   : The function change the current mode.
*
*END**************************************************************************/
tsi_status_t NT_TSI_DRV_ChangeMode(uint32_t instance, const nt_tsi_modes_t mode)
{
    NT_ASSERT(instance < FSL_FEATURE_SOC_TSI_COUNT);

    TSI_Type * base = g_tsiBase[instance];
    nt_tsi_state_t * tsiState = g_tsiStatePtr[instance];

    if((mode == tsiState->opMode) || (mode == tsi_OpModeNoChange))
    {
        return  kStatus_TSI_Success;
    }

    if(mode >= tsi_OpModeCnt)
    {
        return kStatus_TSI_InvalidMode;
    }

    /* OS: Critical section. Access to global variable */
    if (knt_Status_OSA_Success != NT_OSA_MutexLock(&tsiState->lockChangeMode, OSA_WAIT_FOREVER))
    {
        return kStatus_TSI_Error;
    }

    if (tsiState->status != kStatus_TSI_Initialized)
    {
        /* OS: End of critical section. */
        NT_OSA_MutexUnlock(&tsiState->lockChangeMode);
        
        return tsiState->status;
    }
        
    tsiState->opMode = mode;

    NT_TSI_DRV_InitSpecific(base, &tsiState->opModesData[mode].config);

    /* OS: End of critical section. */
    NT_OSA_MutexUnlock(&tsiState->lockChangeMode);

    return  kStatus_TSI_Success;
}


/*FUNCTION**********************************************************************
*
* Function Name : NT_TSI_DRV_LoadConfiguration
* Description   : The function load the configuration for one mode of operation.
*
*END**************************************************************************/
tsi_status_t NT_TSI_DRV_LoadConfiguration(uint32_t instance, const nt_tsi_modes_t mode, const nt_tsi_operation_mode_t * operationMode)
{
    NT_ASSERT(instance < FSL_FEATURE_SOC_TSI_COUNT);
    NT_ASSERT(operationMode);
    TSI_Type * base;
    nt_tsi_state_t * tsiState = g_tsiStatePtr[instance];
    
    if(mode >= tsi_OpModeCnt)
    {
        return kStatus_TSI_InvalidMode;
    }

    /* OS: Critical section. Access to global variable */
    if (knt_Status_OSA_Success != NT_OSA_MutexLock(&tsiState->lock, OSA_WAIT_FOREVER))
    {
        return kStatus_TSI_Error;
    }

    tsiState->opModesData[mode] = *operationMode;

    /* In case that the loaded configuration is active one, update the HW also. */
    if(mode == tsiState->opMode)
    {
        base = g_tsiBase[instance];

        NT_TSI_DRV_InitSpecific(base, &tsiState->opModesData[mode].config);
        TSI_EnableInterrupts(base, kTSI_GlobalInterruptEnable);
        TSI_EnableInterrupts(base, kTSI_EndOfScanInterruptEnable);
    }

    /* OS: End of critical section. */
    NT_OSA_MutexUnlock(&tsiState->lock);

    return  kStatus_TSI_Success;
}

/*!
* @brief Get Sinc status flags
* This function get tsi Sinc status flags.
*
* @param    base  TSI peripheral base address.
* @return         The mask of these status flags combination.
*/
static inline uint32_t TSI_GetSincFlags(TSI_Type *base)
{
    return (base->SINC & (kTSI_EndOfScanFlag | kTSI_OutOfRangeFlag));
}

/*!
 * @brief Interrupt handler for TSI.
 * This handler uses the tsi State structure to handle the instance depend data.
 * This is not a public API as it is called whenever an interrupt occurs.
 */
void TSI_DRV_IRQHandler(uint32_t instance)
{
    TSI_Type * base = g_tsiBase[instance];
    nt_tsi_state_t * tsiState = g_tsiStatePtr[instance];
    uint64_t channels = tsiState->opModesData[tsiState->opMode].enabledElectrodes;
    uint64_t next_pen, pen;
    uint32_t curr_channel;

    if(TSI_GetSincFlags(base) & kTSI_SincOverflowFlag)
    {
      tsiState->status = kStatus_TSI_Overflow;
    }
    
    if(tsi_lpwr_status.TSILowPower)
    {
      tsi_lpwr_status.SelfLowPowerCountBuff =  TSI_GetCounter(base);
      tsi_lpwr_status.SelfLowPowerChannelBuff = TSI_GetSelfCapMeasuredChannel(base);
      tsi_lpwr_status.TSILowPower = 0;
    }
    
    /* Clear interrupt flags. */
    TSI_ClearStatusFlags(base, kTSI_OutOfRangeFlag);
    TSI_ClearStatusFlags(base, kTSI_EndOfScanFlag);
    
    /* self-cap electrode was measured */
    if(!(TSI_GetSensingMode(base)))
    {
        curr_channel = TSI_GetSelfCapMeasuredChannel(base);
        
        /* Save TSICNT value */
        if((uint64_t)(1 << curr_channel) & channels)
        {
            tsiState->counters[curr_channel] = ((uint16_t)0xFFFF - TSI_GetCounter(base));
        }
        
        /* Find next enabled electrode */
        next_pen = curr_channel + 1;
        pen = channels;
        while (((((pen >> next_pen) & 0x1U)) == 0U) && (next_pen < (TF_TSI_TOTAL_CHANNEL_COUNT))) 
        {
            next_pen++;
        }
        
        /* If the next electrode is self-cap, get ready for next self-cap measurement */
        if(next_pen < TF_TSI_SELF_CAP_CHANNEL_COUNT)
        {
            /* Measurement must continue on next channel. */
            TSI_SetSelfCapMeasuredChannel(base, next_pen);
            TSI_StartSoftwareTrigger(base);
            tsi_lpwr_status.TSIScanCompleteFlag = 0;
            return;
        }
        /* If the next electrode is mutual-cap, get ready for next mutual-cap measurement (init TSI for mutual-cap)*/
        else if(next_pen < TF_TSI_TOTAL_CHANNEL_COUNT)
        {
            TSI_EnableModule(base, false);
            TSI_InitMutualCapMode(base, &tsiState->opModesData[tsiState->opMode].config.configMutual);
            TSI_SetMutualCapTxChannel(base, (tsi_mutual_tx_channel_t)((next_pen - TF_TSI_SELF_CAP_CHANNEL_COUNT) / TF_TSI_MUTUAL_CAP_RX_CHANNEL_COUNT));
            TSI_SetMutualCapRxChannel(base, (tsi_mutual_rx_channel_t)((next_pen - TF_TSI_SELF_CAP_CHANNEL_COUNT) % TF_TSI_MUTUAL_CAP_RX_CHANNEL_COUNT));
            TSI_EnableHardwareTriggerScan(base, false);
            TSI_EnableModule(base, true);
            TSI_StartSoftwareTrigger(base);
            tsi_lpwr_status.TSIScanCompleteFlag = 0;
            return;
        }
        else
        {
          tsi_lpwr_status.TSIScanCompleteFlag = 1;
        }
    }
    
    /* mutual-cap electrode was measured */
    else
    {
        curr_channel = (uint32_t)TSI_GetRxMutualCapMeasuredChannel(base) + (uint32_t)TSI_GetTxMutualCapMeasuredChannel(base)*TF_TSI_MUTUAL_CAP_RX_CHANNEL_COUNT + TF_TSI_SELF_CAP_CHANNEL_COUNT;
        
        /* Save TSICNT value, artificially increase sensitivity and inverse counter value */
        if(((uint64_t)1 << curr_channel) & channels)
        {
            tsiState->counters[curr_channel] = TSI_GetCounter(base);
        }
        
        /* Find next enabled electrode */
        next_pen = curr_channel + 1;
        pen = channels;
        while (((((pen >> next_pen) & 0x1U)) == 0U) && (next_pen < (TF_TSI_TOTAL_CHANNEL_COUNT))) 
        {
            next_pen++;
        }
        
        /* Get ready for next mutual-cap measurement if there is any */
        if(next_pen < TF_TSI_TOTAL_CHANNEL_COUNT)
        {
            TSI_SetMutualCapTxChannel(base, (tsi_mutual_tx_channel_t)((next_pen - TF_TSI_SELF_CAP_CHANNEL_COUNT) / TF_TSI_MUTUAL_CAP_RX_CHANNEL_COUNT));
            TSI_SetMutualCapRxChannel(base, (tsi_mutual_rx_channel_t)((next_pen - TF_TSI_SELF_CAP_CHANNEL_COUNT) % TF_TSI_MUTUAL_CAP_RX_CHANNEL_COUNT));
            TSI_StartSoftwareTrigger(base);
            return;
        }
        else
        {
          tsi_lpwr_status.TSIScanCompleteFlag = 1;
        }
    }
    
    if(tsiState->pCallBackFunc)
    {
        tsiState->pCallBackFunc(instance, tsiState->usrData);
    }

    if(tsiState->status != kStatus_TSI_LowPower)
    {
        /* Return status of the driver to initialized state */
        tsiState->status = kStatus_TSI_Initialized;
    }
}

/*FUNCTION**********************************************************************
*
* Function Name : NT_TSI_DRV_MeasureAllElect
* Description   : Automatically measures all used TSI electrodes.
*
*END**************************************************************************/
tsi_status_t NT_TSI_DRV_MeasureAllElect(uint32_t instance, uint16_t (*counters)[])
{
    NT_ASSERT(instance < FSL_FEATURE_SOC_TSI_COUNT);
    NT_ASSERT(counters != NULL);
    
    nt_tsi_state_t * tsiState = g_tsiStatePtr[instance];
    TSI_Type * base = g_tsiBase[instance];
    uint64_t pen;
    uint64_t next_pen = 0;
    uint32_t first_pen;
    uint32_t mutual_rx;
    uint32_t mutual_tx;
    uint32_t gencs = 0;
    uint32_t timeout = 1000000;      
    bool is_enabled;
    bool is_int_enabled;            
    
    /* OS: Critical section. Access to global variable */
    if (knt_Status_OSA_Success != NT_OSA_MutexLock(&tsiState->lock, OSA_WAIT_FOREVER))
    {
        return kStatus_TSI_Error;
    }

    if (tsiState->status != kStatus_TSI_Initialized)
    {
      /* OS: End of critical section. */
        NT_OSA_MutexUnlock(&tsiState->lock);
        return tsiState->status;
    }
    
    if(!tsiState->opModesData[tsiState->opMode].enabledElectrodes)
    {
        /* OS: End of critical section. */
        NT_OSA_MutexUnlock(&tsiState->lock);

        return kStatus_TSI_InvalidChannel;
    }

    CLOCK_EnableClock(kCLOCK_Tsi0);
    if (base->GENCS & TSI_GENCS_TSIEN_MASK)
    {
        is_enabled = true;
        TSI_EnableModule(base, false);
    }
    if (base->GENCS & TSI_GENCS_TSIIEN_MASK)
    {
        is_int_enabled = true;
        TSI_DisableInterrupts(base, kTSI_GlobalInterruptEnable);
    }

    while (next_pen < TF_TSI_TOTAL_CHANNEL_COUNT)  /* reused from NT_TSI_DRV_Measure */ 
    {      
        /* If there is a self-cap electrode used, initialize self-cap sensing*/
        if(tsiState->opModesData[tsiState->opMode].enabledElectrodes & 0x01FFFFFFU)
        {
            /* Find electrode with the lowest index */
            first_pen = 0U;
            pen = tsiState->opModesData[tsiState->opMode].enabledElectrodes;
            while (((pen >> first_pen) & 0x1U) == 0U)
            {
                first_pen++;
            }

            /* OS: End of critical section. */
            NT_OSA_MutexUnlock(&tsiState->lock);

            /* Init self-cap sensing */
            TSI_EnableModule(base, false);
            TSI_InitSelfCapMode(base, &tsiState->opModesData[tsiState->opMode].config.configSelfCap);
            TSI_SetSelfCapMeasuredChannel(base, first_pen);
            TSI_EnableHardwareTriggerScan(base, false);
            TSI_EnableModule(base, true);
            TSI_StartSoftwareTrigger(base);
        }
        /* If there are no self-cap electrodes used, initialize mutual-cap sensing*/
        else
        {
            /* Find electrode with the lowest index */
            first_pen = TF_TSI_SELF_CAP_CHANNEL_COUNT;
            pen = tsiState->opModesData[tsiState->opMode].enabledElectrodes;
            while (((pen >> first_pen) & 0x1U) == 0U) {
                first_pen++;
            }
            
            /*Parse electrode number into rx, tx components*/
            mutual_tx = (first_pen - TF_TSI_SELF_CAP_CHANNEL_COUNT) / TF_TSI_MUTUAL_CAP_RX_CHANNEL_COUNT;
            mutual_rx = (first_pen - TF_TSI_SELF_CAP_CHANNEL_COUNT) % TF_TSI_MUTUAL_CAP_RX_CHANNEL_COUNT;
            
            /* OS: End of critical section. */
            NT_OSA_MutexUnlock(&tsiState->lock);

            /* Init mutual-cap sensing */
            TSI_EnableModule(base, false);
            TSI_InitMutualCapMode(base, &tsiState->opModesData[tsiState->opMode].config.configMutual);
            TSI_SetMutualCapTxChannel(base, (tsi_mutual_tx_channel_t)mutual_tx);
            TSI_SetMutualCapRxChannel(base, (tsi_mutual_rx_channel_t)mutual_rx);
            TSI_EnableHardwareTriggerScan(base, false);
            TSI_EnableModule(base, true);
            TSI_StartSoftwareTrigger(base);
        } 
        
        while(1)   /* not an infinite loop, there is break on the end of loop,it can start again a few time. */             
        {  
            uint64_t channels = tsiState->opModesData[tsiState->opMode].enabledElectrodes;
            uint64_t pen;
            uint32_t curr_channel;   
            
            gencs = base->GENCS;
            while(((gencs & TSI_GENCS_EOSF_MASK) == 0U) && (--timeout))
            {
                gencs = base->GENCS;
                /* Do nothing, just to meet MISRA C 2004 rule 14.3 . */            
            }         
            
            /* Clear interrupt flags. */
            TSI_ClearStatusFlags(base, kTSI_OutOfRangeFlag);
            TSI_ClearStatusFlags(base, kTSI_EndOfScanFlag);
            
            /* self-cap electrode was measured */
            if(!(TSI_GetSensingMode(base)))
            {
                curr_channel = TSI_GetSelfCapMeasuredChannel(base);
                
                /* Save TSICNT value */
                if((uint64_t)(1 << curr_channel) & channels)
                {
                    (*counters)[curr_channel] = ((uint16_t)0xFFFF - TSI_GetCounter(base));
                }
                
                /* Find next enabled electrode */
                next_pen = curr_channel + 1;
                pen = channels;
                while (((((pen >> next_pen) & 0x1U)) == 0U) && (next_pen < (TF_TSI_TOTAL_CHANNEL_COUNT))) 
                {
                    next_pen++;
                }
                
                /* If the next electrode is self-cap, get ready for next self-cap measurement */
                if(next_pen < TF_TSI_SELF_CAP_CHANNEL_COUNT)
                {
                    /* Measurement must continue on next channel. */
                    TSI_SetSelfCapMeasuredChannel(base, next_pen);
                    TSI_StartSoftwareTrigger(base);
                    continue;  /* go to next electrode measurement */
                }
                /* If the next electrode is mutual-cap, get ready for next mutual-cap measurement (init TSI for mutual-cap)*/
                else if(next_pen < TF_TSI_TOTAL_CHANNEL_COUNT)
                {
                    TSI_EnableModule(base, false);
                    TSI_InitMutualCapMode(base, &tsiState->opModesData[tsiState->opMode].config.configMutual);
                    TSI_SetMutualCapTxChannel(base, (tsi_mutual_tx_channel_t)((next_pen - TF_TSI_SELF_CAP_CHANNEL_COUNT) / TF_TSI_MUTUAL_CAP_RX_CHANNEL_COUNT));
                    TSI_SetMutualCapRxChannel(base, (tsi_mutual_rx_channel_t)((next_pen - TF_TSI_SELF_CAP_CHANNEL_COUNT) % TF_TSI_MUTUAL_CAP_RX_CHANNEL_COUNT));
                    TSI_EnableHardwareTriggerScan(base, false);
                    TSI_EnableModule(base, true);
                    TSI_StartSoftwareTrigger(base);
                    continue;  /* go to next electrode measurement */
                }
            }       
            /* mutual-cap electrode was measured */
            else
            {
                curr_channel = (uint32_t)TSI_GetRxMutualCapMeasuredChannel(base) + (uint32_t)TSI_GetTxMutualCapMeasuredChannel(base)*TF_TSI_MUTUAL_CAP_RX_CHANNEL_COUNT + TF_TSI_SELF_CAP_CHANNEL_COUNT;
                
                /* Save TSICNT value, artificially increase sensitivity and inverse counter value */
                if(((uint64_t)1 << curr_channel) & channels)
                {
                    (*counters)[curr_channel] = TSI_GetCounter(base);
                }
                
                /* Find next enabled electrode */
                next_pen = curr_channel + 1;
                pen = channels;
                while (((((pen >> next_pen) & 0x1U)) == 0U) && (next_pen < (TF_TSI_TOTAL_CHANNEL_COUNT))) 
                {
                    next_pen++;
                }
                
                /* Get ready for next mutual-cap measurement if there is any */
                if(next_pen < TF_TSI_TOTAL_CHANNEL_COUNT)
                {
                    TSI_SetMutualCapTxChannel(base, (tsi_mutual_tx_channel_t)((next_pen - TF_TSI_SELF_CAP_CHANNEL_COUNT) / TF_TSI_MUTUAL_CAP_RX_CHANNEL_COUNT));
                    TSI_SetMutualCapRxChannel(base, (tsi_mutual_rx_channel_t)((next_pen - TF_TSI_SELF_CAP_CHANNEL_COUNT) % TF_TSI_MUTUAL_CAP_RX_CHANNEL_COUNT));
                    TSI_StartSoftwareTrigger(base);
                    continue; /* go to next electrode measurement */
                }
            }
            break;  /* all electrode measurement finished go out*/
        }    
    }   
       
    if (is_enabled)
    {
        TSI_EnableModule(base, true);
    }
    if (is_int_enabled)
    {
        TSI_EnableInterrupts(base, kTSI_GlobalInterruptEnable);
    }

    tsiState->status = kStatus_TSI_Initialized;

    /* OS: End of critical section. */
    NT_OSA_MutexUnlock(&tsiState->lock);

    return kStatus_TSI_Success;
}

/*FUNCTION**********************************************************************
*
* Function Name : NT_TSI_DRV_MeasureOneElect
* Description   : Automatically measures one electrode.
*
*END**************************************************************************/
int32_t NT_TSI_DRV_MeasureOneElect(uint32_t instance, uint32_t electrode)
{
    NT_ASSERT(instance < FSL_FEATURE_SOC_TSI_COUNT);
    
    nt_tsi_state_t * tsiState = g_tsiStatePtr[instance];
    TSI_Type * base = g_tsiBase[instance];
    uint32_t mutual_rx, mutual_tx;
    uint32_t gencs = 0;
    uint32_t timeout = 1000000;  
    uint32_t ret_val;    
    bool is_enabled;
    bool is_int_enabled;            
    
    /* OS: Critical section. Access to global variable */
    if (knt_Status_OSA_Success != NT_OSA_MutexLock(&tsiState->lock, OSA_WAIT_FOREVER))
    {
        return kStatus_TSI_Error;
    }

    if (tsiState->status != kStatus_TSI_Initialized)
    {
      /* OS: End of critical section. */
        NT_OSA_MutexUnlock(&tsiState->lock);
        return tsiState->status;
    }
    
    if(!tsiState->opModesData[tsiState->opMode].enabledElectrodes)
    {
        /* OS: End of critical section. */
        NT_OSA_MutexUnlock(&tsiState->lock);

        return kStatus_TSI_InvalidChannel;
    }

    CLOCK_EnableClock(kCLOCK_Tsi0);
    if (base->GENCS & TSI_GENCS_TSIEN_MASK)
    {
        is_enabled = true;
        TSI_EnableModule(base, false);
    }
    if (base->GENCS & TSI_GENCS_TSIIEN_MASK)
    {
        is_int_enabled = true;
        TSI_DisableInterrupts(base, kTSI_GlobalInterruptEnable);
    }
     
        /* If there is a self-cap electrode used, initialize self-cap sensing*/
        if (electrode < TF_TSI_SELF_CAP_CHANNEL_COUNT)    
        {
            /* OS: End of critical section. */
            NT_OSA_MutexUnlock(&tsiState->lock);

            /* Init self-cap sensing */
            TSI_EnableModule(base, false);
            TSI_InitSelfCapMode(base, &tsiState->opModesData[tsiState->opMode].config.configSelfCap);
            TSI_SetSelfCapMeasuredChannel(base, electrode);
            TSI_EnableHardwareTriggerScan(base, false);
            TSI_EnableModule(base, true);
            TSI_StartSoftwareTrigger(base);
        }
        /* If there are no self-cap electrodes used, initialize mutual-cap sensing*/
        else
        {           
            /*Parse electrode number into rx, tx components*/
            mutual_tx = (electrode - TF_TSI_SELF_CAP_CHANNEL_COUNT) / TF_TSI_MUTUAL_CAP_RX_CHANNEL_COUNT;
            mutual_rx = (electrode - TF_TSI_SELF_CAP_CHANNEL_COUNT) % TF_TSI_MUTUAL_CAP_RX_CHANNEL_COUNT;
            
            /* OS: End of critical section. */
            NT_OSA_MutexUnlock(&tsiState->lock);

            /* Init mutual-cap sensing */
            TSI_EnableModule(base, false);
            TSI_InitMutualCapMode(base, &tsiState->opModesData[tsiState->opMode].config.configMutual);
            TSI_SetMutualCapTxChannel(base, (tsi_mutual_tx_channel_t)mutual_tx);
            TSI_SetMutualCapRxChannel(base, (tsi_mutual_rx_channel_t)mutual_rx);
            TSI_EnableHardwareTriggerScan(base, false);
            TSI_EnableModule(base, true);
            TSI_StartSoftwareTrigger(base);
        }  
            
            gencs = base->GENCS;
            while(((gencs & TSI_GENCS_EOSF_MASK) == 0U) && (--timeout))
            {
                gencs = base->GENCS;
                /* Do nothing, just to meet MISRA C 2004 rule 14.3 . */            
            }         
            
            /* Clear interrupt flags. */
            TSI_ClearStatusFlags(base, kTSI_OutOfRangeFlag);
            TSI_ClearStatusFlags(base, kTSI_EndOfScanFlag);
            
            /* self-cap electrode was measured */
            if(!(TSI_GetSensingMode(base)))
            {
                ret_val = ((uint16_t)0xFFFF - TSI_GetCounter(base));
            }       
            /* mutual-cap electrode was measured */
            else
            {             
                ret_val = TSI_GetCounter(base);
            }       
    if (is_enabled)
    {
        TSI_EnableModule(base, true);
    }
    if (is_int_enabled)
    {
        TSI_EnableInterrupts(base, kTSI_GlobalInterruptEnable);
    }

    tsiState->status = kStatus_TSI_Initialized;

    /* OS: End of critical section. */
    NT_OSA_MutexUnlock(&tsiState->lock);

    return ret_val;
}

/*FUNCTION**********************************************************************
*
* Function Name : NT_TSI_DRV_Recalibrate
* Description   : Automatically recalibrates all important TSI settings.
*
*END**************************************************************************/
tsi_status_t NT_TSI_DRV_Recalibrate(uint32_t instance, void *configuration)
{
    NT_ASSERT(instance < FSL_FEATURE_SOC_TSI_COUNT);
    NT_ASSERT(configuration != NULL);
    
    nt_tsi_recalib_config_t *recalib_config = (nt_tsi_recalib_config_t*) configuration; 
    nt_tsi_state_t * tsiState = g_tsiStatePtr[instance];
    tsi_config_t *tsi_config;
    tsi_status_t result;
    uint64_t enabledElectrodes;    
    uint32_t minElectVal = 0x7fffffff;
    uint32_t maxElectVal = 0;
    uint32_t resultTemp;
    uint32_t delta = 0;
    uint16_t prev_counters[TF_TSI_TOTAL_CHANNEL_COUNT];  
    uint16_t curr_counters[TF_TSI_TOTAL_CHANNEL_COUNT]; 
    uint16_t curr_channel;
        
    /* OS: Critical section. Access to global variable */
    if (knt_Status_OSA_Success != NT_OSA_MutexLock(&tsiState->lock, OSA_WAIT_FOREVER))
    {
        return kStatus_TSI_Error;
    }

    if (tsiState->status != kStatus_TSI_Initialized)
    {
      /* OS: End of critical section. */
        NT_OSA_MutexUnlock(&tsiState->lock);
        return tsiState->status;
    }
    
    if(!tsiState->opModesData[tsiState->opMode].enabledElectrodes)
    {
        /* OS: End of critical section. */
        NT_OSA_MutexUnlock(&tsiState->lock);

        return kStatus_TSI_InvalidChannel;
    }
    
    tsi_config = &(tsiState->opModesData[tsiState->opMode].config);

    /* Default confing parameter for tunning process */
    /* Self capacitance measurement config */
    tsi_config->configSelfCap.commonConfig.mainClock = kTSI_MainClockSlection_1;         /*!< Set main clock */
    tsi_config->configSelfCap.commonConfig.mode = kTSI_SensingModeSlection_Self;     /*!< Choose sensing mode */
    tsi_config->configSelfCap.commonConfig.dvolt = kTSI_DvoltOption_1;               /*!< DVOLT option value  */
    tsi_config->configSelfCap.commonConfig.cutoff = kTSI_SincCutoffDiv_0;            /*!< Cutoff divider  */
    tsi_config->configSelfCap.commonConfig.order = kTSI_SincFilterOrder_2;           /*!< SINC filter order */
    tsi_config->configSelfCap.commonConfig.decimation = kTSI_SincDecimationValue_3;  /*!< SINC decimation value */
    tsi_config->configSelfCap.commonConfig.chargeNum = kTSI_SscChargeNumValue_5;     /*!< SSC output bit0's period setting */
    tsi_config->configSelfCap.commonConfig.noChargeNum = kTSI_SscNoChargeNumValue_3; /*!< SSC output bit1's period setting */
    tsi_config->configSelfCap.enableSensitivity = true;                              /*!< Enable sensitivity boost of self-cap or not */
    tsi_config->configSelfCap.xdn = kTSI_SensitivityXdnOption_1;                     /*!< Sensitivity XDN option   */
    tsi_config->configSelfCap.ctrim = kTSI_SensitivityCtrimOption_1;                 /*!< Sensitivity CTRIM option */
    tsi_config->configSelfCap.inputCurrent = kTSI_CurrentMultipleInputValue_1;       /*!< Input current multiple   */
    tsi_config->configSelfCap.chargeCurrent = kTSI_CurrentMultipleChargeValue_1;     /*!< Charge/Discharge current multiple */
    /* Mutual capacitance measurement config */
    tsi_config->configMutual.commonConfig.mainClock = kTSI_MainClockSlection_0;      /*!< Set main clock */
    tsi_config->configMutual.commonConfig.mode = kTSI_SensingModeSlection_Mutual;    /*!< Choose sensing mode */
    tsi_config->configMutual.commonConfig.dvolt = kTSI_DvoltOption_2;                /*!< DVOLT option value  */
    tsi_config->configMutual.commonConfig.cutoff = kTSI_SincCutoffDiv_0;             /*!< Cutoff divider  */
    tsi_config->configMutual.commonConfig.order = kTSI_SincFilterOrder_1;            /*!< SINC filter order */
    tsi_config->configMutual.commonConfig.decimation = kTSI_SincDecimationValue_6;   /*!< SINC decimation value */
    tsi_config->configMutual.commonConfig.chargeNum = kTSI_SscChargeNumValue_6;      /*!< SSC output bit0's period setting */
    tsi_config->configMutual.commonConfig.noChargeNum = kTSI_SscNoChargeNumValue_4;  /*!< SSC output bit1's period setting */
    tsi_config->configMutual.preCurrent = kTSI_MutualPreCurrent_4uA;                 /*!< Vref generator current  */
    tsi_config->configMutual.preResistor = kTSI_MutualPreResistor_4k;                /*!< Vref generator resistor */
    tsi_config->configMutual.senseResistor = kTSI_MutualSenseResistor_10k;           /*!< I-sense generator resistor */
    tsi_config->configMutual.boostCurrent = kTSI_MutualSenseBoostCurrent_0uA;        /*!< Sensitivity boost current setting */
    tsi_config->configMutual.txDriveMode = kTSI_MutualTxDriveModeOption_0;           /*!< TX drive mode control setting */
    tsi_config->configMutual.pmosLeftCurrent = kTSI_MutualPmosCurrentMirrorLeft_32;  /*!< Pmos current mirror on the left side  */
    tsi_config->configMutual.pmosRightCurrent = kTSI_MutualPmosCurrentMirrorRight_1; /*!< Pmos current mirror on the right side */
    tsi_config->configMutual.enableNmosMirror = true;                                /*!< Enable Nmos current mirror setting or not */
    tsi_config->configMutual.nmosCurrent = kTSI_MutualNmosCurrentMirror_1; 
    
    /* untouched counter calibration for self-cap mode */
    bool repeat = false;                 
    /* bit field of self-cap electrodes */
    enabledElectrodes = tsiState->opModesData[tsiState->opMode].enabledElectrodes & 0x01FFFFFFU;
    if (enabledElectrodes)          /* if self-capacitance is not enabled go out */
    {
        do 
        {    
            for (curr_channel=0; curr_channel<TF_TSI_TOTAL_CHANNEL_COUNT; curr_channel++)
            {  prev_counters[curr_channel] = 0;                              /* clear array counter */         
            }                                        
            result = NT_TSI_DRV_MeasureAllElect(instance, &prev_counters);   /* measure all electrodes */
            
            for (curr_channel=0; curr_channel<TF_TSI_TOTAL_CHANNEL_COUNT; curr_channel++)
            {                                               
                if (((enabledElectrodes >> curr_channel) & 0x1U) == 0U)      /* avoid mutual channels */
                    continue;                                                
                if (prev_counters[curr_channel] < minElectVal)               /* find min value */
                    minElectVal = prev_counters[curr_channel];               
                if (prev_counters[curr_channel] > maxElectVal)               /* find max value */
                    maxElectVal = prev_counters[curr_channel];  
            }
           
            resultTemp = (minElectVal + maxElectVal) >> 1;     /* average value from min and max measured values */
            repeat = false;                                    /* no next measurement cycle required as default */
            
            if (resultTemp < recalib_config->SelfRangeMin)       /* untached counter value is too low */
            {
                repeat = true;              /* calibration not finished, new measurement required */ 
                minElectVal = 0x7fffffff;   /* reset min value for new measurement */
                maxElectVal = 0;            /* reset max value for new measurement */
                
                if (tsi_config->configSelfCap.commonConfig.decimation > kTSI_SincDecimationValue_1)   /* SINC decimation calib */
                {
                    tsi_config->configSelfCap.commonConfig.decimation -= 1;          
                }            
                else if (tsi_config->configSelfCap.chargeCurrent < kTSI_CurrentMultipleChargeValue_7) /* Charge/Discharge current multiple calib */
                {
                    tsi_config->configSelfCap.chargeCurrent += 1;   
                } 
                else if (tsi_config->configSelfCap.inputCurrent < kTSI_CurrentMultipleInputValue_1)   /* Input current multiple calib */
                {
                    tsi_config->configSelfCap.inputCurrent = kTSI_CurrentMultipleInputValue_1;         
                }
                else if (tsi_config->configSelfCap.commonConfig.dvolt > kTSI_DvoltOption_0)           /* DVOLT option value calib */
                {
                    tsi_config->configSelfCap.commonConfig.dvolt -= 1;                                 
                }
                else if (tsi_config->configSelfCap.commonConfig.cutoff > kTSI_SincCutoffDiv_0)        /* Cutoff divider calib */
                {
                    tsi_config->configSelfCap.commonConfig.cutoff -= 1;                                
                } 
                else
                {   
                    return kStatus_TSI_Error;;   /* no config setting available - go out from calibration */
                }
            }
            else if (resultTemp > recalib_config->SelfRangeMax)  /* untached counter value is too high */
            {
                repeat = true;              /* calibration not finished, new measurement required */ 
                minElectVal = 0x7fffffff;   /* reset min value for new measurement */
                maxElectVal = 0;            /* reset max value for new measurement */
                
                if (tsi_config->configSelfCap.commonConfig.decimation < kTSI_SincDecimationValue_32)  /* SINC decimation calib */
                {                                                                                 
                    tsi_config->configSelfCap.commonConfig.decimation += 1;                           
                }                                                                                 
                else if (tsi_config->configSelfCap.chargeCurrent > kTSI_CurrentMultipleChargeValue_0) /* Charge/Discharge current multiple calib */
                {                                                                                 
                    tsi_config->configSelfCap.chargeCurrent -= 1;                                     
                }                                                                                 
                else if (tsi_config->configSelfCap.inputCurrent > kTSI_CurrentMultipleInputValue_0)   /* Input current multiple calib */
                {                                                                                 
                    tsi_config->configSelfCap.inputCurrent = kTSI_CurrentMultipleInputValue_0;         
                }                                                                                 
                else if (tsi_config->configSelfCap.commonConfig.dvolt < kTSI_DvoltOption_3)           /* DVOLT option value calib */
                {                                                                                 
                    tsi_config->configSelfCap.commonConfig.dvolt += 1;                                 
                }                                                                                 
                else if (tsi_config->configSelfCap.commonConfig.cutoff < kTSI_SincCutoffDiv_128)      /* Cutoff divider calib */
                {
                    tsi_config->configSelfCap.commonConfig.cutoff += 1;                               
                } 
                else
                {   
                    return kStatus_TSI_Error;;   /* no config setting available - go out from calibration */
                }
            }    
        } while (repeat);    /* next calibration cycle required, TSI setting changed */

        /* sensitivity calibration for self-cap mode, it requests one or more touches on self-cap electrode */
        
        do
        { 
            delta = 0;
            /* waiting to touch event to obtain delta value */
            for (curr_channel=0; curr_channel<TF_TSI_TOTAL_CHANNEL_COUNT; curr_channel++)
            {   prev_counters[curr_channel] = 0;    /* clear counter array */
                curr_counters[curr_channel] = 0;    /* clear counter array */
            }
            
            do
            {   int32_t temp32;          
                result = NT_TSI_DRV_MeasureAllElect(instance, &prev_counters);  /* fist measurement for delta */   
                    
                delay();delay();delay();delay();delay();  /* Delay between measurement to make delta higher */
                result = NT_TSI_DRV_MeasureAllElect(instance, &curr_counters);  /* second measurement for delta */ 
                
                /* finding maximum delta on self-cap channels */
                for (curr_channel=0; curr_channel<TF_TSI_TOTAL_CHANNEL_COUNT; curr_channel++)
                {   if (((enabledElectrodes >> curr_channel) & 0x1U) == 0U)      /* avoid mutual channels */
                        continue;
                    temp32 = prev_counters[curr_channel] - curr_counters[curr_channel];
                    if (temp32 < 0)                   /* substraction can be negative therefore absolute value */
                    {
                        temp32 = -temp32; 
                    }
                    if (temp32 > delta)     /* finding maximum */
                    {   
                        delta = temp32;
                    }
                }
                if (delta == 0)  /* to set sensitivity again because of overflow when substract higher C then electrode C */
                {
                    delta = recalib_config->SelfRangeDeltaMax+1;
                }    
            } while ((result == kStatus_TSI_Success) && !(delta > recalib_config->MutRangeDeltaMin>>2));      /* waiting for touch after successful measurement */
            
            if (delta < recalib_config->SelfRangeDeltaMin)
            {
                 tsi_config->configSelfCap.enableSensitivity = true; 
                 if (tsi_config->configSelfCap.xdn < kTSI_SensitivityXdnOption_7)           /* Sensitivity XDN option calib  */
                 {
                     tsi_config->configSelfCap.xdn += 1;             
                 }                  
                 else if (tsi_config->configSelfCap.ctrim < kTSI_SensitivityCtrimOption_7)  /* Sensitivity CTRIM option calib */
                 {
                     tsi_config->configSelfCap.ctrim += 1;  
                 }                 
                 else
                 {   
                     return kStatus_TSI_Error;;
                 }
            } 
            else if (delta > recalib_config->SelfRangeDeltaMax) 
            {
                 tsi_config->configSelfCap.enableSensitivity = true; 
                 if (tsi_config->configSelfCap.xdn > kTSI_SensitivityXdnOption_0)           /* Sensitivity XDN option calib  */
                 {                                                                     
                     tsi_config->configSelfCap.xdn -= 1;                                   
                 } 
                 else if (tsi_config->configSelfCap.ctrim > kTSI_SensitivityCtrimOption_0)  /* Sensitivity CTRIM option calib */
                 {
                     tsi_config->configSelfCap.ctrim -= 1; 
                 }                                                                   
                 else
                 {   
                     return kStatus_TSI_Error;
                 }
            }
        } while ((delta < recalib_config->SelfRangeDeltaMin) || (delta > recalib_config->SelfRangeDeltaMax));  
    }
    
    repeat = false;  
    /* untouched counter calibration for mut-cap mode */                           
    enabledElectrodes = tsiState->opModesData[tsiState->opMode].enabledElectrodes & 0xFFFFFFFFFE000000U ;
    if (enabledElectrodes)          /* if mutual-capacitance is not enabled go out */
    {
        minElectVal = 0x7fffffff;   /* reset min value for new measurement */
        maxElectVal = 0;            /* reset max value for new measurement */
        
        do 
        {    
            for (curr_channel=0; curr_channel<TF_TSI_TOTAL_CHANNEL_COUNT; curr_channel++)
            {  prev_counters[curr_channel] = 0;                              /* clear array counter */         
            }                                        
            result = NT_TSI_DRV_MeasureAllElect(instance, &prev_counters);   /* measure all electrodes */
            
            for (curr_channel=0; curr_channel<TF_TSI_TOTAL_CHANNEL_COUNT; curr_channel++)
            {                                                
                if (((enabledElectrodes >> curr_channel) & 0x1U) == 0U)      /* avoid self channels */
                    continue;                                                
                if (prev_counters[curr_channel] < minElectVal)               /* find min value */
                    minElectVal = prev_counters[curr_channel];               
                if (prev_counters[curr_channel] > maxElectVal)               /* find max value */
                    maxElectVal = prev_counters[curr_channel];  
            }
           
            resultTemp = (minElectVal + maxElectVal) >> 1;     /* average value from min and max measured values */
            repeat = false;                                    /* no next measurement cycle required as default */
            
            if (resultTemp < recalib_config->MutRangeMin)         /* untached counter value is too low */
            {
                repeat = true;              /* calibration not finished, new measurement required */ 
                minElectVal = 0x7fffffff;   /* reset min value for new measurement */
                maxElectVal = 0;            /* reset max value for new measurement */     
                
                if (tsi_config->configMutual.commonConfig.decimation < kTSI_SincDecimationValue_32)   /* SINC decimation calib */
                {
                    tsi_config->configMutual.commonConfig.decimation += 1;     
                }                    
                else if (tsi_config->configMutual.commonConfig.cutoff > kTSI_SincCutoffDiv_0)             /* Cutoff divider calib */
                {
                    tsi_config->configMutual.commonConfig.cutoff -= 1;                                
                }             
            
                else if (tsi_config->configMutual.commonConfig.chargeNum > kTSI_SscChargeNumValue_1) /* SSC output bit0's period setting calib */
                {                                                                                
                    tsi_config->configMutual.commonConfig.chargeNum -= 1;                            
                }                                                                                
                else if (tsi_config->configMutual.preResistor < kTSI_MutualPreResistor_8k)           /* Vref generator resistor  calib */
                {                                                                                
                    tsi_config->configMutual.preResistor += 1;                                       
                }                                                                                
                else if (tsi_config->configMutual.commonConfig.dvolt < kTSI_DvoltOption_3)           /* DVOLT option value calib */
                {
                    tsi_config->configMutual.commonConfig.dvolt += 1;                                 
                }
        
                else
                {   
                    return kStatus_TSI_Error;;   /* no config setting available - go out from calibration */
                }
            }
            else if (resultTemp > recalib_config->MutRangeMax)  /* untached counter value is too high */
            {
                repeat = true;              /* calibration not finished, new measurement required */ 
                minElectVal = 0x7fffffff;   /* reset min value for new measurement */
                maxElectVal = 0;            /* reset max value for new measurement */
                
            
                if (tsi_config->configMutual.commonConfig.decimation > kTSI_SincDecimationValue_1) /* SINC decimation calib */
                {                                                                                 
                    tsi_config->configMutual.commonConfig.decimation -= 1;                           
                } 
                else if (tsi_config->configMutual.commonConfig.cutoff < kTSI_SincCutoffDiv_128)              /* Cutoff divider calib */
                {
                    tsi_config->configMutual.commonConfig.cutoff += 1;                               
                }                 
                else if (tsi_config->configMutual.commonConfig.chargeNum < kTSI_SscChargeNumValue_16)   /* SSC output bit0's period setting calib */
                {
                    tsi_config->configMutual.commonConfig.chargeNum += 1;   
                }                                                                                 
                else if (tsi_config->configMutual.preResistor > kTSI_MutualPreResistor_1k)              /* Vref generator resistor calib */
                {
                    tsi_config->configMutual.preResistor -= 1;         
                }                                                                                 
                else if (tsi_config->configMutual.commonConfig.dvolt > kTSI_DvoltOption_0)              /* DVOLT option value calib */
                {                                                                                 
                    tsi_config->configMutual.commonConfig.dvolt -= 1;                                 
                }                                                                                 
        
                else
                {   
                    return kStatus_TSI_Error;;   /* no config setting available - go out from calibration */
                }
            }    
        } while (repeat);    /* next calibration cycle required, TSI setting changed */
        
        /* sensitivity calibration for mut-cap mode, it requests one or more touches on mut-cap electrode */
        tsi_config->configMutual.enableNmosMirror = true;
        repeat = true;
        do
        { 
            delta = 0;
            /* waiting to touch event to obtain delta value */
            for (curr_channel=0; curr_channel<TF_TSI_TOTAL_CHANNEL_COUNT; curr_channel++)
            {   prev_counters[curr_channel] = 0;    /* clear counter array */
                curr_counters[curr_channel] = 0;    /* clear counter array */
            }
            
            do
              {   int32_t temp32;          
                  result = NT_TSI_DRV_MeasureAllElect(instance, &prev_counters);  /* fist measurement for delta */   
                      
                  delay();delay();delay();delay();delay();  /* Delay between measurement to make delta higher */
                  result = NT_TSI_DRV_MeasureAllElect(instance, &curr_counters);  /* second measurement for delta */ 
                  
                  /* finding maximum delta on self-cap channels */
                  for (curr_channel=0; curr_channel<TF_TSI_TOTAL_CHANNEL_COUNT; curr_channel++)
                  {   if (((enabledElectrodes >> curr_channel) & 0x1U) == 0U)      /* avoid self channels */
                          continue;
                      temp32 = prev_counters[curr_channel] - curr_counters[curr_channel];
                      if (temp32 < 0)                   /* substraction can be negative therefore absolute value */
                      {
                          temp32 = -temp32; 
                      }
                      if (temp32 > delta)               /* finding maximum */
                      {   
                          delta = temp32;
                      }
                  }
                  if (delta == 0)  /* to set sensitivity again because of overflow when substract higher C then electrode C */
                  {
                      delta = recalib_config->MutRangeDeltaMax+1;
                  }    
              } while ((result == kStatus_TSI_Success) && !(recalib_config->MutRangeDeltaMin>>2));      /* waiting for touch after successful measurement */
            
              if (delta < recalib_config->MutRangeDeltaMin)
              {
                   tsi_config->configMutual.enableNmosMirror = true;
                   if (tsi_config->configMutual.boostCurrent < kTSI_MutualSenseBoostCurrent_62uA)  /* Sensitivity boost current calib  */
                   {
                       tsi_config->configMutual.boostCurrent += 1;             
                   } 
                   else
                   {   
                       return kStatus_TSI_Error;;
                   }
              } 
              else if (delta > recalib_config->MutRangeDeltaMax) 
              {
                   tsi_config->configMutual.enableNmosMirror = true;
                   if (tsi_config->configMutual.boostCurrent > kTSI_MutualSenseBoostCurrent_0uA)   /* Sensitivity boost current calib  */
                   {
                       tsi_config->configMutual.boostCurrent -= 1;             
                   } 
                   else
                   {   
                       return kStatus_TSI_Error;
                   }
              }
        } while ((delta < recalib_config->MutRangeDeltaMin) || (delta > recalib_config->MutRangeDeltaMax));  
    }
    uint8_t n;
    for (n=0; n < 10;n++)
    {
        result = NT_TSI_DRV_MeasureAllElect(instance, &prev_counters);  /* fist measurement for delta */   
    }
    
    tsiState->status = kStatus_TSI_Initialized;

    /* OS: End of critical section. */
    NT_OSA_MutexUnlock(&tsiState->lock);

    if(tsiState->opModesData[tsiState->opMode].enabledElectrodes == 0)
    {
        return kStatus_TSI_Error;
    }
    else
    {
        return kStatus_TSI_Success;
     }
}

#endif

/*******************************************************************************
 * EOF
 ******************************************************************************/

