/*FUNCTION**********************************************************************
*
* Function Name : TSI_DRV_ChangeMode
* Description   : The function change the current mode.
*
*END**************************************************************************/
tsi_status_t TSI_DRV_ChangeMode(uint32_t instance, const tsi_modes_t mode)
{
    assert(instance < TSI_INSTANCE_COUNT);

    TSI_Type * base = g_tsiBase[instance];
    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;
    }

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

    if (tsiState->status != kStatus_TSI_Initialized)
    {
        /* End of critical section. */
        OSA_MutexUnlock(&tsiState->lockChangeMode);
        
        return tsiState->status;
    }
    
    if(mode == tsi_OpModeNoise)
    {
        if(!tsiState->opModesData[mode].config.mode)
        {
            /* End of critical section. */
            OSA_MutexUnlock(&tsiState->lockChangeMode);

            return kStatus_TSI_InvalidMode;
        }
    }else
    {
        if(tsiState->opModesData[mode].config.mode)
        {
            /* End of critical section. */
            OSA_MutexUnlock(&tsiState->lockChangeMode);

            return kStatus_TSI_InvalidMode;
        }
    }
    
    tsiState->opMode = mode;

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

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

    return  kStatus_TSI_Success;
}
/*FUNCTION**********************************************************************
*
* Function Name : TSI_DRV_LoadConfiguration
* Description   : The function load the configuration for one mode of operation.
*
*END**************************************************************************/
tsi_status_t TSI_DRV_LoadConfiguration(uint32_t instance, const tsi_modes_t mode, const tsi_operation_mode_t * operationMode)
{
    assert(instance < TSI_INSTANCE_COUNT);
    assert(operationMode);
    TSI_Type * base;
    tsi_state_t * tsiState = g_tsiStatePtr[instance];
    
    if(mode >= tsi_OpModeCnt)
    {
        return kStatus_TSI_InvalidMode;
    }

    /* Critical section. Access to global variable */
    if (kStatus_OSA_Success != 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];

        TSI_HAL_SetConfiguration(base, &tsiState->opModesData[mode].config);
        TSI_HAL_EnableInterrupt(base);
        TSI_HAL_EnableEndOfScanInterrupt(base);
    }

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

    return  kStatus_TSI_Success;
}
/*FUNCTION**********************************************************************
*
* Function Name : TSI_DRV_ChangeMode
* Description   : The function change the current mode.
*
*END**************************************************************************/
tsi_status_t TSI_DRV_ChangeMode(uint32_t instance, const tsi_modes_t mode)
{
    assert(instance < TSI_INSTANCE_COUNT);

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

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

    if(mode >= tsi_OpModeNoise) /* Neither the noise mode is not supported in TSIv1&2 revision. */
    {
        return kStatus_TSI_InvalidMode;
    }

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

    if (tsiState->status != kStatus_TSI_Initialized)
    {
        /* End of critical section. */
        OSA_MutexUnlock(&tsiState->lockChangeMode);
        return tsiState->status;
    }

    tsiState->opMode = mode;

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

    /* Disable all electrodes */
    TSI_HAL_DisableChannels(base, 0xffff);

    /* Enable the set electrodes for current operation mode */
    TSI_HAL_EnableChannels(base, tsiState->opModesData[mode].enabledElectrodes);

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

    return  kStatus_TSI_Success;
}
/*FUNCTION**********************************************************************
*
* Function Name : TSI_DRV_Init
* Description   : Initialize whole the TSI peripheral to be ready to read capacitance changes
* To initialize the TSI driver, the configuration structure should be handled.
*
*END**************************************************************************/
tsi_status_t TSI_DRV_Init(uint32_t instance, tsi_state_t * tsiState, const tsi_user_config_t * tsiUserConfig)
{
    assert(instance < TSI_INSTANCE_COUNT);

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

    /* Critical section. */
    OSA_EnterCritical(kCriticalDisableInt);

    /* Exit if current instance is already initialized. */
    if(tsiSt)
    {
        /* End of critical section. */
        OSA_ExitCritical(kCriticalDisableInt);
        return kStatus_TSI_Initialized;
    }
    /* Save runtime structure pointer.*/
    tsiSt = g_tsiStatePtr[instance] = tsiState;

    /* Clear the state structure for this instance. */
    memset(tsiSt, 0, sizeof(tsi_state_t));

    /* Create the mutex used by whole driver. */
    OSA_MutexCreate(&tsiSt->lock);
    /* Create the mutex used by change mode function. */
    OSA_MutexCreate(&tsiSt->lockChangeMode);
    
    /* Critical section. Access to global variable */
    if (kStatus_OSA_Success != OSA_MutexLock(&tsiSt->lock, OSA_WAIT_FOREVER))
    {
        /* End of critical section. */
        OSA_ExitCritical(kCriticalDisableInt);  
        return kStatus_TSI_Error;
    }

    /* End of critical section. */
    OSA_ExitCritical(kCriticalDisableInt);

    tsiSt->opMode = tsi_OpModeNormal;

    tsiSt->opModesData[tsiSt->opMode].config = *tsiUserConfig->config; /* Store the hardware configuration. */

    tsiSt->pCallBackFunc = tsiUserConfig->pCallBackFunc;
    tsiSt->usrData = tsiUserConfig->usrData;
    tsiSt->isBlockingMeasure = false;
    /* Un-gate TSI module clock */
    CLOCK_SYS_EnableTsiClock(instance);

    /* Initialize the interrupt sync object. */
    OSA_SemaCreate(&tsiSt->irqSync, 0);

    TSI_HAL_Init(base);
    TSI_HAL_SetConfiguration(base, &tsiSt->opModesData[tsiSt->opMode].config);
    TSI_HAL_EnableInterrupt(base);
    TSI_HAL_EnableEndOfScanInterrupt(base);
    TSI_HAL_EnableSoftwareTriggerScan(base);

    /* Disable all electrodes */
    tsiState->opModesData[tsiState->opMode].enabledElectrodes = 0;

    /* Enable TSI interrupt on NVIC level. */
    INT_SYS_EnableIRQ(g_tsiIrqId[instance]);

    tsiSt->status = kStatus_TSI_Initialized;

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

    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(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;
}