tssimd.c

Go to the documentation of this file.
00001 /********************************************************
00002  This file is part of fbvncserver.
00003 
00004  fbvncserver is free software; you can redistribute it
00005  and/or modify it under the terms of the
00006  GNU General Public License as published by
00007  the Free Software Foundation; either version 2 of the
00008  License, or (at your option) any later version.
00009 
00010  fbvncserver is distributed in the hope that it will be
00011  useful, but WITHOUT ANY WARRANTY; without even the
00012  implied warranty of MERCHANTABILITY or FITNESS FOR A
00013  PARTICULAR PURPOSE.  See the GNU General Public License
00014  for more details.
00015 
00016  You should have received a copy of the GNU General Public
00017  License along with fbvncserver; if not, write to the
00018  Free Software Foundation, Inc., 51 Franklin St,
00019  Fifth Floor, Boston, MA  02110-1301  USA
00020  ********************************************************/
00021 
00050 #include <stdio.h>
00051 #include <stdlib.h>
00052 #include <string.h>
00053 #include <ctype.h>
00054 #include <unistd.h>
00055 #include <errno.h>
00056 #include <signal.h>
00057 
00058 #include <sys/types.h>
00059 
00060 #include <fcntl.h>
00061 #include <errno.h>
00062 
00063 /* KERNEL */
00064 #include <linux/input.h>
00065 /* 2.4 kernel headers */
00066 #ifndef EV_SYN
00067 #define EV_SYN 0
00068 #endif
00069 #include <linux/uinput.h>
00070 
00071 /* GNU C Library */
00072 #include <sys/time.h>
00073 #include <gmp.h> /* Multiple Precision Arithmetic
00074                   * Documentation @ http://www.gnu.org/software/gmp/manual/html_node/index.html
00075                   */
00076 
00077 /* POSIX */
00078 #include <sys/select.h> /* synchronous I/O multiplexing         */
00079 #include <sys/stat.h>   /* data returned by the stat() function */
00080 
00081 /* aux */
00082 #include <tslib.h>
00083 
00084 /* Project */
00085 #include "fbvncserver.h" /* Projectwide Macros & Definitions */
00086 #include "dev_uinput.h"  /* uinput kernel interface          */
00087 
00088 /* Constants */
00089 #define DefaultTS "/dev/sharp_ts"       
00093 #define DefaultTSCal "/etc/pointercal"  
00097 /* Used for Sharp Zaurus SL-5000d and SL-5500 */
00098 struct t_ts_event {
00099         long y;
00100         long x;
00101         long pressure;
00102         long long millisecs;
00103 };
00104 
00105 static struct t_ts_event tsevent;
00106 
00107 void write_to_input(int fd, struct t_ts_event *tsevent) {
00108   ptr_abs(fd,tsevent->x,tsevent->y);
00109   TRACE2(" [I] inputAPI - x=%d, y=%d \n",tsevent->x,tsevent->y);
00110   if ((tsevent->pressure) > 0) {
00111     button_click(fd,1);
00112   } else {
00113     button_click(fd,0);
00114   } // end of [if]
00115   dev_uinput_sync(fd);
00116 }
00117 
00118 int write_to_fifo (char *buf, int size) {
00119   char *fname;
00120   static int fifo;
00121 
00122   fname="/dev/tsvnc";
00123 
00124   TRACE2(" [I] %d Bytes => fifo (fd: %d)...\n", size, fifo);
00125 
00126   if(fifo<=0)
00127     if((fifo=open(fname,O_WRONLY | O_NONBLOCK))<=0) {
00128       TRACE1(" [W] unable to open fifo %s - no listeners? \n",fname);
00129       return(-1);
00130     }
00131 
00132   if(size!=0 && write(fifo,buf,size)==-1 && errno==EPIPE) {
00133     close(fifo);
00134     fifo=-1;
00135     return(-1);
00136   }
00137 
00138   TRACE1(" [I] sent to %s \n", fname);
00139   return(0);
00140 }
00141 
00142 static char *devs[] = {
00143         "/dev/input/event0",
00144         "/dev/input/event1",
00145         "/dev/input/event2",
00146         "/dev/input/event3",
00147         NULL
00148 };
00149 
00155 int node_is_sane (int fd) {
00156   int version;
00157   u_int32_t bit;
00158   u_int64_t absbit;
00159   char name[UINPUT_MAX_NAME_SIZE] = "unknown";
00160 
00161   if (! ((ioctl(fd, EVIOCGVERSION, &version) >= 0) &&
00162     (version == EV_VERSION) &&
00163     (ioctl(fd, EVIOCGBIT(0, sizeof(bit) * 8), &bit) >= 0) &&
00164     (bit & (1 << EV_ABS)) &&
00165     (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit) * 8), &absbit) >= 0) &&
00166     (bit & (1 << EV_SYN))   &&
00167     (bit & (1 << EV_KEY))   &&
00168     (absbit & (1 << ABS_X)) &&
00169     (absbit & (1 << ABS_Y)) )) {
00170 
00171     TRACE(" => event source did NOT pass sanity check. \n");
00172     return -1;
00173     }
00174 
00175   ioctl(fd, EVIOCGNAME(sizeof(name)), name);
00176   if (strcmp(name,UINPUT_TS_NAME) != 0) {
00177     TRACE2(" [I] node name (%s) does not match (!= %s) \n", &name, UINPUT_TS_NAME);
00178     TRACE(" => event source did NOT pass sanity check. \n");
00179     return -1;
00180   }
00181 
00182   TRACE (" => event source passed sanity check. \n");
00183   TRACE1("  - %s - will be used. \n",name);
00184   return 1;
00185 }
00186 
00187 int vncts(int vnctsfd, struct ts_sample *samp) {
00188   struct buffer {
00189     int current_x;
00190     int current_y;
00191     int current_p;
00192 
00193     struct timeval time;
00194   };
00195 
00196   struct input_event ev;
00197   static struct buffer i;
00198   static int pressed = 0;
00199   int size = 0;
00200 
00201   size = read(vnctsfd, &ev, sizeof(struct input_event));
00202   TRACE1(" [I] %d bytes read from uinput \n", size);
00203   if (size < (int)sizeof(struct input_event)) {
00204                 if (pressed == 1) {
00205                         samp->x = i.current_x;
00206                         samp->y = i.current_y;
00207                         samp->pressure = i.current_p;
00208                         gettimeofday(&(i.time),NULL);
00209                         samp->tv = i.time;
00210                         return 1;
00211                 } else {
00212                 }
00213         }
00214 
00215         switch (ev.type) {
00216                 case EV_KEY:
00217                         switch (ev.code) {
00218                                 case BTN_TOUCH:
00219                                         if (ev.value == 0) {    /* pen up */
00220                                                 samp->x = 0;
00221                                                 samp->y = 0;
00222                                                 samp->pressure = 0;
00223                                                 samp->tv = ev.time;
00224                                                 pressed = 0;
00225                                                 return 1;
00226                                         } else {
00227                                                 pressed = 1;
00228                                         }
00229                                 break;
00230                         }
00231                         break;
00232                 case EV_SYN:    /* Fill out a new complete event */
00233                         samp->x = i.current_x;
00234                         samp->y = i.current_y;
00235                         samp->pressure = i.current_p;
00236                         i.time = ev.time;
00237                         samp->tv = ev.time;
00238                         if (i.current_p > 0) {
00239                                 pressed = 1;
00240                         } else {
00241                                 pressed = 0;
00242                         }
00243                         return 1;
00244                 break;
00245                 case EV_ABS:
00246                         switch (ev.code) {
00247                                 case ABS_X:
00248                                         i.current_x = ev.value;
00249                                         break;
00250                                 case ABS_Y:
00251                                         i.current_y = ev.value;
00252                                 break;
00253                                 case ABS_PRESSURE:
00254                                         i.current_p = ev.value;
00255                                 break;
00256                         }
00257                         break;
00258                 }
00259 
00260   return -1;
00261 }
00262 
00267 void display_help(char* arg0) {
00268   printf("%s: error !\n",arg0);
00269 #ifdef DEBUG
00270   printf("Usage: %s [-inputAPI] [-debug] ",arg0);
00271 #else
00272   printf("Usage: %s [-inputAPI] ",arg0);
00273 #endif
00274   printf("\n");
00275   printf("  -input: send TS events to input API \n");
00276 #ifdef DEBUG
00277   printf("  -debug \n\n");
00278 #endif
00279 };
00280 
00281 int main(int argc, char **argv) {
00282   struct tsdev *ts;
00283 
00284   struct linear {
00285     int     swap_xy;
00286 
00287 // Linear scaling and offset parameters for pressure
00288     int     p_offset;
00289     int     p_mult;
00290     int     p_div;
00291 
00292 // Linear scaling and offset parameters for x,y (can include rotation)
00293     mpf_t   a[7];
00294   };
00295 
00296   char *tsdev;         // HW touchscreen device node
00297   char *calfile=NULL;  // TS clibration file
00298   char *tokptr;
00299   char pcalbuf[200];
00300 
00301   int hwtsfd = 0,      // HW TS file descriptor
00302      vnctsfd = 0,      // VNC TS file descriptor
00303 
00304       pcal_fd = 0,     // calibration file fd
00305 
00306    inputAPIfd = 0;     // merged TS (inputAPI)
00307 
00308   fd_set fds;          // fd(s) for synchronous I/O multiplexing
00309 
00310   struct linear lin;   // linear calibration constants
00311   struct stat sbuf;
00312   struct timeval tv;
00313 
00314   int vnctssane = 0,   // vnc event source passed sanity check(s)
00315       inputAPI = 0,    // send events to input API (0,1)
00316       index = 0, i = 0, retval = 0;
00317 
00318 /***
00319  * read environment settings
00320  ***/
00321   if( (tsdev = getenv("TSLIB_TSDEVICE")) == NULL)  tsdev = strdup (DefaultTS);
00322   if( (calfile = getenv("TSLIB_CALIBFILE")) == NULL) calfile = strdup (DefaultTSCal);
00323 
00324   mpf_t b[9]; // pre-calculated calibration values (derived from linear.a)
00325   mpf_t c[6]; // pre-calculated calibration values (derived from b)
00326   mpf_t mpf_helper1, mpf_helper2;
00327 
00328   mpf_init(lin.a[0]);
00329   mpf_init(lin.a[1]);
00330   mpf_init(lin.a[2]);
00331   mpf_init(lin.a[3]);
00332   mpf_init(lin.a[4]);
00333   mpf_init(lin.a[5]);
00334   mpf_init(lin.a[6]);
00335 
00336   printf("%s (%s %s) \n",PACKAGE_STRING,__DATE__, __TIME__ );
00337 /***
00338  * process command line arguments
00339  ***/
00340   for(i=1;i<argc;i++) {
00341     if(!strcmp(argv[i],"-h") ||
00342        !strcmp(argv[i],"-?") ||
00343        !strcmp(argv[i],"/?") ||
00344        !strcmp(argv[i],"-help") ||
00345        !strcmp(argv[i],"--help")) { display_help(argv[0]); return(-1); }
00346       else if(!strcmp(argv[i],"-inputAPI")) { inputAPI = 1;}
00347 #ifdef DEBUG
00348       else if(!strcmp(argv[i],"-debug")) { debug = 1;}
00349 #endif
00350   }
00351 
00352   TRACE1(" [I] %s will be used as HW TS event source \n",tsdev);
00353   TRACE1(" [I] %s will be used to calculate raw frames \n", calfile);
00354 
00355 /***
00356  * prepare HW TS
00357  ***/
00358   ts = ts_open(tsdev,0);
00359   if (!ts) {
00360     perror("ts_open");
00361     exit(1);
00362   }
00363   TRACE(" [I] HW TS open ...\n");
00364   if (ts_config(ts)) {
00365     perror("ts_config");
00366     exit(1);
00367   }
00368   TRACE(" [I] HW TS configured ... \n");
00369   hwtsfd = ts_fd(ts);
00370   TRACE1(" [I] HW TS FD: %d\n", hwtsfd);
00371 
00372 /***
00373  * prepare VNC TS
00374  ***/
00375     i=0;
00376     while (devs[i] != NULL) {
00377       TRACE1(" [I] %s ... ",devs[i]);
00378       vnctsfd = open(devs[i++], O_RDONLY | O_NONBLOCK);
00379        if (vnctsfd > 0) {
00380          if  ((node_is_sane(vnctsfd)) > 0) {
00381            vnctssane = 1;
00382            break;
00383          }
00384        } else {
00385        TRACE(" - not present. \n");
00386       }
00387     }
00388 /***
00389  * prepare merged TS
00390  ***/
00391     if (inputAPI) {
00392       inputAPIfd = dev_uinput_init_mouse(UINPUT_INPUTAPI_NAME);
00393       if (inputAPIfd < 1) {
00394         TRACE(" [F] unable to create a new uinput node for the merged TS \n");
00395         perror("dev_uinput_init_mouse");
00396         exit(1);
00397       } // end of [if]
00398       TRACE(" [I] we'll use inputAPI ... \n");
00399     } // end of [if]
00400 /***
00401  * read calibration file
00402  ***/
00403    // Use default values that leave ts numbers unchanged after transform
00404 
00405      mpf_set_si(lin.a[0],1);
00406      mpf_set_si(lin.a[1],0);
00407      mpf_set_si(lin.a[2],0);
00408      mpf_set_si(lin.a[3],0);
00409      mpf_set_si(lin.a[4],1);
00410      mpf_set_si(lin.a[5],0);
00411      mpf_set_si(lin.a[6],1);
00412 
00413      lin.p_offset = 0;
00414      lin.p_mult   = 1;
00415      lin.p_div    = 1;
00416      lin.swap_xy  = 0;
00417 
00418      if(stat(calfile,&sbuf)==0) {
00419        pcal_fd = open(calfile,O_RDONLY);
00420        read(pcal_fd,pcalbuf,200);
00421        mpf_set_si(lin.a[0],atoi(strtok(pcalbuf," ")));
00422        index=1;
00423        while(index<7) {
00424          tokptr = strtok(NULL," ");
00425          if(*tokptr!='\0') {
00426            mpf_set_si(lin.a[index],atoi(tokptr));
00427            index++;
00428          }
00429        }
00430      }
00431 /* Ignore SIGPIPE, so our writes can return EPIPE */
00432   signal(SIGPIPE,SIG_IGN);
00433 
00434 /* some pre-calculations (to save cpu power) ...
00435  * ... as some quite big numbers are involved we have to use high precision
00436  *     arithmetics
00437  */
00438   mpf_init(mpf_helper1);
00439   mpf_init(mpf_helper2);
00440 
00441   for(index=0;index<9;index++) mpf_init(b[index]);
00442   for(index=0;index<6;index++) mpf_init(c[index]);
00443 
00444   mpf_neg(mpf_helper1,lin.a[1]);          // b[0] = -lin.a[1] * lin.a[6];
00445   mpf_mul(b[0],mpf_helper1,lin.a[6]);
00446   mpf_mul(b[1],lin.a[4],lin.a[6]);        // b[1] =  lin.a[4] * lin.a[6];
00447   mpf_mul(b[2],lin.a[1],lin.a[5]);        // b[2] =  lin.a[1] * lin.a[5];
00448   mpf_mul(b[3],lin.a[2],lin.a[4]);        // b[3] =  lin.a[2] * lin.a[4];
00449   mpf_mul(mpf_helper1,lin.a[1],lin.a[3]); // b[4] =  lin.a[1] * lin.a[3] - lin.a[0] * lin.a[4];
00450   mpf_mul(mpf_helper2,lin.a[0],lin.a[4]);
00451   mpf_sub(b[4],mpf_helper1,mpf_helper2);
00452   mpf_neg(mpf_helper1,lin.a[0]);          // b[5] = -lin.a[0] * lin.a[6];
00453   mpf_mul(b[5],mpf_helper1,lin.a[6]);
00454   mpf_mul(b[6],lin.a[3],lin.a[6]);        // b[6] =  lin.a[3] * lin.a[6];
00455   mpf_mul(b[7],lin.a[0],lin.a[6]);        // b[7] =  lin.a[0] * lin.a[5];
00456   mpf_mul(b[8],lin.a[2],lin.a[3]);        // b[8] =  lin.a[2] * lin.a[3];
00457 
00458   mpf_div(c[0],b[0],b[4]);                // c[0] = b[0] / b[4];
00459   mpf_div(c[1],b[1],b[4]);                // c[1] = b[1] / b[4];
00460   mpf_sub(mpf_helper1,b[2],b[3]);         // c[2] = (b[2] - b[3]) / b[4];
00461   mpf_div(c[2],mpf_helper1,b[4]);
00462   mpf_div(c[3],b[5],b[4]);                // c[3] = b[5] / b[4];
00463   mpf_div(c[4],b[6],b[4]);                // c[4] = b[6] / b[4];
00464   mpf_sub(mpf_helper1,b[7],b[8]);         // c[5] = (b[7] - b[8]) / b[4];
00465   mpf_div(c[5],mpf_helper1,b[4]);
00466 
00467 #ifdef DEBUG
00468   if (debug) {
00469 /*
00470     for(index=0;index<7;index++) gmp_printf(" [I]: a[%d] = %Ff \n",index,lin.a[index]);
00471     TRACE(" ---- \n");
00472     for(index=0;index<9;index++) gmp_printf(" [I]: b[%d] = %Ff \n",index,b[index]);
00473     TRACE(" ---- \n");
00474     for(index=0;index<6;index++) gmp_printf(" [I]: c[%d] = %Ff \n",index,c[index]);
00475 */
00476     TRACE(" [I] raw equations: \n")
00477     gmp_printf(" => rawx = %Ff * y +  %Ff * x + %Ff \n", c[0],c[1], c[2]);
00478     gmp_printf(" => rawy = %Ff * y +  %Ff * x + %Ff \n", c[3],c[4],c[5]);
00479   }
00480 #endif
00481 
00482 
00483   while (1) {
00484     struct ts_sample samp;
00485 
00486     FD_ZERO(&fds);
00487     FD_SET(hwtsfd,&fds);
00488 
00489     if (vnctssane == 1) {
00490       FD_SET(vnctsfd,&fds);
00491     } else {
00492       TRACE(" [W] vnc ts events will not be processed => transparent mode. \n");
00493     }
00494     tv.tv_sec = 5; tv.tv_usec = 0;
00495     retval = select(FD_SETSIZE,&fds,NULL,NULL,&tv);
00496     switch (retval) {
00497       case EBADF:
00498         TRACE(" [W] An invalid file descriptor was given in one of the sets. \n");
00499         break;
00500       case EINTR:
00501         TRACE(" [W] A non blocked signal was caught. \n");
00502         break;
00503       case EINVAL:
00504         TRACE(" [W] n is negative or the value contained within timeout is invalid. \n");
00505         break;
00506       case ENOMEM:
00507         TRACE(" [W] select() was unable to allocate memory for internal tables. \n");
00508         break;
00509       case 0:
00510         // TRACE(" [W] select () - timeout ... \n");
00511         // write_to_fifo(NULL,0);
00512         break;
00513       case 1:
00514         TRACE(" [I] event catched ... ");
00515         if (FD_ISSET(hwtsfd,&fds)) {
00516           TRACE(" [- HW -] \n");
00517           retval = ts_read_raw(ts,&samp,1);
00518           if (retval < 0) {
00519             perror("ts_read_raw");
00520             exit;
00521           }
00522 
00523           tsevent.y = samp.y;
00524           tsevent.x = samp.x;
00525           tsevent.pressure = samp.pressure;
00526           tsevent.millisecs = ((samp.tv.tv_sec * 1000) + samp.tv.tv_usec);
00527 
00528           write_to_fifo((char*) &tsevent,sizeof(tsevent));
00529         }
00530         if (vnctssane == 1) {
00531           if (FD_ISSET(vnctsfd,&fds)) {
00532             TRACE(" [- VNC -] \n");
00533             if (vncts(vnctsfd,&samp) == 1) {
00534               mpf_t tmpy, tmpx;
00535               mpf_init(tmpx);
00536               mpf_init(tmpy);
00537 
00538            // tmpx = c[0] * samp.y + c[1] * samp.x + c[2];
00539               mpf_set_si(mpf_helper1,samp.x);
00540               mpf_set_si(mpf_helper2,samp.y);
00541               mpf_mul(mpf_helper2,c[0],mpf_helper2);
00542               mpf_mul(mpf_helper1,c[1],mpf_helper1);
00543               mpf_add(tmpx,mpf_helper1,mpf_helper2);
00544               mpf_add(tmpx,tmpx,c[2]);
00545 
00546           // tmpy = c[3] * samp.y + c[4] * samp.x + c[5];
00547               mpf_set_si(mpf_helper1,samp.x);
00548               mpf_set_si(mpf_helper2,samp.y);
00549               mpf_mul(mpf_helper2,c[3],mpf_helper2);
00550               mpf_mul(mpf_helper1,c[4],mpf_helper1);
00551               mpf_add(tmpy,mpf_helper1,mpf_helper2);
00552               mpf_add(tmpy,tmpy,c[5]);
00553 /*
00554 ... this reverts the linear calibration as applied by tslib
00555 
00556 (%i1) solve([x=(a2+a0*xtemp+a1*ytemp)/a6, y=(a5+a3*xtemp+a4*ytemp)/a6],[xtemp,ytemp]);
00557 
00558                   - a1 a6 y + a4 a6 x + a1 a5 - a2 a4
00559 (%o1) [[xtemp = - -----------------------------------,
00560                              a1 a3 - a0 a4
00561 
00562                   - a0 a6 y + a3 a6 x + a0 a5 - a2 a3
00563         ytemp = -----------------------------------]]
00564                              a1 a3 - a0 a4
00565 
00566               tmpx = ( -lin.a[1] * lin.a[6] * samp.y +
00567                         lin.a[4] * lin.a[6] * samp.x +
00568                         lin.a[1] * lin.a[5] -
00569                         lin.a[2] * lin.a[4]) / (lin.a[1] * lin.a[3] - lin.a[0] * lin.a[4]);
00570 
00571               tmpy = ( -lin.a[0] * lin.a[6] * samp.y +
00572                         lin.a[3] * lin.a[6] * samp.x +
00573                         lin.a[0] * lin.a[5] -
00574                         lin.a[2] * lin.a[3]) / (lin.a[1] * lin.a[3] - lin.a[0] * lin.a[4]);
00575 */
00576               tsevent.y = mpf_get_si(tmpy);
00577               tsevent.x = -mpf_get_si(tmpx);
00579 #ifdef DEBUG
00580               if (debug) {
00581                 gmp_printf(" [I]    x: %d,    y: %d \n", samp.x,samp.y);
00582                 gmp_printf(" [I] rawx: %d, rawy: %d \n", tsevent.x, tsevent.y);
00583               }
00584 #endif
00585               tsevent.pressure = samp.pressure;
00586               tsevent.millisecs = ((samp.tv.tv_sec * 1000) + samp.tv.tv_usec);
00587 
00588               if (!inputAPI) {
00589                 write_to_fifo((char*) &tsevent,sizeof(tsevent));
00590               } else {
00591                 write_to_input(inputAPIfd,&tsevent);
00592               } // end if [if]
00593             }
00594           }
00595         }
00596         break;
00597     }
00598   }
00599 }