#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <sys/types.h>
#include <fcntl.h>
#include <linux/input.h>
#include <linux/uinput.h>
#include <sys/time.h>
#include <gmp.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <tslib.h>
#include "fbvncserver.h"
#include "dev_uinput.h"
Include dependency graph for tssimd.c:
Go to the source code of this file.
Defines | |
#define | DefaultTS "/dev/sharp_ts" |
#define | DefaultTSCal "/etc/pointercal" |
#define | EV_SYN 0 |
Functions | |
void | display_help (char *arg0) |
display info on how to use tssimd | |
int | main (int argc, char **argv) |
int | node_is_sane (int fd) |
checks, if this event node is a valid vnc mouse event source | |
int | vncts (int vnctsfd, struct ts_sample *samp) |
int | write_to_fifo (char *buf, int size) |
void | write_to_input (int fd, struct t_ts_event *tsevent) |
TSLIB_TSDEVICE | | HW TS -> tslib ------------------------------------ VNC -> fbvncserver -> uinput -> kernel -> evdev - | | | | | | | V V +--------+ | tssimd | +--------+ | | /dev/tsvnc | V tslib
Definition in file tssimd.c.
#define DefaultTS "/dev/sharp_ts" |
#define DefaultTSCal "/etc/pointercal" |
#define EV_SYN 0 |
Definition at line 67 of file tssimd.c.
Referenced by dev_uinput_init_mouse(), dev_uinput_sync(), node_is_sane(), and vncts().
void display_help | ( | char * | arg0 | ) |
display info on how to use tssimd
[in] | char* |
Definition at line 267 of file tssimd.c.
Referenced by main().
00267 { 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 };
int main | ( | int | argc, | |
char ** | argv | |||
) |
Definition at line 281 of file tssimd.c.
References DefaultTS, DefaultTSCal, dev_uinput_init_mouse(), display_help(), node_is_sane(), PACKAGE_STRING, TRACE, TRACE1, UINPUT_INPUTAPI_NAME, vncts(), write_to_fifo(), and write_to_input().
00281 { 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 }
Here is the call graph for this function:
int node_is_sane | ( | int | fd | ) |
checks, if this event node is a valid vnc mouse event source
[in] | fd | file descriptor of the node to check |
Definition at line 155 of file tssimd.c.
References EV_SYN, TRACE, TRACE1, TRACE2, and UINPUT_TS_NAME.
Referenced by main().
00155 { 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 }
int vncts | ( | int | vnctsfd, | |
struct ts_sample * | samp | |||
) |
Definition at line 187 of file tssimd.c.
References EV_SYN, and TRACE1.
Referenced by main().
00187 { 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 }
int write_to_fifo | ( | char * | buf, | |
int | size | |||
) |
Definition at line 118 of file tssimd.c.
References TRACE1, and TRACE2.
Referenced by main().
00118 { 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 }
void write_to_input | ( | int | fd, | |
struct t_ts_event * | tsevent | |||
) |
Definition at line 107 of file tssimd.c.
References button_click(), dev_uinput_sync(), ptr_abs(), and TRACE2.
Referenced by main().
00107 { 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 }
Here is the call graph for this function: