⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mou_tp.c

📁 神龙卡开发原代码
💻 C
字号:
/* * drivers/mou_tp.c * * Touch-panel driver * * Designed for for use with the Linux-VR project touch-panel kernel driver. * This includes the VTech Helio. * Also runs with Embedded Planet's PowerPC LinuxPlanet. * Also runs with Yopy (untested, can use mou_yopy.c also) * * Requires /dev/tpanel kernel driver (char special 10,11) * * Copyright (C) 1999 Bradley D. LaRonde <brad@ltc.com> * Portions Copyright (c) 2001 Kevin Oh <webmaster@prg-lib.net> * Portions Copyright (c) 1999, 2000 Greg Haerr <greg@censoft.com> * Portions Copyright (c) 1991 David I. Bell * * Permission is granted to use, distribute, or modify this source, * provided that this copyright notice remains intact. * * This program is free software; you may 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 <unistd.h>#include <errno.h>#include <fcntl.h>#include <math.h>#include <sys/ioctl.h>#if !defined(TPHELIO) && !defined(YOPY)#include <linux/tpanel.h>#endif#include "device.h"#include "mou_tp.h"#define EMBEDDEDPLANET	0	/* =1 for embeddedplanet ppc framebuffer*/#if EMBEDDEDPLANET#define DATACHANGELIMIT	50#else#define DATACHANGELIMIT	100#endif/* * Enable absolute coordinate transformation. * Normally this should be left at 1. * To disable transformation, set it to 0 before calling MwMain(). * This is done by the pointer calibration utility since it's used * to produce the pointer calibration data file. */int enable_pointing_coordinate_transform = 1;static TRANSFORMATION_COEFFICIENTS tc;/* file descriptor for touch panel */static int pd_fd;int GetPointerCalibrationData(void){	/*	 * Read the calibration data from the calibration file.	 * Calibration file format is seven coefficients separated by spaces.	 */	/* Get pointer calibration data from this file */	const char cal_filename[] = "/etc/pointercal";	int items;	FILE* f = fopen(cal_filename, "r");	if ( f == NULL )	{		EPRINTF("Error %d opening pointer calibration file %s.\n",			errno, cal_filename);		return -1;	}	items = fscanf(f, "%d %d %d %d %d %d %d",		&tc.a, &tc.b, &tc.c, &tc.d, &tc.e, &tc.f, &tc.s);	if ( items != 7 )	{		EPRINTF("Improperly formatted pointer calibration file %s.\n",			cal_filename);		return -1;	}#if TEST		EPRINTF("a=%d b=%d c=%d d=%d e=%d f=%d s=%d\n",			tc.a, tc.b, tc.c, tc.d, tc.e, tc.f, tc.s);#endif	return 0;}inline MWPOINT DeviceToScreen(MWPOINT p){	/*	 * Transform device coordinates to screen coordinates.	 * Take a point p in device coordinates and return the corresponding	 * point in screen coodinates.	 * This can scale, translate, rotate and/or skew, based on the	 * coefficients calculated above based on the list of screen	 * vs. device coordinates.	 */	static MWPOINT prev;	/* set slop at 3/4 pixel */	const short slop = TRANSFORMATION_UNITS_PER_PIXEL * 3 / 4;	MWPOINT 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;}#ifndef	YOPYstatic int PD_Open(MOUSEDEVICE *pmd){ 	/*	 * open up the touch-panel device.	 * Return the fd if successful, or negative if unsuccessful.	 */#ifndef TPHELIO	struct scanparam s;	int settle_upper_limit;	int result;#endif	pd_fd = open("/dev/tpanel", O_NONBLOCK);	if (pd_fd < 0) {		EPRINTF("Error %d opening touch panel\n", errno);		return -1;	}#ifndef TPHELIO	/* set interval to 5000us (200Hz) */	s.interval = 5000;	/*	 * Upper limit on settle time is approximately (scan_interval / 5) - 60	 * (5 conversions and some fixed overhead)	 * The opmtimal value is the lowest that doesn't cause significant	 * distortion.	 * 50% of upper limit works well on my Clio.  25% gets into distortion.	 */	settle_upper_limit = (s.interval / 5) - 60;	s.settletime = settle_upper_limit * 50 / 100;	result = ioctl(pd_fd, TPSETSCANPARM, &s);	if ( result < 0 )		EPRINTF("Error %d, result %d setting scan parameters.\n",			result, errno);#endif	if (enable_pointing_coordinate_transform)	{ 		if (GetPointerCalibrationData() < 0)		{			close(pd_fd);			return -1;		}	}	return pd_fd;}#else	/* ifndef YOPY */static TRANSFORMATION_COEFFICIENTS default_tc = {	68339, 328, -3042464, -508, 91638, -4339545, 65536};static int PD_Open(MOUSEDEVICE *pmd){ 	/*	 * open up the touch-panel device.	 * Return the fd if successful, or negative if unsuccessful.	 */	pd_fd = open("/dev/yopy-ts", O_NONBLOCK);	if (pd_fd < 0) {		EPRINTF("Error %d opening touch panel\n", errno);		return -1;	}	if (enable_pointing_coordinate_transform)	{ 		if (GetPointerCalibrationData() < 0)		{			//close(pd_fd);			//return -1;			memcpy( &tc, &default_tc, sizeof(TRANSFORMATION_COEFFICIENTS) );		}	}#if 0		EPRINTF("a=%d b=%d c=%d d=%d e=%d f=%d s=%d\n",			tc.a, tc.b, tc.c, tc.d, tc.e, tc.f, tc.s);#endif	return pd_fd;}#endifstatic void PD_Close(void){ 	/* Close the touch panel device. */	if (pd_fd > 0)		close(pd_fd);	pd_fd = 0;}static int PD_GetButtonInfo(void){ 	/* get "mouse" buttons supported */	return MWBUTTON_L;}static void PD_GetDefaultAccel(int *pscale,int *pthresh){	/*	 * Get default mouse acceleration settings	 * This doesn't make sense for a touch panel.	 * Just return something inconspicuous for now.	 */	*pscale = 3;	*pthresh = 5;}#ifndef	YOPYstatic int PD_Read(MWCOORD *px, MWCOORD *py, MWCOORD *pz, int *pb){	/*	 * Read the tpanel state and position.         * Returns the position data in x, y, and button data in b.	 * Returns -1 on error.	 * Returns 0 if no new data is available.	 * Returns 1 if position data is relative (i.e. mice).	 * 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.	 *	 * Unlike a mouse, this driver returns absolute postions, not deltas.	 */	/* If z is below this value, ignore the data. */	/* const int low_z_limit = 900; EVEREX*/#ifndef TPHELIO	const int low_z_limit = 815;#endif	/*	 * 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.	 */#ifndef TPHELIO	const int data_change_limit = DATACHANGELIMIT;#endif	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).	 * Lower iir_width means less pointer lag, higher iir_width means	 * steadier pointer.	 */	const int iir_shift_bits = 3;	const int iir_sample_depth = (1 << iir_shift_bits);	static int iir_accum_x = 0;	static int iir_accum_y = 0;	static int iir_accum_z = 0;	static int iir_count = 0;	int data_x, data_y, data_z;	/* read a data point */#if TPHELIO	short data[3];#else	short data[6];#endif	int bytes_read;	bytes_read = read(pd_fd, data, sizeof(data));	if (bytes_read != sizeof(data)) {		if (errno == EINTR || errno == EAGAIN) {			return 0;		}		return -1;	}#ifndef TPHELIO	/* did we lose any data? */	if ( (data[0] & 0x2000) )		EPRINTF("Lost touch panel data\n");	/* do we only have contact state data (no position data)? */	if ( (data[0] & 0x8000) == 0 )	{		/* is it a pen-release? */		if ( (data[0] & 0x4000) == 0 )		{			/* reset the limiter */			have_last_data = 0;			/* reset the filter */			iir_count = 0;			iir_accum_x = 0;			iir_accum_y = 0;			iir_accum_z = 0;			/* return the pen (button) state only, */			/* indicating that the pen is up (no buttons are down)*/			*pb = 0;			return 3;		}		/* ignore pen-down since we don't know where it is */		return 0;	}#endif	/* we have position data */#if TPHELIO        data_x = data[1];        data_y = data[2];	data_z = data[0] ? 2000 : 0;#else	/*	 * Combine the complementary panel readings into one value (except z)	 * This effectively doubles the sampling freqency, reducing noise	 * by approx 3db.	 * Again, please don't quote the 3db figure.  I think it also	 * cancels out changes in the overall resistance of the panel	 * such as may be caused by changes in panel temperature.	 */	data_x = data[2] - data[1];	data_y = data[4] - data[3];	data_z = data[5];	/* isn't z big enough for valid position data? */	if ( data_z <= low_z_limit ) {		return 0;	}	/* has the position changed more than we will allow? */	if ( have_last_data )		if ( (abs(data_x - last_data_x) > data_change_limit)			|| ( abs(data_y - last_data_y) > data_change_limit ) ) {			return 0;		}#endif	/* save last position */	last_data_x = data_x;	last_data_y = data_y;	have_last_data = 1;	/* is filter ready? */	if ( iir_count == iir_sample_depth )	{#if TPHELIO                if (enable_pointing_coordinate_transform) {			MWPOINT transformed = {data_x, data_y};			transformed = DeviceToScreen(transformed);			*px = transformed.x >> 2;			*py = transformed.y >> 2;		} else {			*px = data_x;			*py = data_y;		}		*pb = data[0] ? MWBUTTON_L : 0;#else		/* make room for new sample */		iir_accum_x -= iir_accum_x >> iir_shift_bits;		iir_accum_y -= iir_accum_y >> iir_shift_bits;		iir_accum_z -= iir_accum_z >> iir_shift_bits;		/* feed new sample to filter */		iir_accum_x += data_x;		iir_accum_y += data_y;		iir_accum_z += data_z;		/* transformation enabled? */		if (enable_pointing_coordinate_transform)		{			/* transform x,y to screen coords */			MWPOINT transformed = {iir_accum_x, iir_accum_y};			transformed = DeviceToScreen(transformed);			/*			 * HACK: move this from quarter pixels to whole			 * pixels for now at least until I decide on the			 * right interface to get the quarter-pixel data			 * up to the next layer.			 */			*px = transformed.x >> 2;			*py = transformed.y >> 2;		}		else		{			/* return untransformed coords (for calibration) */			*px = iir_accum_x;			*py = iir_accum_y;		}		*pb = MWBUTTON_L;#endif		/* return filtered pressure */		*pz = iir_accum_z;#ifdef TEST		EPRINTF("In: %hd, %hd, %hd  Filtered: %d %d %d  Out: %d, %d, %d\n",			data_x, data_y, data_z, iir_accum_x, iir_accum_y,			iir_accum_z, *px, *py, *pz);#endif		return 2;	}	/* prime the filter */	iir_accum_x += data_x;	iir_accum_y += data_y;	iir_accum_z += data_z;	iir_count += 1;	return 0;}#else	/* ifdef YOPY */static int PD_Read(MWCOORD *px, MWCOORD *py, MWCOORD *pz, int *pb){	/*	 * Read the tpanel state and position.         * Returns the position data in x, y, and button data in b.	 * Returns -1 on error.	 * Returns 0 if no new data is available.	 * Returns 1 if position data is relative (i.e. mice).	 * 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.	 *	 * Unlike a mouse, this driver returns absolute postions, not deltas.	 */	/* If z is below this value, ignore the data. */	/* const int low_z_limit = 900; EVEREX*/	/*	 * 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.	 */	int data_x, data_y;	/* read a data point */	int bytes_read;	int	mou_data;	bytes_read = read(pd_fd, &mou_data, sizeof(mou_data));	if (bytes_read != sizeof(mou_data)) {		if (errno == EINTR || errno == EAGAIN) {			return 0;		}		return -1;	}	data_x = ((MWCOORD)(mou_data & 0x3ff));	data_y = (MWCOORD)(( mou_data>>10 ) & 0x3ff );	/* transformation enabled? */	if (enable_pointing_coordinate_transform)	{		/* transform x,y to screen coords */		MWPOINT transformed = {data_x, data_y};		transformed = DeviceToScreen(transformed);		/*		 * HACK: move this from quarter pixels to whole		 * pixels for now at least until I decide on the		 * right interface to get the quarter-pixel data		 * up to the next layer.		 */		*px = transformed.x >> 2;		*py = transformed.y >> 2;	}	else	{		/* return untransformed coords (for calibration) */		*px = data_x;		*py = data_y;	}	*pz = 0;	*pb = ( mou_data & (1<<31) )? MWBUTTON_L: 0;	if ( ! *pb )		return 3;	else		return 2;}#endifMOUSEDEVICE mousedev = {	PD_Open,	PD_Close,	PD_GetButtonInfo,	PD_GetDefaultAccel,	PD_Read,	NULL};#ifdef TESTint main(){	MWCOORD x, y, z;	int	b;	int result;	enable_pointing_coordinate_transform = 1;	DPRINTF("Opening touch panel...\n");	if((result=PD_Open(0)) < 0)		DPRINTF("Error %d, result %d opening touch-panel\n", errno, result);	DPRINTF("Reading touch panel...\n");	while(1) {		result = PD_Read(&x, &y, &z, &b);		if( result > 0) {			/* DPRINTF("%d,%d,%d,%d,%d\n", result, x, y, z, b); */		}	}}#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -