1 /*!
2  * @file        tsc_ecs.c
3  *
4  * @brief       This file contains all functions to manage the ECS
5  *
6  * @version     V1.0.1
7  *
8  * @date        2022-09-20
9  *
10  * @attention
11  *
12  *  Copyright (C) 2020-2022 Geehy Semiconductor
13  *
14  *  You may not use this file except in compliance with the
15  *  GEEHY COPYRIGHT NOTICE (GEEHY SOFTWARE PACKAGE LICENSE).
16  *
17  *  The program is only for reference, which is distributed in the hope
18  *  that it will be useful and instructional for customers to develop
19  *  their software. Unless required by applicable law or agreed to in
20  *  writing, the program is distributed on an "AS IS" BASIS, WITHOUT
21  *  ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.
22  *  See the GEEHY SOFTWARE PACKAGE LICENSE for the governing permissions
23  *  and limitations under the License.
24  */
25 
26 /* Includes */
27 #include "tsc.h"
28 #include "tsc_ecs.h"
29 
30 /** @addtogroup TSC_Driver_Library TSC Driver Library
31   @{
32 */
33 
34 /** @addtogroup TSC_ECS_Driver TSC ECS Driver
35   @{
36 */
37 
38 /** @defgroup TSC_ECS_Macros Macros
39   @{
40 */
41 
42 /**@} end of group TSC_ECS_Macros */
43 
44 /** @defgroup TSC_ECS_Enumerations Enumerations
45   @{
46 */
47 
48 /**@} end of group TSC_ECS_Enumerations */
49 
50 /** @defgroup TSC_ECS_Structures Structures
51   @{
52 */
53 
54 /**@} end of group TSC_ECS_Structures */
55 
56 /** @defgroup TSC_ECS_Variables Variables
57   @{
58 */
59 
60 /**@} end of group TSC_ECS_Variables */
61 
62 /** @defgroup TSC_ECS_Functions Functions
63   @{
64 */
65 
66 /*!
67  * @brief       Calculate the K coefficient
68  *
69  * @param       kDiffer: K coefficient when objects have different delta variation
70  *
71  * @param       kSame: K coefficient when objects have the same delta variation
72  *
73  * @retval      K coefficient (differ or same)
74  */
TSC_Ecs_CalculateK(TSC_ObjectGroup_T * objgrp,TSC_tKCoeff_T kDiffer,TSC_tKCoeff_T kSame)75 TSC_tKCoeff_T TSC_Ecs_CalculateK(TSC_ObjectGroup_T* objgrp, TSC_tKCoeff_T kDiffer, TSC_tKCoeff_T kSame)
76 {
77     TSC_tIndex_T   idxObj;
78     TSC_tIndex_T   idxChannel;
79     TSC_tDelta_T   value = 0;
80     TSC_tDelta_T   Cmd = 1;
81     TSC_tDelta_T   Dir = 0;
82     TSC_tNum_T     numChannel = 0;
83     TSC_tKCoeff_T  retval = kDiffer;
84     TSC_Channel_Data_T* p_Ch = 0;
85     CONST TSC_Object_T* pObj;
86 
87     pObj = objgrp->p_Obj;
88 
89     /* Process all objects */
90     for (idxObj = 0; idxObj < objgrp->NbObjects; idxObj++)
91     {
92         TSC_Obj_ConfigGlobalObj(pObj);
93 
94         switch (FOR_OBJ_TYPE)
95         {
96 #if TOUCH_TOTAL_KEYS > 0
97             case TSC_OBJ_TOUCHKEY:
98             case TSC_OBJ_TOUCHKEYB:
99                 if (FOR_KEY_STATEID != TSC_STATEID_RELEASE)
100                 {
101                     pObj++;
102                     continue;
103                 }
104                 numChannel = 1;
105                 p_Ch = TSC_Globals.For_Key->p_ChD;
106                 break;
107 #endif
108 
109 #if TOUCH_TOTAL_LNRTS > 0
110             case TSC_OBJ_LINEAR:
111             case TSC_OBJ_LINEARB:
112             case TSC_OBJ_ROTARY:
113             case TSC_OBJ_ROTARYB:
114                 if (FOR_LINROT_STATEID != TSC_STATEID_RELEASE)
115                 {
116                     pObj++;
117                     continue;
118                 }
119                 numChannel = FOR_LINROT_NB_CHANNELS;
120                 p_Ch = TSC_Globals.For_LinRot->p_ChD;
121                 break;
122 #endif
123             default:
124                 break;
125         }
126 
127         /* Check all channels of current object */
128         for (idxChannel = 0; idxChannel < numChannel; idxChannel++)
129         {
130             value = p_Ch->Delta;
131 
132             if (value)
133             {
134                 if (value >= 0)
135                 {
136                     if (Dir > 0)
137                     {
138                         Dir = 1;
139                     }
140                     else
141                     {
142                         Cmd = 0;
143                     }
144                 }
145                 else
146                 {
147                     if (Dir < 0)
148                     {
149                         Dir = -1;
150                     }
151                     else
152                     {
153                         Cmd = 0;
154                     }
155                 }
156             }
157             else
158             {
159                 Cmd = 0;
160             }
161             p_Ch++;
162         }
163         pObj++;
164     }
165 
166     if (Cmd)
167     {
168         retval = kSame;
169     }
170     return retval;
171 }
172 
173 /*!
174  * @brief       Calculate the new Reference on a group of objects
175  *
176  * @param       objgrp: Pointer to the objects group to process
177  *
178  * @param       kCoeff: K coefficient to apply
179  *
180  * @retval      None
181  */
TSC_Ecs_ProcessK(TSC_ObjectGroup_T * objgrp,TSC_tKCoeff_T kCoeff)182 void TSC_Ecs_ProcessK(TSC_ObjectGroup_T* objgrp, TSC_tKCoeff_T kCoeff)
183 {
184     TSC_tIndex_T        idxObj;
185     TSC_tIndex_T        idxChannel;
186     CONST TSC_Object_T*  pObj;
187     TSC_tKCoeff_T       kCoeffComp;
188     uint32_t            meas, refer;
189     TSC_tNum_T          numChannel = 0;
190     TSC_Channel_Data_T*  p_Ch = 0;
191     void(*pFunc_SetStateCalibration)(TSC_tCounter_T delay) = 0;
192 
193     pObj = objgrp->p_Obj;
194 
195     /* Calculate the K coefficient complement */
196     kCoeffComp = (0xFF ^ kCoeff) + 1;
197 
198     /* Process all objects */
199     for (idxObj = 0; idxObj < objgrp->NbObjects; idxObj++)
200     {
201         TSC_Obj_ConfigGlobalObj(pObj);
202 
203         switch (FOR_OBJ_TYPE)
204         {
205 #if TOUCH_TOTAL_KEYS > 0
206             case TSC_OBJ_TOUCHKEY:
207             case TSC_OBJ_TOUCHKEYB:
208                 if (FOR_KEY_STATEID != TSC_STATEID_RELEASE)
209                 {
210                     pObj++;
211                     continue;
212                 }
213                 numChannel = 1;
214                 p_Ch = TSC_Globals.For_Key->p_ChD;
215                 pFunc_SetStateCalibration = &TSC_TouchKey_ConfigCalibrationState;
216                 break;
217 #endif
218 
219 #if TOUCH_TOTAL_LNRTS > 0
220             case TSC_OBJ_LINEAR:
221             case TSC_OBJ_LINEARB:
222             case TSC_OBJ_ROTARY:
223             case TSC_OBJ_ROTARYB:
224                 if (FOR_LINROT_STATEID != TSC_STATEID_RELEASE)
225                 {
226                     pObj++;
227                     continue;
228                 }
229                 numChannel = FOR_LINROT_NB_CHANNELS;
230                 p_Ch = TSC_Globals.For_LinRot->p_ChD;
231                 pFunc_SetStateCalibration = &TSC_Linrot_ConfigCalibrationState;
232                 break;
233 #endif
234             default:
235                 break;
236         }
237 
238         /* Calculate the new reference + rest for all channels */
239         for (idxChannel = 0; idxChannel < numChannel; idxChannel++)
240         {
241             meas = TSC_Acq_ComputeMeas(p_Ch->Refer, p_Ch->Delta);
242             meas <<= 8;
243 
244             refer = (uint32_t)(p_Ch->Refer);
245             refer <<= 8;
246             refer += p_Ch->RefRest;
247             refer *= kCoeffComp;
248             refer += (kCoeff * meas);
249 
250             p_Ch->RefRest = (TSC_tRefRest_T)((refer >> 8) & 0xFF);
251             p_Ch->Refer = (TSC_tRefer_T)(refer >> 16);
252 
253             /* Go in Calibration state in the Reference is out of Range */
254             if (TSC_Acq_TestReferenceRange(p_Ch) == TSC_TRUE)
255             {
256                 pFunc_SetStateCalibration(0);
257             }
258             p_Ch++;
259         }
260         pObj++;
261     }
262 }
263 
264 /*!
265  * @brief       ECS algorithm on a group of objects
266  *              The ECS is only performed if at least an object is in Release state and
267  *              if no objects are in active states (Prox, Detect or Touch)
268  *              An optional delay is added after the ECS condition (all sensors in Release state) is reached.
269  *
270  * @param       objgrp: Pointer to the objects group to process
271  *
272  * @retval      Status
273  */
TSC_Ecs_Process(TSC_ObjectGroup_T * objgrp)274 TSC_STATUS_T TSC_Ecs_Process(TSC_ObjectGroup_T* objgrp)
275 {
276     TSC_tKCoeff_T myKcoeff;
277     TSC_STATUS_T  retval;
278 
279     if ((objgrp->StateMask & TSC_STATE_RELEASE_BIT_MASK) && !(objgrp->StateMask & TSC_STATEMASK_ACTIVE))
280     {
281 #if TOUCH_ECS_DELAY > 0
282         if (!objgrp->wait)
283         {
284             disableInterrupts();
285             objgrp->time = TSC_Globals.Tick_ms;
286             enableInterrupts();
287             objgrp->wait = 1;
288             objgrp->execution = 0;
289         }
290 #else
291         objgrp->execution = 1;
292 #endif
293     }
294     else
295     {
296 #if TOUCH_ECS_DELAY > 0
297         objgrp->wait = 0;
298 #endif
299         objgrp->execution = 0;
300     }
301 
302 #if TOUCH_ECS_DELAY > 0
303     if (objgrp->wait && (!objgrp->execution))
304     {
305         if (TSC_Time_Delay_ms(TOUCH_ECS_DELAY, &objgrp->time) == TSC_STATUS_OK)
306         {
307             objgrp->execution = 1;
308         }
309     }
310 #endif
311 
312     if (objgrp->execution == 0)
313     {
314         retval = TSC_STATUS_BUSY;
315     }
316     else
317     {
318         /* Calculate the K coefficient */
319         myKcoeff = TSC_Ecs_CalculateK(objgrp, TOUCH_ECS_K_DIFFER, TOUCH_ECS_K_SAME);
320         /* Process the objects */
321         TSC_Ecs_ProcessK(objgrp, myKcoeff);
322         retval = TSC_STATUS_OK;
323     }
324     return retval;
325 }
326 
327 /**@} end of group TSC_ECS_Functions */
328 /**@} end of group TSC_ECS_Driver */
329 /**@} end of group TSC_Driver_Library */
330