Vekatech / Touch
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers Touch.cpp Source File

Touch.cpp

00001 #include "Touch.hpp"
00002 
00003 
00004 
00005 namespace Vekatech {
00006 
00007 #define DISABLED    0
00008 #define LAST_SAMPLE 1
00009 #define ALL_SAMPLES 2
00010 
00011 //Debug is disabled by default
00012 #define TOUCH_DBG   DISABLED
00013 //#define MORE_DETAILS
00014 
00015 #ifndef FUNCTION_NAME
00016 //#define FUNCTION_NAME ""
00017 //#define FUNCTION_NAME __func__
00018 //#define FUNCTION_NAME __FUNCTION__
00019 #define FUNCTION_NAME __PRETTY_FUNCTION__
00020 #endif
00021 
00022 #if (TOUCH_DBG > DISABLED)
00023 #ifdef MORE_DETAILS
00024     #define DBG(x, ...) printf("[DBG: %s:%s:%d] " x "\r\n", __FILE__, FUNCTION_NAME, __LINE__, ##__VA_ARGS__)
00025 #else
00026     #define DBG(x, ...) printf("[DBG:] " x "\r\n", ##__VA_ARGS__)
00027 #endif
00028 #else
00029     #define DBG(x, ...)
00030 #endif
00031 
00032 #if (TOUCH_DBG > LAST_SAMPLE)
00033 #ifdef MORE_DETAILS
00034     #define DBG_MORE(x, ...) printf("[DBG_MORE: %s:%s:%d] " x "\r\n", __FILE__, FUNCTION_NAME, __LINE__,  ##__VA_ARGS__)
00035 #else
00036     #define DBG_MORE(x, ...) printf("[DBG_MORE:] " x "\r\n", ##__VA_ARGS__)
00037 #endif
00038 #else
00039     #define DBG_MORE(x, ...)
00040 #endif
00041 
00042 #if (TOUCH_DBG > ALL_SAMPLES)
00043 #ifdef MORE_DETAILS
00044     #define DBG_ALL(x, ...) printf("[DBG_ALL: %s:%s:%d] " x "\r\n", __FILE__, FUNCTION_NAME, __LINE__,  ##__VA_ARGS__)
00045 #else
00046     #define DBG_ALL(x, ...) printf("[DBG_ALL:] " x "\r\n", ##__VA_ARGS__)
00047 #endif
00048 #else
00049     #define DBG_ALL(x, ...)
00050 #endif
00051 
00052 
00053 
00054 #define NEW_TOUCH_DATA  0x1
00055 
00056 const touch_config_t  STMPE811_cfg = {
00057     "STMPE811", LCD_VDC5_CH0_PANEL, RESISTIVE,
00058     {I_2_C, TPIIC_SDA, TPIIC_SCL, NC, NC, NC, NC, 100000},
00059     {INT_ON_EDGE, FALLING_OR_ACTIVE_LO, TPIRQ_PIN}
00060 };
00061 
00062 osThreadId          TouchThreadID;
00063 
00064 /**************************************************************************//**
00065  * @brief       Constructor of the Touch class
00066  * @param[in]   pointer to Config structure (touch_config_t)
00067 ******************************************************************************/
00068 //SPI(tp_cfg->interface.mosi, tp_cfg->interface.miso, tp_cfg->interface.sclk, tp_cfg->interface.ssel),
00069 Touch::Touch( const touch_config_t * tp_cfg ) : I2C(tp_cfg->interface.sda, tp_cfg->interface.scl), InterruptIn(tp_cfg->activity_irq.pin)
00070 {
00071     if(tp_cfg == NULL)
00072         touch_cfg = &STMPE811_cfg;
00073     else
00074         touch_cfg = tp_cfg;
00075 
00076     x = y = z = 0;    adc_x = adc_y = adc_z = 0;
00077     xyz_data = screen_data; adc_data = raw_data;
00078     last_xyz_idx = FIFO_DEPTH-1;
00079 
00080     dot_thd = 0;
00081     fraction = 0;
00082     calib.data.flag = 0;
00083 } /* End of constructor */
00084 
00085 
00086 /**************************************************************************//**
00087  * @brief       Destructor of the Touch class
00088 ******************************************************************************/
00089 Touch::~Touch( )
00090 {
00091     Thread::State S = thd.get_state();
00092 
00093     disable_irq();
00094 
00095     if((S != Thread::Inactive) && (S != Thread::Deleted))
00096     {
00097         thd.terminate();
00098         thd.join();
00099     }
00100 
00101     touch_cfg = NULL;
00102     xyz_data = NULL;
00103     adc_data = NULL;
00104 }
00105 
00106 
00107 /**************************************************************************//**
00108  * @brief       Touch controller initialization
00109  * @retval      error code
00110 ******************************************************************************/
00111 Touch::init_err_t  Touch::Init( void )
00112 {
00113     init_err_t  tp_err;
00114 
00115     if(touch_cfg->type  == RESISTIVE)
00116     {
00117         tp_err = Clb_Setup();
00118 
00119         if(tp_err != TOUCH_OK )
00120             return tp_err;
00121     }
00122 
00123     if(touch_cfg->interface.type  == I_2_C)
00124         I2C::frequency(touch_cfg->interface.freq);
00125     //else
00126         //SPI::frequency(touch_cfg->interface.freq);
00127 
00128     tp_err = Drv_Setup();
00129 
00130     if(tp_err != TOUCH_OK )
00131         return tp_err;
00132     else
00133     {
00134         thd.start(callback(this, &Touch::Handle_touch));
00135 
00136         if(touch_cfg->activity_irq.polarity == FALLING_OR_ACTIVE_LO)
00137         {
00138             rise(NULL);
00139             fall(Irq_Alert);
00140         }
00141         else
00142         {
00143             rise(Irq_Alert);
00144             fall(NULL);
00145         }
00146 
00147         enable_irq();
00148     }
00149 
00150     return tp_err;
00151 } /* End of method Init() */
00152 
00153 
00154 /**************************************************************************//**
00155  * @brief       Set Calibration data
00156  * @retval      error code
00157 ******************************************************************************/
00158 Touch::init_err_t  Touch::Clb_Setup()
00159 {
00160     if(touch_cfg->name  == "STMPE811")
00161     {
00162         #ifndef __USE_DEFAULT_CALIBRATION_DATA__
00163             // extract calibration info from lcdpanel EEPROM
00164             char adr = 0;
00165 
00166             if( (touch_cfg->interface.sda == EEIIC_SDA) || (touch_cfg->interface.scl == EEIIC_SCL))
00167             {   // lcdpanel EEPROM is on the same I2C channel no need to initialize a new one !
00168                 if(I2C::write(EE_CALIB_DEVICE_ADDR, (const char *)&adr, 1, true) != 0)
00169                     return TOUCH_INIT_ERR ;
00170                 if(I2C::read(EE_CALIB_DEVICE_ADDR, (char*)calib.KX08, sizeof(calib.KX08)) != 0)
00171                     return TOUCH_INIT_ERR ;
00172             }
00173             else
00174             {   // lcdpanel EEPROM is on different I2C channel so initialize a new one !
00175                 I2C clb_eeprom(EEIIC_SDA, EEIIC_SCL);
00176 
00177                 clb_eeprom.frequency(100000);
00178                 if(clb_eeprom.write(EE_CALIB_DEVICE_ADDR, (const char *)&adr, 1, true) != 0)
00179                     return TOUCH_INIT_ERR ;
00180                 if(clb_eeprom.read(EE_CALIB_DEVICE_ADDR, (char*)calib.KX08, sizeof(calib.KX08)) != 0)
00181                     return TOUCH_INIT_ERR ;
00182             }
00183         #endif
00184 
00185         if(calib.data.flag != 1)
00186         {   // load default calibration info
00187             unsigned char clb[] = {TPCALIBRATION_DATA};
00188             memcpy(calib.KX08, clb, sizeof(clb));
00189         }
00190 
00191         return TOUCH_OK ;
00192     }
00193     else
00194         return TOUCH_UNSUPP_ERR ;
00195 } /* End of method Clb_Setup() */
00196 
00197 
00198 /**************************************************************************//**
00199  * @brief       Set Touch Controller settings
00200  * @retval      error code
00201 ******************************************************************************/
00202 Touch::init_err_t  Touch::Drv_Setup()
00203 {
00204     if(touch_cfg->name  == "STMPE811")
00205     {
00206         unsigned char i, initdata[][2] = { INIT_DATA };
00207 
00208         for(i=0; i<(sizeof(initdata)>>1); i++)
00209         {
00210             if(initdata[i][0] == INT_CTRL)
00211             {   // reconfigure interrupt if needed
00212                 initdata[i][1] = 0x01;
00213                 initdata[i][1] |= (touch_cfg->activity_irq.trigger  == INT_ON_EDGE)? 0x02 : 0x00;
00214                 initdata[i][1] |= (touch_cfg->activity_irq.polarity == RISING_OR_ACTIVE_HI)? 0x04 : 0x00;
00215             }
00216 
00217             if(initdata[i][0] == FIFO_TH)
00218             {   // save threshold
00219                 if(initdata[i][1] < 2)
00220                     initdata[i][1] = 2;
00221 
00222                 dot_thd = initdata[i][1]-1;
00223             }
00224 
00225             if(initdata[i][0] == TSC_FRACT_Z)
00226                 fraction = initdata[i][1];  // save z precision
00227 
00228             if ((I2C::write(STMPE811_DEVICE_ADDR, (const char *)&initdata[i][0], 2)) != 0)
00229                 return TOUCH_INIT_ERR ;
00230 
00231             while (I2C::write(STMPE811_DEVICE_ADDR, (const char *)initdata, 0) != 0);  // ACK polling
00232         }
00233 
00234         return TOUCH_OK ;
00235     }
00236     else
00237         return TOUCH_UNSUPP_ERR ;
00238 }
00239 
00240 
00241 /**************************************************************************//**
00242  * @brief       Get Status of the pen
00243  * @retval      true    : StylusDown
00244  *              false   : StyluUp
00245 ******************************************************************************/
00246 bool Touch::Get_Pen_Status()
00247 {
00248     if(touch_cfg->name  == "STMPE811")
00249     {
00250         unsigned char pen = TSC_CTRL;
00251 
00252         I2C::write(STMPE811_DEVICE_ADDR, (const char *)&pen, 1, true);
00253         pen = 0;
00254         I2C::read(STMPE811_DEVICE_ADDR, (char *)&pen, 1);
00255 
00256         return (pen & TSC_STA)? true : false;
00257     }
00258     else
00259         return false;
00260 } /* End of method Get_Pen_Status() */
00261 
00262 
00263 /**************************************************************************//**
00264  * @brief       Get one sample of data
00265  * @param[in]   * raw   : pointer to ring buffer to store the samples
00266 ******************************************************************************/
00267 void Touch::Get_Data( unsigned long long * raw )
00268 {
00269     if(touch_cfg->name  == "STMPE811")
00270     {
00271         int idx = last_xyz_idx;
00272         unsigned char  i, packed_sample[dot_thd * 4];
00273         unsigned short raw_x, raw_y;
00274         unsigned char  raw_z;
00275 
00276         i = TSC_DATA_FIFO;
00277         I2C::write(STMPE811_DEVICE_ADDR, (const char *)&i, 1, true);
00278         I2C::read(STMPE811_DEVICE_ADDR, (char *)packed_sample, sizeof(packed_sample));
00279         for(i=0; i<dot_thd; i++)
00280         {
00281             raw_x = (unsigned short)((packed_sample[(i*4)+0]<<4) | (packed_sample[(i*4)+1]>>4));
00282             raw_y = (unsigned short)(((0x0F & packed_sample[(i*4)+1])<<8) | packed_sample[(i*4)+2]);
00283             raw_z = packed_sample[(i*4)+3];
00284 
00285             idx = ((idx+1) < FIFO_DEPTH)? idx+1 : 0;
00286             ((touch_raw_data_t*)raw)[idx].axis.x = raw_x;
00287             ((touch_raw_data_t*)raw)[idx].axis.y = raw_y;
00288             ((touch_raw_data_t*)raw)[idx].axis.z = raw_z;
00289         }
00290     }
00291 } /* End of method Get_Data() */
00292 
00293 
00294 /**************************************************************************//**
00295  * @brief       Get all available samples of data
00296  * @param[in]   * raw   : pointer to ring buffer to store the samples
00297  * @retval                samples count
00298 ******************************************************************************/
00299 int Touch::Get_Fifo( unsigned long long * raw )
00300 {
00301     if(touch_cfg->name  == "STMPE811")
00302     {
00303       int idx = last_xyz_idx;
00304       unsigned char packets;
00305 
00306       packets = FIFO_SIZE;
00307       I2C::write(STMPE811_DEVICE_ADDR, (const char *)&packets, 1, true);
00308       packets = 0;
00309       I2C::read(STMPE811_DEVICE_ADDR, (char *)&packets, 1);
00310       if(packets)
00311       {
00312         unsigned char  packed_sample[packets * 4];
00313         unsigned short raw_x, raw_y, i;
00314         unsigned char  raw_z;
00315 
00316         raw_z = TSC_DATA_FIFO;
00317         I2C::write(STMPE811_DEVICE_ADDR, (const char *)&raw_z, 1, true);
00318         I2C::read(STMPE811_DEVICE_ADDR, (char *)packed_sample, packets*4);
00319 
00320         for(i=0; i<packets; i++)
00321         {
00322           raw_x = (unsigned short)((packed_sample[(i*4)+0]<<4) | (packed_sample[(i*4)+1]>>4));
00323           raw_y = (unsigned short)(((0x0F & packed_sample[(i*4)+1])<<8) | packed_sample[(i*4)+2]);
00324           raw_z = packed_sample[(i*4)+3];
00325 
00326           idx = ((idx+1) < FIFO_DEPTH)? idx+1 : 0;
00327           ((touch_raw_data_t*)raw)[idx].axis.x = raw_x;
00328           ((touch_raw_data_t*)raw)[idx].axis.y = raw_y;
00329           ((touch_raw_data_t*)raw)[idx].axis.z = raw_z;
00330         }
00331 
00332         return packets;
00333       }
00334       return 0;
00335     }
00336     else
00337         return 0;
00338 } /* End of method Get_Fifo() */
00339 
00340 
00341 /**************************************************************************//**
00342  * @brief       Coordinates Transfer function
00343  * @param[in]   points      : number of samples which have to become meaningful
00344 ******************************************************************************/
00345 void Touch::Get_XYZ( int points)
00346 {
00347     if(touch_cfg->name  == "STMPE811")
00348     {
00349         int i, idx;
00350 
00351         for(i=0; i<points; i++)
00352         {
00353             idx = ((last_xyz_idx+1) < FIFO_DEPTH)? last_xyz_idx+1 : 0;
00354             screen_data[idx].axis.x = (signed short)(calib.data.KX1*((signed short)raw_data[idx].axis.x)+calib.data.KX2*((signed short)raw_data[idx].axis.y)+calib.data.KX3+0.5);
00355             screen_data[idx].axis.y = (signed short)(calib.data.KY1*((signed short)raw_data[idx].axis.x)+calib.data.KY2*((signed short)raw_data[idx].axis.y)+calib.data.KY3+0.5);
00356             screen_data[idx].axis.z = ((float)(raw_data[idx].axis.z >> fraction)) + (((float)(raw_data[idx].axis.z & ((0x1<<fraction)-1)))*(1.0f/float(0x1<<fraction)));
00357             last_xyz_idx = idx;
00358             #ifdef MORE_DETAILS
00359                 DBG_MORE("TH_No: (%d)   X-> %d (%d), Y-> %d (%d), Z-> %f (%d), dots-> %d/%d", idx, screen_data[idx].axis.x, raw_data[idx].axis.x, screen_data[idx].axis.y, raw_data[idx].axis.y, screen_data[idx].axis.z, raw_data[idx].axis.z, i+1, points);
00360             #else
00361                 DBG_MORE("TH_No: (%d)   X-> %d, Y-> %d, Z-> %f, dots-> %d/%d", idx, screen_data[idx].axis.x, screen_data[idx].axis.y, screen_data[idx].axis.z, i+1, points);
00362             #endif
00363         }
00364 
00365         x = screen_data[last_xyz_idx].axis.x; adc_x = raw_data[last_xyz_idx].axis.x;
00366         y = screen_data[last_xyz_idx].axis.y; adc_y = raw_data[last_xyz_idx].axis.y;
00367         z = screen_data[last_xyz_idx].axis.z; adc_z = raw_data[last_xyz_idx].axis.z;
00368             #ifdef MORE_DETAILS
00369                 DBG("S_No: (%d)   X-> %d (%d), Y-> %d (%d), Z-> %f (%d), dots-> %d", last_xyz_idx, x, adc_x, y, adc_y, z, adc_z, points);
00370             #else
00371                 DBG("S_No: (%d)   X-> %d, Y-> %d, Z-> %f, dots-> %d", last_xyz_idx, x, y, z, points);
00372             #endif
00373     }
00374 } /* End of method Get_XYZ() */
00375 
00376 
00377 /**************************************************************************//**
00378  * @brief       IRQ interrupt handler : indicates "New Touch Data available" which activates i2c data transfer in Handle_touch()
00379 ******************************************************************************/
00380 void Touch::Irq_Alert()
00381 {
00382     // Execute the time critical part first
00383 
00384     // Then the rest can execute later in user context (and can contain code that's not interrupt safe).
00385     osSignalSet(TouchThreadID, NEW_TOUCH_DATA);
00386 }
00387 
00388 
00389 /**************************************************************************//**
00390  * @brief       Get index of the last sample in the ring buffer
00391  * @retval      idx
00392 ******************************************************************************/
00393 int Touch::Get_Last_Idx() { return last_xyz_idx; }
00394 
00395 /**************************************************************************//**
00396  * @brief       Get dot collection threshold
00397  * @retval      threshold
00398 ******************************************************************************/
00399 int Touch::Get_Dot_thd() { return dot_thd; }
00400 
00401 /**************************************************************************//**
00402  * @brief       Pull the new samples if new touch data is available
00403 ******************************************************************************/
00404 void Touch::Handle_touch()
00405 {
00406     bool Stylus = false;
00407     bool Click_send = false;
00408     unsigned short idx_on = 0;
00409     unsigned char TP_IntStat = 0, rec[2];
00410     int dots = 0;
00411     osEvent evt;
00412 
00413     TouchThreadID = thd.gettid();
00414 
00415     while (true)
00416     {
00417         evt = thd.signal_wait(NEW_TOUCH_DATA);
00418 
00419         if(evt.status == osEventSignal)
00420         {
00421             if(touch_cfg->name  == "STMPE811")
00422             {
00423                 TP_IntStat = INT_STA;
00424                 I2C::write(STMPE811_DEVICE_ADDR, (const char *)&TP_IntStat, 1, true);
00425                 TP_IntStat = 0;
00426                 I2C::read(STMPE811_DEVICE_ADDR, (char *)&TP_IntStat, 1);
00427 
00428                 if(TP_IntStat & INT_FIFO_TH)
00429                 {
00430                     Get_Data(&raw_data[0].dot);
00431                     Get_XYZ(dot_thd);
00432                     if(Stylus)
00433                     {
00434                         if(!Click_send)
00435                         {
00436                             MSG(EV_STYLUS_DOWN, idx_on, 0);
00437                             Click_send = true;
00438                         }
00439                         MSG(EV_STYLUS_HOLD, idx_on, last_xyz_idx);
00440                     }
00441                 }
00442 
00443                 if(TP_IntStat & INT_TOUCH_DET)
00444                 {
00445                     Stylus = Get_Pen_Status();
00446                     DBG("Pen: %s", (Stylus)? "DOWN" : "UP");
00447 
00448                     dots = Get_Fifo(&raw_data[0].dot);
00449                     if(dots)
00450                     {
00451                         Get_XYZ(dots);
00452 
00453                         if(Stylus)
00454                         {
00455                             int on = (last_xyz_idx+1) - dots;
00456                             idx_on = (on<0)? (FIFO_DEPTH-on) : on;
00457                             MSG(EV_STYLUS_DOWN, idx_on, 0);
00458                             Click_send = true;
00459                         }
00460                         else
00461                         {
00462                             if(!Click_send)
00463                             {
00464                                 MSG(EV_STYLUS_DOWN, idx_on, 0);
00465                                 Click_send = true;
00466                             }
00467                             MSG(EV_STYLUS_UP, idx_on, last_xyz_idx);
00468                         }
00469                     }
00470                     else
00471                     {
00472                         if(Stylus)
00473                         {
00474                             Click_send = false;
00475                             idx_on = (last_xyz_idx == (FIFO_DEPTH-1))? 0 : last_xyz_idx+1;
00476                         }
00477                         else
00478                         {
00479                             if(Click_send)
00480                                 MSG( EV_STYLUS_UP, idx_on, last_xyz_idx);
00481                         }
00482                     }
00483                 }
00484 
00485                 if(TP_IntStat & INT_FIFO_OFLOW)
00486                 {
00487                     DBG("Overflow !!!");
00488 
00489                     rec[0] = FIFO_STA;
00490                     rec[1] = 0x01;      // Clear FIFO
00491                     I2C::write(STMPE811_DEVICE_ADDR, (const char *)rec, 2);
00492 
00493                     rec[1] = 0x00;      // Reset FIFO
00494                     I2C::write(STMPE811_DEVICE_ADDR, (const char *)rec, 2);
00495                 }
00496 
00497                 rec[0] = INT_STA;
00498                 rec[1] = TP_IntStat;
00499                 I2C::write(STMPE811_DEVICE_ADDR, (const char *)rec, 2);
00500             }
00501         }
00502         else
00503         {
00504             DBG("Abnormal Touch Thread Status: 0x%X", evt.status);
00505         }
00506     }
00507 }
00508 
00509 } // namespace Vekatech
00510 
00511 /* End of file */