/* --COPYRIGHT--,BSD * Copyright (c) 2013, Texas Instruments Incorporated * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name of Texas Instruments Incorporated nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * --/COPYRIGHT--*/ /*! * @file CTS_Layer.c * * @brief This source file contains the API calls and one support function. * * @par Project: * MSP430 Capacitive Touch Library * * @par Developed using: * CCS Version : 5.4.0.00048, w/support for GCC extensions (--gcc) * \n IAR Version : 5.51.6 [Kickstart] * * @author C. Sterzik * @author T. Hwang * * @version 1.2 * Updated HALs for new devices. * * @par Supported API Calls: * - TI_CAPT_Init_Baseline() * - TI_CAPT_Update_Baseline() * - TI_CAPT_Reset_Tracking() * - TI_CAPT_Update_Tracking_DOI() * - TI_CAPT_Update_Tracking_Rate() * - TI_CAPT_Raw() * - TI_CAPT_Custom() * - TI_CAPT_Button() * - TI_CAPT_Buttons() * - TI_CAPT_Slider() * - TI_CAPT_Wheel() */ #include "CTS_Layer.h" /*! @defgroup GLOBAL_VARS Global Variables * @{ */ #ifdef TOTAL_NUMBER_OF_ELEMENTS /*! * The baseline tracking variables */ uint16_t baseCnt[TOTAL_NUMBER_OF_ELEMENTS]; #ifdef RAM_FOR_FLASH /*! * The current measurement variables */ uint16_t measCnt[MAXIMUM_NUMBER_OF_ELEMENTS_PER_SENSOR]; #endif /*! * The Status Register */ uint16_t ctsStatusReg = (DOI_INC+TRADOI_FAST+TRIDOI_SLOW); #endif /*! * @} */ /** @defgroup CTS_API API Group * @{ */ /***************************************************************************//** * @brief Measure the capacitance of each element within the Sensor * * This function selects the appropriate HAL to perform the capacitance * measurement based upon the halDefinition found in the sensor * structure. * The order of the elements within the Sensor structure is arbitrary * but must be consistent between the application and configuration. * The first element in the array (counts) corresponds to the first * element within the Sensor structure. * @param groupOfElements Pointer to Sensor structure to be measured * @param counts Address to where the measurements are to be written * @return none ******************************************************************************/ void TI_CAPT_Raw(const struct Sensor* groupOfElements, uint16_t * counts) { #ifdef RO_CSIO_TA2_WDTA if(groupOfElements->halDefinition == RO_CSIO_TA2_WDTA) { TI_CTS_RO_CSIO_TA2_WDTA_HAL(groupOfElements, counts); } #endif #ifdef RO_CSIO_TA2_TA3 if(groupOfElements->halDefinition == RO_CSIO_TA2_TA3) { TI_CTS_RO_CSIO_TA2_TA3_HAL(groupOfElements, counts); } #endif #ifdef fRO_CSIO_TA2_TA3 if(groupOfElements->halDefinition == fRO_CSIO_TA2_TA3) { TI_CTS_fRO_CSIO_TA2_TA3_HAL(groupOfElements, counts); } #endif #ifdef RO_COMPB_TB0_WDTA if(groupOfElements->halDefinition == RO_COMPB_TB0_WDTA) { TI_CTS_RO_COMPB_TB0_WDTA_HAL(groupOfElements, counts); } #endif #ifdef RO_PINOSC_TA0_TA1 if(groupOfElements->halDefinition == RO_PINOSC_TA0_TA1) { TI_CTS_RO_PINOSC_TA0_TA1_HAL(groupOfElements, counts); } #endif #ifdef fRO_PINOSC_TA0_TA1 if(groupOfElements->halDefinition == fRO_PINOSC_TA0_TA1) { TI_CTS_fRO_PINOSC_TA0_TA1_HAL(groupOfElements, counts); } #endif #ifdef RO_COMPAp_TA0_WDTp if(groupOfElements->halDefinition == RO_COMPAp_TA0_WDTp) { TI_CTS_RO_COMPAp_TA0_WDTp_HAL(groupOfElements, counts); } #endif #ifdef fRO_COMPAp_TA0_SW if(groupOfElements->halDefinition == fRO_COMPAp_TA0_SW) { TI_CTS_fRO_COMPAp_TA0_SW_HAL(groupOfElements, counts); } #endif #ifdef fRO_COMPAp_SW_TA0 if(groupOfElements->halDefinition == fRO_COMPAp_SW_TA0) { TI_CTS_fRO_COMPAp_SW_TA0_HAL(groupOfElements, counts); } #endif #ifdef RO_COMPAp_TA1_WDTp if(groupOfElements->halDefinition == RO_COMPAp_TA1_WDTp) { TI_CTS_RO_COMPAp_TA1_WDTp_HAL(groupOfElements, counts); } #endif #ifdef fRO_COMPAp_TA1_SW if(groupOfElements->halDefinition == fRO_COMPAp_TA1_SW) { TI_CTS_fRO_COMPAp_TA1_SW_HAL(groupOfElements, counts); } #endif #ifdef RC_PAIR_TA0 if(groupOfElements->halDefinition == RC_PAIR_TA0) { TI_CTS_RC_PAIR_TA0_HAL(groupOfElements, counts); } #endif #ifdef RO_PINOSC_TA0_WDTp if(groupOfElements->halDefinition == RO_PINOSC_TA0_WDTp) { TI_CTS_RO_PINOSC_TA0_WDTp_HAL(groupOfElements, counts); } #endif #ifdef RO_PINOSC_TA0 if(groupOfElements->halDefinition == RO_PINOSC_TA0) { TI_CTS_RO_PINOSC_TA0_HAL(groupOfElements, counts); } #endif #ifdef fRO_PINOSC_TA0_SW if(groupOfElements->halDefinition == fRO_PINOSC_TA0_SW) { TI_CTS_fRO_PINOSC_TA0_SW_HAL(groupOfElements, counts); } #endif #ifdef RO_COMPB_TA0_WDTA if(groupOfElements->halDefinition == RO_COMPB_TA0_WDTA) { TI_CTS_RO_COMPB_TA0_WDTA_HAL(groupOfElements, counts); } #endif #ifdef fRO_COMPB_TA0_SW if(groupOfElements->halDefinition == fRO_COMPB_TA0_SW) { TI_CTS_fRO_COMPB_TA0_SW_HAL(groupOfElements, counts); } #endif #ifdef RO_COMPB_TA1_WDTA if(groupOfElements->halDefinition == RO_COMPB_TA1_WDTA) { TI_CTS_RO_COMPB_TA1_WDTA_HAL(groupOfElements, counts); } #endif #ifdef fRO_COMPB_TA1_SW if(groupOfElements->halDefinition == fRO_COMPB_TA1_SW) { TI_CTS_fRO_COMPB_TA1_SW_HAL(groupOfElements, counts); } #endif #ifdef RO_COMPB_TA1_TA0 if(groupOfElements->halDefinition == RO_COMPB_TA1_TA0) { TI_CTS_RO_COMPB_TA1_TA0_HAL(groupOfElements, counts); } #endif #ifdef fRO_COMPB_TA1_TA0 if(groupOfElements->halDefinition == fRO_COMPB_TA1_TA0) { TI_CTS_fRO_COMPB_TA1_TA0_HAL(groupOfElements, counts); } #endif #ifdef RO_PINOSC_TA1_WDTp if(groupOfElements->halDefinition == RO_PINOSC_TA1_WDTp) { TI_CTS_RO_PINOSC_TA1_WDTp_HAL(groupOfElements, counts); } #endif #ifdef RO_PINOSC_TA1_TB0 if(groupOfElements->halDefinition == RO_PINOSC_TA1_TB0) { TI_CTS_RO_PINOSC_TA1_TB0_HAL(groupOfElements, counts); } #endif #ifdef fRO_PINOSC_TA1_TA0 if(groupOfElements->halDefinition == fRO_PINOSC_TA1_TA0) { TI_CTS_fRO_PINOSC_TA1_TA0_HAL(groupOfElements, counts); } #endif #ifdef fRO_PINOSC_TA1_TB0 if(groupOfElements->halDefinition == fRO_PINOSC_TA1_TB0) { TI_CTS_fRO_PINOSC_TA1_TB0_HAL(groupOfElements, counts); } #endif } #ifdef TOTAL_NUMBER_OF_ELEMENTS /***************************************************************************//** * @brief Make a single capacitance meausrment to initialize baseline tracking * @param groupOfElements Pointer to Sensor structure to be measured * @return none ******************************************************************************/ void TI_CAPT_Init_Baseline(const struct Sensor* groupOfElements) { TI_CAPT_Raw(groupOfElements, &baseCnt[groupOfElements->baseOffset]); } /***************************************************************************//** * @brief Update baseline tracking by averaging several measurements * @param groupOfElements Pointer to Sensor structure to be measured * @param numberOfAverages Number of measurements to be averaged * @return none ******************************************************************************/ void TI_CAPT_Update_Baseline(const struct Sensor* groupOfElements, uint8_t numberOfAverages) { uint8_t i,j; #ifndef RAM_FOR_FLASH uint16_t *measCnt; measCnt = (uint16_t *)malloc(groupOfElements->numElements * sizeof(uint16_t)); if(measCnt ==0) { while(1); } #endif for(j=0; j < numberOfAverages; j++) { for(i=0; i < groupOfElements->numElements; i++) { TI_CAPT_Raw(groupOfElements, measCnt); baseCnt[i+groupOfElements->baseOffset] = measCnt[i]/2 + baseCnt[i+groupOfElements->baseOffset]/2; } } #ifndef RAM_FOR_FLASH free(measCnt); #endif } /***************************************************************************//** * @brief Reset the Baseline Tracking algorithm to the default state * @param none * @return none ******************************************************************************/ void TI_CAPT_Reset_Tracking(void) { ctsStatusReg = (DOI_INC+TRADOI_FAST+TRIDOI_SLOW); } /***************************************************************************//** * @brief Update the Baseline Tracking algorithm Direction of Interest * @param direction Direction of increasing or decreasing capacitance * @return none ******************************************************************************/ void TI_CAPT_Update_Tracking_DOI(uint8_t direction) { if(direction) { ctsStatusReg |= DOI_INC; } else { ctsStatusReg &= ~DOI_INC; } } /***************************************************************************//** * @brief Update the baseling tracking algorithm tracking rates * @param rate Rate of tracking changes in and against direction of intrest * @return none ******************************************************************************/ void TI_CAPT_Update_Tracking_Rate(uint8_t rate) { ctsStatusReg &= ~(TRIDOI_FAST+TRADOI_VSLOW); // clear fields ctsStatusReg |= (rate & 0xF0); // update fields } /***************************************************************************//** * @brief Measure the change in capacitance of the Sensor * * This function measures the change in capacitance of each element * within a sensor and updates the baseline tracking in the event that * no change exceeds the detection threshold. * The order of the elements within the Sensor structure is arbitrary * but must be consistent between the application and configuration. * The first element in the array (deltaCnt) corresponds to the first * element within the Sensor structure. * @param groupOfElements Pointer to Sensor structure to be measured * @param deltaCnt Address to where the measurements are to be written * @return none ******************************************************************************/ void TI_CAPT_Custom(const struct Sensor* groupOfElements, uint16_t * deltaCnt) { uint8_t j; uint16_t tempCnt, remainder; ctsStatusReg &= ~ EVNT; TI_CAPT_Raw(groupOfElements, &deltaCnt[0]); // measure group of sensors for (j = 0; j < (groupOfElements->numElements); j++) { tempCnt = deltaCnt[j]; if(deltaCnt[j]) { if(((ctsStatusReg & DOI_MASK) && (groupOfElements->halDefinition & RO_MASK)) || ((!(ctsStatusReg & DOI_MASK)) && (!(groupOfElements->halDefinition & RO_MASK)))) { /* * Interested in a decrease in counts. Either the decrease * represents an increase in capacitance (a touch) with the * RO method, or the decrease represents a decrease in capacitance * (release) with the fRO or RC methods. */ if(baseCnt[j+groupOfElements->baseOffset] < deltaCnt[j]) { /* * The measured value is greater than the baseline therefore * no detection logic is needed. The measured value is * preserved in tempCnt and is used for baseline updates. */ deltaCnt[j] = 0; if(((groupOfElements->arrayPtr[j])->threshold) && (baseCnt[j+groupOfElements->baseOffset] +((groupOfElements->arrayPtr[j])->threshold/2) < tempCnt)) { /* * When the threshold is valid (non-calibration state), * limit the measurement to the baseline + threshold/2. */ tempCnt = baseCnt[j+groupOfElements->baseOffset] +((groupOfElements->arrayPtr[j])->threshold)/2; } } else { /* * deltaCnt now represents the magnitude of change relative to * the baseline. */ deltaCnt[j] = baseCnt[j+groupOfElements->baseOffset] - deltaCnt[j]; } } if(((!(ctsStatusReg & DOI_MASK)) && (groupOfElements->halDefinition & RO_MASK)) || ((ctsStatusReg & DOI_MASK) && (!(groupOfElements->halDefinition & RO_MASK)))) { /* * Interested in an increase in counts. Either the increase * represents a decrease in capacitance (a release) with the * RO method, or the increase represents a increase in capacitance * (touch) with the fRO or RC methods. */ if(baseCnt[j+groupOfElements->baseOffset] > deltaCnt[j]) { /* * The measured value is less than the baseline therefore * no detection logic is needed. The measured value is * preserved in tempCnt and is used for baseline updates. */ deltaCnt[j] = 0; if(((groupOfElements->arrayPtr[j])->threshold) && (baseCnt[j+groupOfElements->baseOffset] -((groupOfElements->arrayPtr[j])->threshold/2) > tempCnt)) { /* * When the threshold is valid (non-calibration state), * limit the measurement to the baseline - threshold/2. */ tempCnt = baseCnt[j+groupOfElements->baseOffset] -((groupOfElements->arrayPtr[j])->threshold)/2; } } else { /* * deltaCnt now represents the magnitude of change relative to * the baseline. */ deltaCnt[j] = deltaCnt[j] - baseCnt[j+groupOfElements->baseOffset]; } } // This section updates the baseline capacitance************************ if (deltaCnt[j]==0) { // if delta counts is 0, then the change in capacitance was opposite // the direction of interest. The baseCnt[i] is updated with the // saved tempCnt value for the current index value 'i'. remainder = 0; switch ((ctsStatusReg & TRADOI_VSLOW)) { case TRADOI_FAST://Fast tempCnt = tempCnt/2; baseCnt[j+groupOfElements->baseOffset] = (baseCnt[j+groupOfElements->baseOffset]/2); break; case TRADOI_MED://Medium tempCnt = tempCnt/4; baseCnt[j+groupOfElements->baseOffset] = 3*(baseCnt[j+groupOfElements->baseOffset]/4); break; case TRADOI_SLOW://slow /* Calculate remainder associated with (x + 63*y)/64 */ remainder = 0x003F & baseCnt[j+groupOfElements->baseOffset]; remainder = remainder * 63; remainder += 0x003F & tempCnt; remainder = remainder >> 6; tempCnt = tempCnt/64; baseCnt[j+groupOfElements->baseOffset] = 63*(baseCnt[j+groupOfElements->baseOffset]/64); break; case TRADOI_VSLOW://very slow /* Calculate remainder associated with (x+127*y)/128 */ remainder = 0x007F & baseCnt[j+groupOfElements->baseOffset]; remainder = remainder * 127; remainder += 0x007F & tempCnt; remainder = remainder >> 7; tempCnt = tempCnt/128; baseCnt[j+groupOfElements->baseOffset] = 127*(baseCnt[j+groupOfElements->baseOffset]/128); break; } /* Base_Capacitance = (Measured_Capacitance/Z) + Y*(Base_Capacitance/Z) */ tempCnt += remainder; baseCnt[j+groupOfElements->baseOffset] += tempCnt; /* In the case that DOI is set and */ if(groupOfElements->halDefinition & RO_MASK) { /* If the RO_MASK is set then the direction of interest is * decreasing (counts decrease with capacitance) and therefore * movement against the direction of interest would be an * increase: increment. */ baseCnt[j+groupOfElements->baseOffset]++; } else { /* RO_MASK is not set and therefore a decrease is against * the direction of interest: decrement */ baseCnt[j+groupOfElements->baseOffset]--; } } /* deltaCnt is either 0, less than threshold, or greater than threshold, never negative. */ else if(deltaCnt[j]<(groupOfElements->arrayPtr[j])->threshold && !(ctsStatusReg & PAST_EVNT)) { //if delta counts is positive but less than threshold, remainder = 1; switch ((ctsStatusReg & TRIDOI_FAST)) { case TRIDOI_VSLOW: tempCnt = 0; break; case TRIDOI_SLOW://slow remainder = 2; tempCnt = 0; break; case TRIDOI_MED://medium tempCnt = tempCnt/4; baseCnt[j+groupOfElements->baseOffset] = 3*(baseCnt[j+groupOfElements->baseOffset]/4); break; case TRIDOI_FAST://fast tempCnt = tempCnt/2; baseCnt[j+groupOfElements->baseOffset] = (baseCnt[j+groupOfElements->baseOffset]/2); break; } /* * Base_Capacitance = (Measured_Capacitance/Z) + * Y*(Base_Capacitance/Z) */ baseCnt[j+groupOfElements->baseOffset] += tempCnt; if(groupOfElements->halDefinition & RO_MASK) { /* If the RO_MASK is set then the direction of interest is * decreasing (counts decrease with capacitance) and * therefore movement in the direction of interest would * be a decrease: decrement. */ baseCnt[j+groupOfElements->baseOffset]-= remainder; } else { /* RO_MASK is not set and therefore an increase is in the * direction of interest: increment */ baseCnt[j+groupOfElements->baseOffset]+= remainder; } } //if delta counts above the threshold, event has occurred else if(deltaCnt[j]>=(groupOfElements->arrayPtr[j])->threshold) { ctsStatusReg |= EVNT; ctsStatusReg |= PAST_EVNT; } } }// end of for-loop if(!(ctsStatusReg & EVNT)) { ctsStatusReg &= ~PAST_EVNT; } } /***************************************************************************//** * @brief Determine if a button is being pressed * @param groupOfElements Pointer to button to be scanned * @return result Indication if button is (1) or is not (0) being pressed ******************************************************************************/ uint8_t TI_CAPT_Button(const struct Sensor * groupOfElements) { uint8_t result = 0; #ifndef RAM_FOR_FLASH uint16_t *measCnt; measCnt = (uint16_t *)malloc(groupOfElements->numElements * sizeof(uint16_t)); if(measCnt ==0) { while(1); } #endif TI_CAPT_Custom(groupOfElements, measCnt); #ifndef RAM_FOR_FLASH free(measCnt); #endif if(ctsStatusReg & EVNT) { result = 1; } return result; } /***************************************************************************//** * @brief Determine which button if any is being pressed * @param groupOfElements Pointer to buttons to be scanned * @return result pointer to element (button) being pressed or 0 none ******************************************************************************/ const struct Element *TI_CAPT_Buttons(const struct Sensor *groupOfElements) { uint8_t index; #ifndef RAM_FOR_FLASH uint16_t *measCnt; measCnt = (uint16_t *)malloc(groupOfElements->numElements * sizeof(uint16_t)); if(measCnt ==0) { while(1); } #endif TI_CAPT_Custom(groupOfElements, measCnt); if(ctsStatusReg & EVNT) { index = Dominant_Element(groupOfElements, measCnt); //ctsStatusReg &= ~EVNT; index++; } else { index = 0; } #ifndef RAM_FOR_FLASH free(measCnt); #endif if(index) { return groupOfElements->arrayPtr[index-1]; } return 0; } #ifdef SLIDER /***************************************************************************//** * @brief Determine the position on a slider * @param groupOfElements Pointer to slider * @return result position on slider or illegal value if no touch ******************************************************************************/ uint16_t TI_CAPT_Slider(const struct Sensor* groupOfElements) { uint8_t index; int16_t position; // allocate memory for measurement #ifndef RAM_FOR_FLASH uint16_t *measCnt; measCnt = (uint16_t *)malloc(groupOfElements->numElements * sizeof(uint16_t)); if(measCnt ==0) { while(1); } #endif position = ILLEGAL_SLIDER_WHEEL_POSITION; //make measurement TI_CAPT_Custom(groupOfElements, measCnt); // Use EVNT flag to determine if slider was touched. // The EVNT flag is a global variable and managed within the TI_CAPT_Custom // function. if(ctsStatusReg & EVNT) { index = Dominant_Element(groupOfElements, &measCnt[0]); // The index represents the element within the array with the highest // return. if(index == 0) { // Special case of 1st element in slider, add 1st, last, and 2nd position = measCnt[0] + measCnt[1]; } else if(index == (groupOfElements->numElements -1)) { // Special case of Last element in slider, add last, // 1st, and 2nd to last position = measCnt[groupOfElements->numElements -1] + measCnt[groupOfElements->numElements -2]; } else { position = measCnt[index] + measCnt[index+1] + measCnt[index-1]; } // Determine if sensor threshold criteria is met if(position >= groupOfElements->sensorThreshold) { // calculate position position = index *(groupOfElements->points /groupOfElements->numElements); position += (groupOfElements->points/groupOfElements->numElements) /2; if(index == 0) { // Special case of 1st element in slider, which only has one // neighbor, measCnt[1]. measCnt is limited to maxResponse // within dominantElement function if(measCnt[1]) { position += (measCnt[1] *(groupOfElements->points /groupOfElements->numElements))/100; } else { /* Calculate position based upon measCnt[0] */ position = (measCnt[0] *(groupOfElements->points /groupOfElements->numElements)/2)/100; } } else if(index == (groupOfElements->numElements -1)) { // Special case of Last element in slider, which only has one // neighbor, measCnt[x-1] or measCnt[numElements-1] if(measCnt[index-1]) { position -= (measCnt[index-1] *(groupOfElements->points /groupOfElements->numElements))/100; } else { position = groupOfElements->points; position -= (measCnt[index] *(groupOfElements->points /groupOfElements->numElements)/2)/100; } } else { position += (measCnt[index+1]*(groupOfElements->points/groupOfElements->numElements))/100; position -= (measCnt[index-1]*(groupOfElements->points/groupOfElements->numElements))/100; } if((position > groupOfElements->points) || (position < 0)) { position = ILLEGAL_SLIDER_WHEEL_POSITION; } } else { position = ILLEGAL_SLIDER_WHEEL_POSITION; } } #ifndef RAM_FOR_FLASH free(measCnt); #endif return position; } #endif #ifdef WHEEL /***************************************************************************//** * @brief Determine the position on a wheel * @param groupOfElements Pointer to wheel * @return result position on wheel or illegal value if no touch ******************************************************************************/ uint16_t TI_CAPT_Wheel(const struct Sensor* groupOfElements) { uint8_t index; int16_t position; // allocate memory for measurement #ifndef RAM_FOR_FLASH uint16_t *measCnt; measCnt = (uint16_t *)malloc(groupOfElements->numElements * sizeof(uint16_t)); if(measCnt ==0) { while(1); } #endif position = ILLEGAL_SLIDER_WHEEL_POSITION; //make measurement TI_CAPT_Custom(groupOfElements, measCnt); // Translate the EVNT flag from an element level EVNT to a sensor level EVNT. // The sensor must read at least 75% cumulative response before indicating a // touch. if(ctsStatusReg & EVNT) { index = Dominant_Element(groupOfElements, &measCnt[0]); // The index represents the element within the array with the highest return. // if(index == 0) { // Special case of 1st element in slider, add 1st, last, and 2nd position = measCnt[0] + measCnt[groupOfElements->numElements -1] + measCnt[1]; } else if(index == (groupOfElements->numElements -1)) { // Special case of Last element in slider, add last, 1st, and 2nd to last position = measCnt[index] + measCnt[0] + measCnt[index-1]; } else { position = measCnt[index] + measCnt[index+1] + measCnt[index-1]; } if(position > groupOfElements->sensorThreshold) { //index = Dominant_Element(groupOfElements, &measCnt[0]); // The index represents the element within the array with the highest return. // position = index*(groupOfElements->points/groupOfElements->numElements); position += (groupOfElements->points/groupOfElements->numElements)/2; if(index == 0) { // Special case of 1st element in slider, which only has one neighbor, measCnt[1] // measCnt is limited to maxResponse within dominantElement function position += (measCnt[1]*(groupOfElements->points/groupOfElements->numElements))/100; position -= (measCnt[groupOfElements->numElements -1]*(groupOfElements->points/groupOfElements->numElements))/100; if(position < 0) { position = position + (int16_t)groupOfElements->points; position++; // -1 goes to points } } else if(index == (groupOfElements->numElements -1)) { // Special case of Last element in slider, which only has one neighbor, measCnt[x-1] or measCnt[numElements-1] // measCnt is limited to maxResponse within dominantElement function position += (measCnt[0]*(groupOfElements->points/groupOfElements->numElements))/100; position -= (measCnt[index-1]*(groupOfElements->points/groupOfElements->numElements))/100; if(position > groupOfElements->points) { position = position - (int16_t)groupOfElements->points; position--; // points+1 goes to 0 } } else { position += (measCnt[index+1]*(groupOfElements->points/groupOfElements->numElements))/100; position -= (measCnt[index-1]*(groupOfElements->points/groupOfElements->numElements))/100; } if((position > groupOfElements->points) || position < 0) { position = ILLEGAL_SLIDER_WHEEL_POSITION; } } else { position = ILLEGAL_SLIDER_WHEEL_POSITION; } } #ifndef RAM_FOR_FLASH free(measCnt); #endif return position; } #endif /** @} */ /***************************************************************************//** * @defgroup CTS_support Support Group * @ingroup CTS_API ******************************************************************************/ /***************************************************************************//** * @ingroup CTS_support * @brief Determine which element within a sensor has the largest response * * This function compares and normalizes the change in capacitance to * determine which element has the dominant response. The deltaCnt * values for each element that exceed the threshold are also * converted from a 'raw' measurement to a percentage of the maximum * response. * @param groupOfElements Pointer to buttons to be scanned * @param deltaCnt Address to where the measurements are to be written * @return result index to the element which is dominant ******************************************************************************/ uint8_t Dominant_Element(const struct Sensor* groupOfElements, uint16_t* deltaCnt) { uint8_t i; uint16_t percentDelta=0; uint8_t dominantElement=0; for(i=0;inumElements;i++) { if(deltaCnt[i]>=(groupOfElements->arrayPtr[i])->threshold) { if(deltaCnt[i] > ((groupOfElements->arrayPtr[i])->maxResponse)) { deltaCnt[i] = (groupOfElements->arrayPtr[i])->maxResponse; // limit response to the maximum } // (maxResponse - threshold) cannot exceed 655 // 100*(delta - threshold) / (maxResponse - threshold) deltaCnt[i] = (100*(deltaCnt[i] -(groupOfElements->arrayPtr[i])->threshold)) /((groupOfElements->arrayPtr[i])->maxResponse -(groupOfElements->arrayPtr[i])->threshold); if(deltaCnt[i] >= percentDelta) { //update percentDelta percentDelta = deltaCnt[i]; dominantElement = i; } } else { deltaCnt[i] = 0; } } // end for loop return dominantElement; } #endif