/*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;
}
/*FUNCTION**********************************************************************
*
* Function Name : 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 TSI_DRV_Measure(uint32_t instance)
{
    assert(instance < TSI_INSTANCE_COUNT);

    TSI_Type * base = g_tsiBase[instance];
    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_Initialized)
    {
        /* End of critical section. */
        OSA_MutexUnlock(&tsiState->lock);

        return tsiState->status;
    }

    tsiState->status = kStatus_TSI_Busy;

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

    TSI_HAL_DisableModule(base);
    TSI_HAL_EnableSoftwareTriggerScan(base);
    TSI_HAL_EnableModule(base);
    TSI_HAL_StartSoftwareTrigger(base);

    return kStatus_TSI_Success;
}
uint32_t TSI_HAL_Recalibrate(TSI_Type * base, tsi_config_t *config, const uint32_t electrodes, const tsi_parameter_limits_t *parLimits)
{
    assert(config != NULL);
    
    uint32_t is_enabled = TSI_HAL_IsModuleEnabled(base);
    uint32_t is_int_enabled = TSI_HAL_IsInterruptEnabled(base);
    uint32_t lowest_signal = TSI_RECALIBRATE_MAX_SIGNAL_VAL;
    
    if (is_enabled) {
        TSI_HAL_DisableModule(base);
    }
    if (is_int_enabled) {
        TSI_HAL_DisableInterrupt(base);
    }

    TSI_HAL_SetNumberOfScans(base, config->nscn);
    TSI_HAL_SetPrescaler(base, config->ps);
    TSI_HAL_SetElectrodeChargeCurrent(base, config->extchrg);
    TSI_HAL_SetReferenceChargeCurrent(base, config->refchrg);

    TSI_HAL_EnableModule(base);

    if (TSI_HAL_MeasurementBlocking(base) == 0) {
        for (uint32_t i = 0U; i < 16U; i++) {
            if (TSI_HAL_GetEnabledChannel(base, i)) {
                int32_t counter = TSI_HAL_GetCounter(base, i);
                if (counter < lowest_signal) {
                    lowest_signal = counter;
                }
            }
        }
    }

    if (!is_enabled) {
        TSI_HAL_EnableModule(base);
    }
    if (is_int_enabled) {
        TSI_HAL_EnableInterrupt(base);
    }
    if (lowest_signal == TSI_RECALIBRATE_MAX_SIGNAL_VAL) {
        lowest_signal = 0U;  /* not valid */
    }

    return lowest_signal;
}
/*FUNCTION**********************************************************************
*
* Function Name : 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 TSI_DRV_Measure(uint32_t instance)
{
    assert(instance < TSI_INSTANCE_COUNT);

    TSI_Type * base = g_tsiBase[instance];
    tsi_state_t * tsiState = g_tsiStatePtr[instance];
    uint32_t    first_pen, pen;
    
    /* 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_Initialized)
    {
        /* End of critical section. */
        OSA_MutexUnlock(&tsiState->lock);

        return tsiState->status;
    }

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

        return kStatus_TSI_InvalidChannel;
    }
    
    tsiState->status = kStatus_TSI_Busy;

    first_pen = 0U;
    pen = tsiState->opModesData[tsiState->opMode].enabledElectrodes;
    while (((pen >> first_pen) & 0x1U) == 0U) {
        first_pen++;
    }
    
    /* End of critical section. */
    OSA_MutexUnlock(&tsiState->lock);

    TSI_HAL_DisableModule(base);
    TSI_HAL_SetMeasuredChannelNumber(base, first_pen);
    TSI_HAL_EnableSoftwareTriggerScan(base);
    TSI_HAL_EnableModule(base);
    TSI_HAL_StartSoftwareTrigger(base);

    return kStatus_TSI_Success;
}
/*FUNCTION**********************************************************************
*
* Function Name : TSI_HAL_SetConfiguration
* Description   : Function set the whole TSI peripheral by handled configuration
*
*END**************************************************************************/
void TSI_HAL_SetConfiguration(TSI_Type * base, tsi_config_t *config)
{
    assert(config != NULL);

    uint32_t is_enabled = TSI_HAL_IsModuleEnabled(base);
    uint32_t is_int_enabled = TSI_HAL_IsInterruptEnabled(base);
    
    if (is_enabled) {
        TSI_HAL_DisableModule(base);
    }
    if (is_int_enabled) {
        TSI_HAL_DisableInterrupt(base);
    }
    
    if(config->mode == kTsiAnalogModeSel_AutoNoise)
    {
     TSI_HAL_SetMode(base, config->mode); 
     TSI_HAL_SetPrescaler(base, config->ps);
     TSI_HAL_SetNumberOfScans(base, config->nscn);
     TSI_HAL_SetReferenceChargeCurrent(base, config->refchrg);
     TSI_HAL_SetOscilatorVoltageRails(base, config->dvolt);
     TSI_HAL_SetElectrodeSeriesResistor(base, config->serres);
     TSI_HAL_SetFilterBits(base, config->filter);
    }
    
    else
    {  
     TSI_HAL_SetPrescaler(base, config->ps);
     TSI_HAL_SetNumberOfScans(base, config->nscn);
     TSI_HAL_SetReferenceChargeCurrent(base, config->refchrg);
     TSI_HAL_SetElectrodeChargeCurrent(base, config->extchrg);
     TSI_HAL_SetMode(base, config->mode);
     TSI_HAL_SetOscilatorVoltageRails(base, config->dvolt);
     TSI_HAL_SetLowThreshold(base, config->thresl);
     TSI_HAL_SetHighThreshold(base, config->thresh);
    }
    
    if (is_enabled) {
        TSI_HAL_EnableModule(base);
    }
    if (is_int_enabled) {
        TSI_HAL_EnableInterrupt(base);
    }
}
uint32_t TSI_HAL_Recalibrate(TSI_Type * base, tsi_config_t *config, const uint32_t electrodes, const tsi_parameter_limits_t *parLimits)
{
    assert(config != NULL);

    uint32_t is_enabled = TSI_HAL_IsModuleEnabled(base);
    uint32_t is_int_enabled = TSI_HAL_IsInterruptEnabled(base);
    uint32_t lowest_signal = TSI_RECALIBRATE_MAX_SIGNAL_VAL;

    if(electrodes == 0)
    {
      return 0;
    }
    
    if (is_enabled) {
        TSI_HAL_DisableModule(base);
    }
    if (is_int_enabled) {
        TSI_HAL_DisableInterrupt(base);
    }
    
    if(parLimits == NULL) /* If NOISE mode calibration*/
    {
      /* parLimits are not used in NOISE mode so this is calibration of noise mode. */      
      TSI_HAL_SetConfiguration(base, config);
      
      lowest_signal = 1;      
      
    }else
    {
      // Normal capacitive mode calibration 
      TSI_HAL_SetNumberOfScans(base, config->nscn);
      TSI_HAL_SetPrescaler(base, config->ps);
      TSI_HAL_SetElectrodeChargeCurrent(base, config->extchrg);
      TSI_HAL_SetReferenceChargeCurrent(base, config->refchrg);

       TSI_HAL_EnableModule(base);

      for (uint32_t i = 0U; i < 16U; i++) 
          {
          if ((uint32_t)(1 << i) & electrodes) 
                  {
              int32_t counter = TSI_HAL_MeasurementBlocking(base, i, 0);
              if (counter < lowest_signal) {
                  lowest_signal = counter;
              }
          }
      }
    }
    
    if (!is_enabled) {
        TSI_HAL_EnableModule(base);
    }
    if (is_int_enabled) {
        TSI_HAL_EnableInterrupt(base);
    }
    if (lowest_signal == TSI_RECALIBRATE_MAX_SIGNAL_VAL) {
        lowest_signal = 0U;  /* not valid */
    }

    return lowest_signal;
}
/*FUNCTION**********************************************************************
*
* Function Name : TSI_DRV_EnableLowPower
* Description   : Enables/Disables the low power module.
*
*END**************************************************************************/
tsi_status_t TSI_DRV_EnableLowPower(uint32_t instance)
{
    assert(instance < TSI_INSTANCE_COUNT);

    TSI_Type * base = g_tsiBase[instance];
    tsi_state_t * tsiState = g_tsiStatePtr[instance];
    tsi_status_t status;
    uint32_t i;
    int32_t channel = -1;

    /* Critical section. Access to global variable */
    if (kStatus_OSA_Success != OSA_MutexLock(&tsiState->lock, OSA_WAIT_FOREVER))
    {
        return kStatus_TSI_Error;
    }
    
    if((tsiState->opModesData[tsiState->opMode].config.thresl == 0) || (tsiState->opModesData[tsiState->opMode].config.thresh == 0))
    {
        /* End of critical section. */
        OSA_MutexUnlock(&tsiState->lock);

        return kStatus_TSI_Error;
    }
    
    if ((status = TSI_DRV_ChangeMode(instance, tsi_OpModeLowPower)) != kStatus_TSI_Success)
    {
        /* End of critical section. */
        OSA_MutexUnlock(&tsiState->lock);

        return status;
    }

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

        return kStatus_TSI_InvalidChannel;
    }

    /* Configurate the peripheral for next use */
    TSI_HAL_EnableOutOfRangeInterrupt(base);
    TSI_HAL_EnableHardwareTriggerScan(base);

    for(i = 0; i < FSL_FEATURE_TSI_CHANNEL_COUNT; i++)
    {
        if((uint32_t)(1 << i) & tsiState->opModesData[tsiState->opMode].enabledElectrodes)
        {
            channel = i;
            break;
        }
    }

    if(channel == -1)
    {
        /* End of critical section. */
        OSA_MutexUnlock(&tsiState->lock);

        return kStatus_TSI_InvalidChannel;  
    }
    
    tsiState->status = kStatus_TSI_LowPower;
    
    TSI_HAL_EnableLowPower(base);
    TSI_HAL_SetMeasuredChannelNumber(base, channel);
    TSI_HAL_EnableInterrupt(base);
    TSI_HAL_EnableModule(base);
    
    /* End of critical section. */
    OSA_MutexUnlock(&tsiState->lock);

    return kStatus_TSI_Success;
}