acidportal

- 😈 Worlds smallest Evil Portal on a LilyGo T-QT
git clone git://git.acid.vegas/acidportal.git
Log | Files | Refs | Archive | README | LICENSE

Touch.cpp (13298B)

      1 // The following touch screen support code by maxpautsch was merged 1/10/17
      2 // https://github.com/maxpautsch
      3 
      4 // Define TOUCH_CS is the user setup file to enable this code
      5 
      6 // A demo is provided in examples Generic folder
      7 
      8 // Additions by Bodmer to double sample, use Z value to improve detection reliability
      9 // and to correct rotation handling
     10 
     11 // See license in root directory.
     12 
     13 // Define a default pressure threshold
     14 #ifndef Z_THRESHOLD
     15   #define Z_THRESHOLD 350 // Touch pressure threshold for validating touches
     16 #endif
     17 
     18 /***************************************************************************************
     19 ** Function name:           begin_touch_read_write - was spi_begin_touch
     20 ** Description:             Start transaction and select touch controller
     21 ***************************************************************************************/
     22 // The touch controller has a low SPI clock rate
     23 inline void TFT_eSPI::begin_touch_read_write(void){
     24   DMA_BUSY_CHECK;
     25   CS_H; // Just in case it has been left low
     26   #if defined (SPI_HAS_TRANSACTION) && defined (SUPPORT_TRANSACTIONS)
     27     if (locked) {locked = false; spi.beginTransaction(SPISettings(SPI_TOUCH_FREQUENCY, MSBFIRST, SPI_MODE0));}
     28   #else
     29     spi.setFrequency(SPI_TOUCH_FREQUENCY);
     30   #endif
     31   SET_BUS_READ_MODE;
     32   T_CS_L;
     33 }
     34 
     35 /***************************************************************************************
     36 ** Function name:           end_touch_read_write - was spi_end_touch
     37 ** Description:             End transaction and deselect touch controller
     38 ***************************************************************************************/
     39 inline void TFT_eSPI::end_touch_read_write(void){
     40   T_CS_H;
     41   #if defined (SPI_HAS_TRANSACTION) && defined (SUPPORT_TRANSACTIONS)
     42     if(!inTransaction) {if (!locked) {locked = true; spi.endTransaction();}}
     43   #else
     44     spi.setFrequency(SPI_FREQUENCY);
     45   #endif
     46   //SET_BUS_WRITE_MODE;
     47 }
     48 
     49 /***************************************************************************************
     50 ** Function name:           Legacy - deprecated
     51 ** Description:             Start/end transaction
     52 ***************************************************************************************/
     53 void TFT_eSPI::spi_begin_touch() {begin_touch_read_write();}
     54 void TFT_eSPI::spi_end_touch()   {  end_touch_read_write();}
     55 
     56 /***************************************************************************************
     57 ** Function name:           getTouchRaw
     58 ** Description:             read raw touch position.  Always returns true.
     59 ***************************************************************************************/
     60 uint8_t TFT_eSPI::getTouchRaw(uint16_t *x, uint16_t *y){
     61   uint16_t tmp;
     62 
     63   begin_touch_read_write();
     64   
     65   // Start YP sample request for x position, read 4 times and keep last sample
     66   spi.transfer(0xd0);                    // Start new YP conversion
     67   spi.transfer(0);                       // Read first 8 bits
     68   spi.transfer(0xd0);                    // Read last 8 bits and start new YP conversion
     69   spi.transfer(0);                       // Read first 8 bits
     70   spi.transfer(0xd0);                    // Read last 8 bits and start new YP conversion
     71   spi.transfer(0);                       // Read first 8 bits
     72   spi.transfer(0xd0);                    // Read last 8 bits and start new YP conversion
     73 
     74   tmp = spi.transfer(0);                   // Read first 8 bits
     75   tmp = tmp <<5;
     76   tmp |= 0x1f & (spi.transfer(0x90)>>3);   // Read last 8 bits and start new XP conversion
     77 
     78   *x = tmp;
     79 
     80   // Start XP sample request for y position, read 4 times and keep last sample
     81   spi.transfer(0);                       // Read first 8 bits
     82   spi.transfer(0x90);                    // Read last 8 bits and start new XP conversion
     83   spi.transfer(0);                       // Read first 8 bits
     84   spi.transfer(0x90);                    // Read last 8 bits and start new XP conversion
     85   spi.transfer(0);                       // Read first 8 bits
     86   spi.transfer(0x90);                    // Read last 8 bits and start new XP conversion
     87 
     88   tmp = spi.transfer(0);                 // Read first 8 bits
     89   tmp = tmp <<5;
     90   tmp |= 0x1f & (spi.transfer(0)>>3);    // Read last 8 bits
     91 
     92   *y = tmp;
     93 
     94   end_touch_read_write();
     95 
     96   return true;
     97 }
     98 
     99 /***************************************************************************************
    100 ** Function name:           getTouchRawZ
    101 ** Description:             read raw pressure on touchpad and return Z value. 
    102 ***************************************************************************************/
    103 uint16_t TFT_eSPI::getTouchRawZ(void){
    104 
    105   begin_touch_read_write();
    106 
    107   // Z sample request
    108   int16_t tz = 0xFFF;
    109   spi.transfer(0xb0);               // Start new Z1 conversion
    110   tz += spi.transfer16(0xc0) >> 3;  // Read Z1 and start Z2 conversion
    111   tz -= spi.transfer16(0x00) >> 3;  // Read Z2
    112 
    113   end_touch_read_write();
    114 
    115   if (tz == 4095) tz = 0;
    116 
    117   return (uint16_t)tz;
    118 }
    119 
    120 /***************************************************************************************
    121 ** Function name:           validTouch
    122 ** Description:             read validated position. Return false if not pressed. 
    123 ***************************************************************************************/
    124 #define _RAWERR 20 // Deadband error allowed in successive position samples
    125 uint8_t TFT_eSPI::validTouch(uint16_t *x, uint16_t *y, uint16_t threshold){
    126   uint16_t x_tmp, y_tmp, x_tmp2, y_tmp2;
    127 
    128   // Wait until pressure stops increasing to debounce pressure
    129   uint16_t z1 = 1;
    130   uint16_t z2 = 0;
    131   while (z1 > z2)
    132   {
    133     z2 = z1;
    134     z1 = getTouchRawZ();
    135     delay(1);
    136   }
    137 
    138   //  Serial.print("Z = ");Serial.println(z1);
    139 
    140   if (z1 <= threshold) return false;
    141     
    142   getTouchRaw(&x_tmp,&y_tmp);
    143 
    144   //  Serial.print("Sample 1 x,y = "); Serial.print(x_tmp);Serial.print(",");Serial.print(y_tmp);
    145   //  Serial.print(", Z = ");Serial.println(z1);
    146 
    147   delay(1); // Small delay to the next sample
    148   if (getTouchRawZ() <= threshold) return false;
    149 
    150   delay(2); // Small delay to the next sample
    151   getTouchRaw(&x_tmp2,&y_tmp2);
    152   
    153   //  Serial.print("Sample 2 x,y = "); Serial.print(x_tmp2);Serial.print(",");Serial.println(y_tmp2);
    154   //  Serial.print("Sample difference = ");Serial.print(abs(x_tmp - x_tmp2));Serial.print(",");Serial.println(abs(y_tmp - y_tmp2));
    155 
    156   if (abs(x_tmp - x_tmp2) > _RAWERR) return false;
    157   if (abs(y_tmp - y_tmp2) > _RAWERR) return false;
    158   
    159   *x = x_tmp;
    160   *y = y_tmp;
    161   
    162   return true;
    163 }
    164   
    165 /***************************************************************************************
    166 ** Function name:           getTouch
    167 ** Description:             read callibrated position. Return false if not pressed. 
    168 ***************************************************************************************/
    169 uint8_t TFT_eSPI::getTouch(uint16_t *x, uint16_t *y, uint16_t threshold){
    170   uint16_t x_tmp, y_tmp;
    171   
    172   if (threshold<20) threshold = 20;
    173   if (_pressTime > millis()) threshold=20;
    174 
    175   uint8_t n = 5;
    176   uint8_t valid = 0;
    177   while (n--)
    178   {
    179     if (validTouch(&x_tmp, &y_tmp, threshold)) valid++;;
    180   }
    181 
    182   if (valid<1) { _pressTime = 0; return false; }
    183   
    184   _pressTime = millis() + 50;
    185 
    186   convertRawXY(&x_tmp, &y_tmp);
    187 
    188   if (x_tmp >= _width || y_tmp >= _height) return false;
    189 
    190   _pressX = x_tmp;
    191   _pressY = y_tmp;
    192   *x = _pressX;
    193   *y = _pressY;
    194   return valid;
    195 }
    196 
    197 /***************************************************************************************
    198 ** Function name:           convertRawXY
    199 ** Description:             convert raw touch x,y values to screen coordinates 
    200 ***************************************************************************************/
    201 void TFT_eSPI::convertRawXY(uint16_t *x, uint16_t *y)
    202 {
    203   uint16_t x_tmp = *x, y_tmp = *y, xx, yy;
    204 
    205   if(!touchCalibration_rotate){
    206     xx=(x_tmp-touchCalibration_x0)*_width/touchCalibration_x1;
    207     yy=(y_tmp-touchCalibration_y0)*_height/touchCalibration_y1;
    208     if(touchCalibration_invert_x)
    209       xx = _width - xx;
    210     if(touchCalibration_invert_y)
    211       yy = _height - yy;
    212   } else {
    213     xx=(y_tmp-touchCalibration_x0)*_width/touchCalibration_x1;
    214     yy=(x_tmp-touchCalibration_y0)*_height/touchCalibration_y1;
    215     if(touchCalibration_invert_x)
    216       xx = _width - xx;
    217     if(touchCalibration_invert_y)
    218       yy = _height - yy;
    219   }
    220   *x = xx;
    221   *y = yy;
    222 }
    223 
    224 /***************************************************************************************
    225 ** Function name:           calibrateTouch
    226 ** Description:             generates calibration parameters for touchscreen. 
    227 ***************************************************************************************/
    228 void TFT_eSPI::calibrateTouch(uint16_t *parameters, uint32_t color_fg, uint32_t color_bg, uint8_t size){
    229   int16_t values[] = {0,0,0,0,0,0,0,0};
    230   uint16_t x_tmp, y_tmp;
    231 
    232 
    233 
    234   for(uint8_t i = 0; i<4; i++){
    235     fillRect(0, 0, size+1, size+1, color_bg);
    236     fillRect(0, _height-size-1, size+1, size+1, color_bg);
    237     fillRect(_width-size-1, 0, size+1, size+1, color_bg);
    238     fillRect(_width-size-1, _height-size-1, size+1, size+1, color_bg);
    239 
    240     if (i == 5) break; // used to clear the arrows
    241     
    242     switch (i) {
    243       case 0: // up left
    244         drawLine(0, 0, 0, size, color_fg);
    245         drawLine(0, 0, size, 0, color_fg);
    246         drawLine(0, 0, size , size, color_fg);
    247         break;
    248       case 1: // bot left
    249         drawLine(0, _height-size-1, 0, _height-1, color_fg);
    250         drawLine(0, _height-1, size, _height-1, color_fg);
    251         drawLine(size, _height-size-1, 0, _height-1 , color_fg);
    252         break;
    253       case 2: // up right
    254         drawLine(_width-size-1, 0, _width-1, 0, color_fg);
    255         drawLine(_width-size-1, size, _width-1, 0, color_fg);
    256         drawLine(_width-1, size, _width-1, 0, color_fg);
    257         break;
    258       case 3: // bot right
    259         drawLine(_width-size-1, _height-size-1, _width-1, _height-1, color_fg);
    260         drawLine(_width-1, _height-1-size, _width-1, _height-1, color_fg);
    261         drawLine(_width-1-size, _height-1, _width-1, _height-1, color_fg);
    262         break;
    263       }
    264 
    265     // user has to get the chance to release
    266     if(i>0) delay(1000);
    267 
    268     for(uint8_t j= 0; j<8; j++){
    269       // Use a lower detect threshold as corners tend to be less sensitive
    270       while(!validTouch(&x_tmp, &y_tmp, Z_THRESHOLD/2));
    271       values[i*2  ] += x_tmp;
    272       values[i*2+1] += y_tmp;
    273       }
    274     values[i*2  ] /= 8;
    275     values[i*2+1] /= 8;
    276   }
    277 
    278 
    279   // from case 0 to case 1, the y value changed. 
    280   // If the measured delta of the touch x axis is bigger than the delta of the y axis, the touch and TFT axes are switched.
    281   touchCalibration_rotate = false;
    282   if(abs(values[0]-values[2]) > abs(values[1]-values[3])){
    283     touchCalibration_rotate = true;
    284     touchCalibration_x0 = (values[1] + values[3])/2; // calc min x
    285     touchCalibration_x1 = (values[5] + values[7])/2; // calc max x
    286     touchCalibration_y0 = (values[0] + values[4])/2; // calc min y
    287     touchCalibration_y1 = (values[2] + values[6])/2; // calc max y
    288   } else {
    289     touchCalibration_x0 = (values[0] + values[2])/2; // calc min x
    290     touchCalibration_x1 = (values[4] + values[6])/2; // calc max x
    291     touchCalibration_y0 = (values[1] + values[5])/2; // calc min y
    292     touchCalibration_y1 = (values[3] + values[7])/2; // calc max y
    293   }
    294 
    295   // in addition, the touch screen axis could be in the opposite direction of the TFT axis
    296   touchCalibration_invert_x = false;
    297   if(touchCalibration_x0 > touchCalibration_x1){
    298     values[0]=touchCalibration_x0;
    299     touchCalibration_x0 = touchCalibration_x1;
    300     touchCalibration_x1 = values[0];
    301     touchCalibration_invert_x = true;
    302   }
    303   touchCalibration_invert_y = false;
    304   if(touchCalibration_y0 > touchCalibration_y1){
    305     values[0]=touchCalibration_y0;
    306     touchCalibration_y0 = touchCalibration_y1;
    307     touchCalibration_y1 = values[0];
    308     touchCalibration_invert_y = true;
    309   }
    310 
    311   // pre calculate
    312   touchCalibration_x1 -= touchCalibration_x0;
    313   touchCalibration_y1 -= touchCalibration_y0;
    314 
    315   if(touchCalibration_x0 == 0) touchCalibration_x0 = 1;
    316   if(touchCalibration_x1 == 0) touchCalibration_x1 = 1;
    317   if(touchCalibration_y0 == 0) touchCalibration_y0 = 1;
    318   if(touchCalibration_y1 == 0) touchCalibration_y1 = 1;
    319 
    320   // export parameters, if pointer valid
    321   if(parameters != NULL){
    322     parameters[0] = touchCalibration_x0;
    323     parameters[1] = touchCalibration_x1;
    324     parameters[2] = touchCalibration_y0;
    325     parameters[3] = touchCalibration_y1;
    326     parameters[4] = touchCalibration_rotate | (touchCalibration_invert_x <<1) | (touchCalibration_invert_y <<2);
    327   }
    328 }
    329 
    330 
    331 /***************************************************************************************
    332 ** Function name:           setTouch
    333 ** Description:             imports calibration parameters for touchscreen. 
    334 ***************************************************************************************/
    335 void TFT_eSPI::setTouch(uint16_t *parameters){
    336   touchCalibration_x0 = parameters[0];
    337   touchCalibration_x1 = parameters[1];
    338   touchCalibration_y0 = parameters[2];
    339   touchCalibration_y1 = parameters[3];
    340 
    341   if(touchCalibration_x0 == 0) touchCalibration_x0 = 1;
    342   if(touchCalibration_x1 == 0) touchCalibration_x1 = 1;
    343   if(touchCalibration_y0 == 0) touchCalibration_y0 = 1;
    344   if(touchCalibration_y1 == 0) touchCalibration_y1 = 1;
    345 
    346   touchCalibration_rotate = parameters[4] & 0x01;
    347   touchCalibration_invert_x = parameters[4] & 0x02;
    348   touchCalibration_invert_y = parameters[4] & 0x04;
    349 }