📄 vr4181.c
字号:
/*** $Id: vr4181.c,v 1.15 2003/09/04 03:38:26 weiym Exp $**** vr4181.c: Low Level Input Engine for NEC VR4181 debug board.** ** Copyright (C) 2001 RedFlag Software. **** Author: Luo Gang.**** Created by Wei Yongming, 2001/08/20*//*** This program is free software; you can redistribute it and/or modify** it under the terms of the GNU General Public License as published by** the Free Software Foundation; either version 2 of the License, or** (at your option) any later version.**** This program is distributed in the hope that it will be useful,** but WITHOUT ANY WARRANTY; without even the implied warranty of** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the** GNU General Public License for more details.**** You should have received a copy of the GNU General Public License** along with this program; if not, write to the Free Software** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <errno.h>#include <fcntl.h>#include <sys/poll.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/ioctl.h>#include <linux/kd.h>#include "common.h"#ifdef _VR4181_IAL#include "ial.h"#include "vr4181.h"/* define _VR_BUTTONS to include button handling */#undef _VR_BUTTONS#define TP_DEV_FILE "/dev/tpanel"#define BTN_DEV_FILE "/dev/vrbuttons"#define WIDTH 320#define HEIGHT 240typedef struct { short b; short x; short y; short pad;} POS;typedef struct { int a; int b; int c; int d; int e; int f; int s;} TRANSF_COEFF;typedef struct{ int x, y;} XYPOINT;struct scanparam { unsigned int interval; unsigned int settletime;};#define TPGETSCANPARM _IOR( 0xB0, 0x00, struct scanparam )#define TPSETSCANPARM _IOW( 0xB0, 0x01, struct scanparam )static int ts = -1;static int mousex = 0;static int mousey = 0;static int mousez = 0;static unsigned short btn_state = 0;static unsigned char state[NR_KEYS];#ifdef _VR_BUTTONSstatic int btn_fd = -1;#endif/* * Set default scan interval in microseconds (50 Hz). * If you adjust this value, you may also want to adust iir_shift_bits * in VrTpanelRead. */int scan_interval = 20000;/* * Set default settle time in microseconds. * Functional upper limit on settle time is approximately * (scan_interval / 5) - 60 (5 conversions and some fixed overhead * fitting within scan interval). The opmtimal value is the lowest * that doesn't cause significant distortion. The lower the value, * the more "simultaneous" and thus coherent the conversions. * 480us is probably a reasonable value for most hardware. Lower * than that can get into distortion. */int scan_settle_time = 480;/* * Set default low z limit. If z measurement data is below this value, * ignore the data. */int low_z_limit = 800;/* * Enable absolute coordinate transformation. * Normally this should be left at 1. * To disable transformation, set it to 0 before calling VrPanelInit. * This is done by the pointer calibration utility since it's used to produce the pointer * calibration data file. */int Vr_enable_transform = 1;#if TESTstatic int show_raw = 0;static int show_filtered = 0;static int show_enqueue = 0;#endifstatic TRANSF_COEFF tc;static int GetPointerCalibrationData(void){ /* * Read the calibration data from the calibration file. * Calibration file format are these values separated by spaces: * - Seven tranformation coefficients a, b, c, d, e, f, and g * - Scan interval microseconds * - Scan settle time in microseconds * - Low-z limit */ /* Get pointer calibration data from this file */ const char cal_filename[] = "/etc/pointercal"; int items; FILE* cf = fopen (cal_filename, "r"); if ( cf == NULL ) { fprintf(stderr, "Error %d opening pointer calibration file %s.\n", errno, cal_filename); return -1; } items = fscanf(cf, "%d %d %d %d %d %d %d %d %d %d", &tc.a, &tc.b, &tc.c, &tc.d, &tc.e, &tc.f, &tc.s, &scan_interval, &scan_settle_time, &low_z_limit); if (items < 7) { fprintf(stderr, "Improperly formatted pointer calibration file %s.\n", cal_filename); fclose(cf); return -1; } fclose(cf); return 0;}#ifndef TRANSFORMATION_UNITS_PER_PIXEL#define TRANSFORMATION_UNITS_PER_PIXEL 4#endifXYPOINT DeviceToScreen(XYPOINT p){ /* * Transform device coordinates to screen coordinates. * Take a point p in device coordinates and return the corresponding * point in fractional screen coodinates (fraction is * 1 / TRANSFORMATION_UNITS_PER_PIXEL). * * It can scale, translate, rotate and/or skew, based on the coefficients * calculated above based on the list of screen vs. device coordinates. */ static XYPOINT prev; /* Slop is how far the pointer has to move before we will allow the output * to change. Optimal is probably 3/4 of a pixel, but that might not be * enough for some panels that are very noisey. * Using larger values appears to makes the pointer movement more "blocky". * This is noticeable, say, when drawing a line at a 45 degree angle. */ /* TODO: make this configurable */ const short slop = TRANSFORMATION_UNITS_PER_PIXEL * 3 / 4; XYPOINT new, out; /* Transform */ new.x = (tc.a * p.x + tc.b * p.y + tc.c) / tc.s; new.y = (tc.d * p.x + tc.e * p.y + tc.f) / tc.s; /* Hysteresis (thanks to John Siau) */ if ( abs(new.x - prev.x) >= slop ) out.x = (new.x | 0x3) ^ 0x3; else out.x = prev.x; if ( abs(new.y - prev.y) >= slop ) out.y = (new.y | 0x3) ^ 0x3; else out.y = prev.y; prev = out; return out;}static int VrTpanelInit(void){ /* * Open up the touch-panel device. * Return the fd if successful, or negative if unsuccessful. */ struct scanparam s; int result; int fd; /* Read the calibration file first for scan interval and settling time. */ GetPointerCalibrationData(); /* Open the touch-panel device. */ fd = open (TP_DEV_FILE, O_RDONLY); if (fd < 0) { fprintf(stderr, "Error %d opening touch panel\n", errno); return -1; } s.interval = scan_interval; s.settletime = scan_settle_time; result = ioctl (fd, TPSETSCANPARM, &s); if ( result < 0 ) fprintf(stderr, "Error %d, result %d setting scan parameters.\n", result, errno); return fd;}/* mouse button bits in BUTTON */#define LBUTTON 04#define MBUTTON 02#define RBUTTON 01static int VrTpanelRead(int fd, int *px, int *py, int *pz, unsigned int *pb){ /* * This driver returns absolute postions, not deltas. * Returns the position in px, py, pressure in pz, and buttons pb. * Returns -1 on error. * Returns 0 if no new data is available. * Does not return 1 (which is for relative position data). * Returns 2 if position data is absolute (i.e. touch panels). * Returns 3 if position data is not available, but button data is. * This routine does not block. */ /* * I do some error masking by tossing out really wild data points. * Lower data_change_limit value means pointer get's "left behind" more easily. * Higher value means less errors caught. * The right setting of this value is just slightly higher than the number of * units traversed per sample during a "quick" stroke. * I figure a fast pen scribble can cover about 3000 pixels in one second on a typical screen. * There are typically about 3 to 6 points of touch-panel resolution per pixel. * So 3000 pixels-per-second * 3 to 6 tp-points-per-pixel / 50 samples-per-second = * 180 to 360 tp points per scan. */ /* TODO: make this configurable */ const int data_change_limit = 360; static int have_last_data = 0; static int last_data_x = 0; static int last_data_y = 0; /* * Thanks to John Siau <jsiau@benchmarkmedia.com> for help with the noise filter. * I use an infinite impulse response low-pass filter on the data to filter out * high-frequency noise. Results look better than a finite impulse response filter. * If I understand it right, the nice thing is that the noise now acts as a dither * signal that effectively increases the resolution of the a/d converter by a few bits * and drops the noise level by about 10db. * Please don't quote me on those db numbers however. :-) * The end result is that the pointer goes from very fuzzy to much more steady. * Hysteresis really calms it down in the end (elsewhere). * * iir_shift_bits effectively sets the number of samples used by the filter * (number of samples is 2^iir_shift_bits). * * Setting iir_shift_bits lower allows shorter "taps" and less pointer lag, but a * fuzzier pointer, which can be especially bad for display update when dragging. * * Setting iir_shift_bits higher requires longer "presses" and causes more pointer lag, * but it provides steadier pointer. * * If you adjust iir_shift_bits, you may also want to adjust the sample interval * in VrTpanelInit. * * The filter gain is fixed at 8 times the input (gives room for increased resolution * potentially added by the noise-dithering). * * The filter won't start outputing data until iir_count is above iir_output_threshold. */ const int iir_shift_bits = 2; const int iir_sample_depth = (1 << iir_shift_bits); const int iir_output_threshold = 1; const int iir_gain = 8; static int iir_accum_x = 0; static int iir_accum_y = 0; static int iir_accum_z = 0; static int iir_count = 0; int iir_out_x; int iir_out_y; int iir_out_z; int data_x, data_y, data_z; /* read a data point */ short data[6]; int bytes_read;again: bytes_read = read (fd, data, sizeof(data)); if (bytes_read != sizeof (data)) { if (errno == EINTR) goto again; else return -1; } /* did we lose any data? */ if ( (data[0] & 0x2000) ) fprintf(stderr, "Lost touch panel data\n");#if TEST if ( show_raw ) printf("Raw %.4hx %s %s x %5hd %5hd %5hd y %5hd %5hd %5hd z %5hd\n", data[0], data[0] & 0x8000 ? "data " : "no data", data[0] & 0x4000 ? "down" : "up ", data[1], data[2], data[2] - data[1], data[3], data[4], data[4] - data[3], data[5]);#endif /* do we only have contact state data (no position data)? */ if ( (data[0] & 0x8000) == 0 ) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -