/*FUNCTION**********************************************************************
*
* Function Name : TSI_DRV_DeInit
* Description   : De initialize whole the TSI peripheral and driver to be ready
* for any future use and don't load the system.
*
*END**************************************************************************/
tsi_status_t TSI_DRV_DeInit(uint32_t instance)
{
    assert(instance < TSI_INSTANCE_COUNT);

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

    if (tsiState == NULL)
    {
        return kStatus_TSI_Error;
    }

    TSI_HAL_DisableInterrupt(base);
    tsiState->opModesData[tsiState->opMode].enabledElectrodes = 0;
    TSI_HAL_ClearOutOfRangeFlag(base);
    TSI_HAL_ClearEndOfScanFlag(base);
    TSI_HAL_DisableModule(base);

    /* Disable the interrupt */
    INT_SYS_DisableIRQ(g_tsiIrqId[instance]);

    /* Destroy the interrupt synch object*/
    OSA_SemaDestroy(&tsiState->irqSync);

    /* Clear runtime structure pointer.*/
    tsiState = NULL;

    /* Gate TSI module clock */
    CLOCK_SYS_DisableTsiClock(instance);

    return kStatus_TSI_Success;
}
/*FUNCTION**********************************************************************
*
* Function Name : TSI_HAL_MeasurementBlocking
* Description   : Function do blocking measurement of enabled electrodes
*                 It used just for recalibration process
*END**************************************************************************/
static int32_t TSI_HAL_MeasurementBlocking(TSI_Type * base)
{
  int32_t result = -1;
  uint32_t timeout = 10000000; /* Big timeout */ 
  
  if (TSI_RD_PEN(base)) {

    /* measure only if at least one electrode is enabled */
    TSI_HAL_EnableSoftwareTriggerScan(base);
    TSI_HAL_EnableModule(base);
    TSI_HAL_StartSoftwareTrigger(base);

    while((TSI_HAL_GetEndOfScanFlag(base) == 0U) && (timeout--))
    {
      /* Do nothing, just to meet MISRA C 2004 rule 14.3 . */
    }
    TSI_HAL_ClearEndOfScanFlag(base);
    TSI_HAL_DisableModule(base);

    if(timeout)
    {
      result = 0;
    }
  }
  return result;
}
/*FUNCTION**********************************************************************
*
* Function Name : TSI_HAL_MeasurementBlocking
* Description   : Function do blocking measurement of enabled electrodes
*                 It used just for recalibration process
*END**************************************************************************/
static int32_t TSI_HAL_MeasurementBlocking(TSI_Type * base, uint32_t electrode, uint32_t noise_mode)
{
    int32_t result;
    uint32_t timeout = 1000000;
    /* measure only if at least one electrode is enabled */
    TSI_HAL_EnableSoftwareTriggerScan(base);
    TSI_HAL_SetMeasuredChannelNumber(base, electrode);
    TSI_HAL_SetMode(base, TSI_HAL_GetMode(base)); /* force to HW right analog mode. */    
    TSI_HAL_EnableModule(base);
    TSI_HAL_StartSoftwareTrigger(base);
    
    while((TSI_HAL_GetEndOfScanFlag(base) == 0U) && (--timeout))
    {
      /* Do nothing, just to meet MISRA C 2004 rule 14.3 . */
    }
    
    if(timeout == 0)
    {
      result = 0;
    }else
    {
      if(noise_mode)
      {
        result = TSI_HAL_GetNoiseResult(base);
      }else
      {
        result = TSI_HAL_GetCounter(base);
      }
    }
    
    TSI_HAL_ClearEndOfScanFlag(base);
    TSI_HAL_DisableModule(base);
    
    return result;
}
/*!
 * @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];
    tsi_state_t * tsiState = g_tsiStatePtr[instance];
    uint32_t channels = tsiState->opModesData[tsiState->opMode].enabledElectrodes;
    uint32_t curr_channel = TSI_HAL_GetMeasuredChannelNumber(base);
    uint32_t next_pen, pen;
    /* Check if a measure is running and wanted. */

    TSI_HAL_ClearOutOfRangeFlag(base);
    TSI_HAL_ClearEndOfScanFlag(base);

    if((uint32_t)(1 << curr_channel) & channels)
    {
        /* Am I in noise mode? */
        if(tsiState->opMode == tsi_OpModeNoise)
        {
            tsiState->counters[curr_channel] = TSI_HAL_GetMode(base);
        }
        else
        {
            tsiState->counters[curr_channel] = TSI_HAL_GetCounter(base);
        }
    }
    
    next_pen = curr_channel + 1;
    pen = channels;
    while (((((pen >> next_pen) & 0x1U)) == 0U) && (next_pen < 16)) 
    {
        next_pen++;
    }
    
    if(next_pen < 16)
    {
        /* Measurement must continue on next channel. */
        TSI_HAL_SetMeasuredChannelNumber(base, next_pen);
        TSI_HAL_StartSoftwareTrigger(base);
        return;
    }
    
    if(tsiState->isBlockingMeasure)
    {
        /* Signal the synchronous completion object. */
        OSA_SemaPost(&tsiState->irqSync);
        tsiState->isBlockingMeasure = false;
    }
    else 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;
    }
}
/*!
 * @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];
    uint32_t channels = TSI_HAL_GetEnabledChannels(base);
    uint32_t i;
    tsi_state_t * tsiState = g_tsiStatePtr[instance];
    /* Check if a measure is running and wanted. */

    if(tsiState->status != kStatus_TSI_Busy)
    {
        return;
    }

    TSI_HAL_ClearOutOfRangeFlag(base);
    TSI_HAL_ClearEndOfScanFlag(base);

    for(i = 0; i < FSL_FEATURE_TSI_CHANNEL_COUNT; i++)
    {
        if((uint32_t)(1 << i) & channels)
        {
            tsiState->counters[i] = TSI_HAL_GetCounter(base, i);
        }
    }


    if(tsiState->isBlockingMeasure)
    {
        /* Signal the synchronous completion object. */
        OSA_SemaPost(&tsiState->irqSync);
        tsiState->isBlockingMeasure = false;
    }
    else 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 : TSI_DRV_AbortMeasure
* Description   : This function aborts possible measure cycle.
*
*END**************************************************************************/
tsi_status_t TSI_DRV_AbortMeasure(uint32_t instance)
{
    assert(instance < TSI_INSTANCE_COUNT);

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

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

    if(tsiState->status == kStatus_TSI_Recalibration)
    {
       status = kStatus_TSI_Recalibration;
    }
    else if(tsiState->status != kStatus_TSI_Initialized)
    {
        TSI_HAL_ClearOutOfRangeFlag(base);
        TSI_HAL_ClearEndOfScanFlag(base);
        TSI_HAL_DisableModule(base);

        if(tsiState->isBlockingMeasure)
        {
            /* Signal the synchronous completion object. */
            OSA_SemaPost(&tsiState->irqSync);
            tsiState->isBlockingMeasure = false;
        }

        /* Return status of the driver to initialized state */
        tsiState->status = kStatus_TSI_Initialized;
    }

    /* End of critical section. */
    OSA_MutexUnlock(&tsiState->lock);

    return status;
}