/**
******************************************************************************
* @file tsl_ecs.c
* @author MCD Application Team
* @version V1.4.4
* @date 31-March-2014
* @brief This file contains all functions to manage the ECS.
******************************************************************************
* @attention
*
*
© COPYRIGHT 2014 STMicroelectronics
*
* 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_ecs.h"
#include "tsl_globals.h"
#include "stm32f0xx_conf.h"
/* Private typedefs ----------------------------------------------------------*/
/* Private defines -----------------------------------------------------------*/
#define THIS_OBJ_TYPE TSL_Globals.This_Obj->Type
#define THIS_TKEY_REF TSL_Globals.This_TKey->p_ChD->Ref
#define THIS_TKEY_REFREST TSL_Globals.This_TKey->p_ChD->RefRest
#define THIS_TKEY_DELTA TSL_Globals.This_TKey->p_ChD->Delta
#define THIS_TKEY_STATEID TSL_Globals.This_TKey->p_Data->StateId
#define THIS_LINROT_STATEID TSL_Globals.This_LinRot->p_Data->StateId
#define THIS_LINROT_NB_CHANNELS TSL_Globals.This_LinRot->NbChannels
/* Private macros ------------------------------------------------------------*/
#define IS_K_COEFF_OK(COEFF) (((COEFF) == 0) || (((COEFF) > 0) && ((COEFF) < 256)))
#define IS_POINTER_INITIALIZED(POINTER) ((POINTER) != 0)
/* Private variables ---------------------------------------------------------*/
/* Private functions prototype -----------------------------------------------*/
/**
* @brief Calculate the K coefficient
* @param[in] objgrp Pointer to the objects group to process
* @param[in] k_slow K coefficient when objects have different delta variation
* @param[in] k_fast K coefficient when objects have the same delta variation
* @retval K coefficient (slow or fast)
*/
TSL_tKCoeff_T TSL_ecs_CalcK(TSL_ObjectGroup_T *objgrp, TSL_tKCoeff_T k_slow, TSL_tKCoeff_T k_fast)
{
TSL_tIndex_T idx_obj; // Index of current object
TSL_tIndex_T idx_ch; // Index of current channel
TSL_tDelta_T ldelta = 0; // Temporary delta
TSL_tDelta_T ECS_Fast_Enable = 1;
TSL_tDelta_T ECS_Fast_Direction = 0;
CONST TSL_Object_T *pobj;
TSL_tKCoeff_T retval = k_slow;
TSL_tNb_T nb_channels = 0; // Number of channels inside current object
TSL_ChannelData_T *p_Ch = 0;
// Check parameters (if USE_FULL_ASSERT is defined)
assert_param(IS_K_COEFF_OK(k_slow));
assert_param(IS_K_COEFF_OK(k_fast));
pobj = objgrp->p_Obj; // First object in the group
// Process all objects
for (idx_obj = 0; idx_obj < objgrp->NbObjects; idx_obj++)
{
// Assign global object
TSL_obj_SetGlobalObj(pobj);
#if TSLPRM_TOTAL_TKEYS > 0
if ((THIS_OBJ_TYPE == TSL_OBJ_TOUCHKEY) || (THIS_OBJ_TYPE == TSL_OBJ_TOUCHKEYB))
{
// Ignore object if not in Release state (OFF or Error in this case)
if (THIS_TKEY_STATEID != TSL_STATEID_RELEASE)
{
pobj++; // Next object
continue; // Stop processing of current object
}
nb_channels = 1;
p_Ch = TSL_Globals.This_TKey->p_ChD;
}
#endif
#if TSLPRM_TOTAL_LNRTS > 0
if ((THIS_OBJ_TYPE == TSL_OBJ_LINEAR) || (THIS_OBJ_TYPE == TSL_OBJ_LINEARB) ||
(THIS_OBJ_TYPE == TSL_OBJ_ROTARY) || (THIS_OBJ_TYPE == TSL_OBJ_ROTARYB))
{
// Ignore object if not in Release state (OFF or Error in this case)
if (THIS_LINROT_STATEID != TSL_STATEID_RELEASE)
{
pobj++; // Next object
continue; // Stop processing of current object
}
nb_channels = THIS_LINROT_NB_CHANNELS;
p_Ch = TSL_Globals.This_LinRot->p_ChD;
}
#endif
// Check channel pointer variable (if USE_FULL_ASSERT is defined)
assert_param(IS_POINTER_INITIALIZED(p_Ch));
// Check all channels of current object
for (idx_ch = 0; idx_ch < nb_channels; idx_ch++)
{
ldelta = p_Ch->Delta;
// Check delta
if (ldelta == 0) // No Fast ECS !
{
ECS_Fast_Enable = 0;
}
else
{
if (ldelta < 0)
{
if (ECS_Fast_Direction > 0) // No Fast ECS !
{
ECS_Fast_Enable = 0;
}
else
{
ECS_Fast_Direction = -1;
}
}
else
{
if (ECS_Fast_Direction < 0) // No Fast ECS !
{
ECS_Fast_Enable = 0;
}
else
{
ECS_Fast_Direction = 1;
}
}
}
p_Ch++; // Next channel
} // for all channels of current object
pobj++; // Next object
} // for all objects
// Assign K fast following Delta variations
if (ECS_Fast_Enable)
{
retval = k_fast;
}
return retval;
}
/**
* @brief Calculate the new Reference on a group of objects
* @param[in] objgrp Pointer to the objects group to process
* @param[in] Kcoeff K coefficient to apply
* @retval None
*/
void TSL_ecs_ProcessK(TSL_ObjectGroup_T *objgrp, TSL_tKCoeff_T Kcoeff)
{
TSL_tIndex_T idx_obj; // Index of current object
TSL_tIndex_T idx_ch; // Index of current channel
CONST TSL_Object_T *pobj;
TSL_tKCoeff_T Kcoeff_comp;
uint32_t ECS_meas;
uint32_t ECS_ref;
TSL_tNb_T nb_channels = 0; // Number of channels inside current object
TSL_ChannelData_T *p_Ch = 0;
void(*pFunc_SetStateCalibration)(TSL_tCounter_T delay) = 0;
// Check parameters (if USE_FULL_ASSERT is defined)
assert_param(IS_K_COEFF_OK(Kcoeff));
pobj = objgrp->p_Obj; // First object in the group
// Calculate the K coefficient complement
Kcoeff_comp = (0xFF ^ Kcoeff) + 1;
// Process all objects
for (idx_obj = 0; idx_obj < objgrp->NbObjects; idx_obj++)
{
// Assign global object
TSL_obj_SetGlobalObj(pobj);
#if TSLPRM_TOTAL_TKEYS > 0
if ((THIS_OBJ_TYPE == TSL_OBJ_TOUCHKEY) || (THIS_OBJ_TYPE == TSL_OBJ_TOUCHKEYB))
{
// Ignore object if not in Release state (OFF or Error in this case)
if (THIS_TKEY_STATEID != TSL_STATEID_RELEASE)
{
pobj++; // Next object
continue; // Stop processing of current object
}
nb_channels = 1;
p_Ch = TSL_Globals.This_TKey->p_ChD;
pFunc_SetStateCalibration = &TSL_tkey_SetStateCalibration;
}
#endif
#if TSLPRM_TOTAL_LNRTS > 0
if ((THIS_OBJ_TYPE == TSL_OBJ_LINEAR) || (THIS_OBJ_TYPE == TSL_OBJ_LINEARB) ||
(THIS_OBJ_TYPE == TSL_OBJ_ROTARY) || (THIS_OBJ_TYPE == TSL_OBJ_ROTARYB))
{
// Ignore object if not in Release state (OFF or Error in this case)
if (THIS_LINROT_STATEID != TSL_STATEID_RELEASE)
{
pobj++; // Next object
continue; // Stop processing of current object
}
nb_channels = THIS_LINROT_NB_CHANNELS;
p_Ch = TSL_Globals.This_LinRot->p_ChD;
pFunc_SetStateCalibration = &TSL_linrot_SetStateCalibration;
}
#endif
// Check channel pointer variable (if USE_FULL_ASSERT is defined)
assert_param(IS_POINTER_INITIALIZED(p_Ch));
// Calculate the new reference + rest for all channels
for (idx_ch = 0; idx_ch < nb_channels; idx_ch++)
{
ECS_meas = TSL_acq_ComputeMeas(p_Ch->Ref, p_Ch->Delta);
ECS_meas <<= 8;
ECS_ref = (uint32_t)(p_Ch->Ref);
ECS_ref <<= 8;
ECS_ref += p_Ch->RefRest;
ECS_ref *= Kcoeff_comp;
ECS_ref += (Kcoeff * ECS_meas);
p_Ch->RefRest = (TSL_tRefRest_T)((ECS_ref >> 8) & 0xFF);
p_Ch->Ref = (TSL_tRef_T)(ECS_ref >> 16);
// Go in Calibration state in the Reference is out of Range
if (TSL_acq_TestReferenceOutOfRange(p_Ch) == TSL_TRUE)
{
pFunc_SetStateCalibration(0);
}
p_Ch++; // Next channel
}
pobj++; // Next object
} // for all objects
}
/**
* @brief ECS algorithm on a group of objects
* The ECS is only performed if at least an object is in Release state and
* if no objects are in active states (Prox, Detect or Touch)
* An optional delay is added after the ECS condition (all sensors in Release state) is reached.
* @param[in] objgrp Pointer to the objects group to process
* @retval Status
*/
TSL_Status_enum_T TSL_ecs_Process(TSL_ObjectGroup_T *objgrp)
{
TSL_tKCoeff_T MyKcoeff;
TSL_Status_enum_T retval;
if ((objgrp->StateMask & TSL_STATE_RELEASE_BIT_MASK) && !(objgrp->StateMask & TSL_STATEMASK_ACTIVE))
{
#if TSLPRM_ECS_DELAY > 0
if (!objgrp->ECS_wait)
{
disableInterrupts();
objgrp->ECS_start_time = TSL_Globals.Tick_ms; // Save the current time
enableInterrupts();
objgrp->ECS_wait = 1;
objgrp->ECS_exec = 0;
}
#else
objgrp->ECS_exec = 1;
#endif
}
else
{
#if TSLPRM_ECS_DELAY > 0
objgrp->ECS_wait = 0;
#endif
objgrp->ECS_exec = 0;
}
#if TSLPRM_ECS_DELAY > 0
if (objgrp->ECS_wait && (!objgrp->ECS_exec))
{
// Execute the ECS only when the delay has elapsed
if (TSL_tim_CheckDelay_ms(TSLPRM_ECS_DELAY, &objgrp->ECS_start_time) == TSL_STATUS_OK)
{
objgrp->ECS_exec = 1;
}
}
#endif
if (objgrp->ECS_exec)
{
// Calculate the K coefficient
MyKcoeff = TSL_ecs_CalcK(objgrp, TSLPRM_ECS_K_SLOW, TSLPRM_ECS_K_FAST);
// Process the objects
TSL_ecs_ProcessK(objgrp, MyKcoeff);
retval = TSL_STATUS_OK;
}
else
{
retval = TSL_STATUS_BUSY;
}
return retval;
}
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/