/*
|
/*
|
* Microwindows touch screen driver for NEC Harrier Demo Board.
|
* Microwindows touch screen driver for NEC Harrier Demo Board.
|
*
|
*
|
* Copyright (c) 2000 Century Software Embedded Technologies
|
* Copyright (c) 2000 Century Software Embedded Technologies
|
*
|
*
|
* Requires /dev/tpanel kernel device driver for the VRC4173 chip
|
* Requires /dev/tpanel kernel device driver for the VRC4173 chip
|
*/
|
*/
|
#include <stdio.h>
|
#include <stdio.h>
|
#include <stdlib.h>
|
#include <stdlib.h>
|
#include <unistd.h>
|
#include <unistd.h>
|
#include <errno.h>
|
#include <errno.h>
|
#include <fcntl.h>
|
#include <fcntl.h>
|
#include <math.h>
|
#include <math.h>
|
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
#include <linux/tpanel.h>
|
#include <linux/tpanel.h>
|
#include "device.h"
|
#include "device.h"
|
#include "mou_tp.h"
|
#include "mou_tp.h"
|
|
|
/* Very basic handling for the touch panel */
|
/* Very basic handling for the touch panel */
|
/* Mostly borrowed from mou_ipaq.c which I believe was mostly */
|
/* Mostly borrowed from mou_ipaq.c which I believe was mostly */
|
/* borrowed from mou_tp.c */
|
/* borrowed from mou_tp.c */
|
|
|
/* Define this if you want to use the filter instead of the average method */
|
/* Define this if you want to use the filter instead of the average method */
|
/* #define USE_FILTER */
|
/* #define USE_FILTER */
|
|
|
/* Defines used throughout */
|
/* Defines used throughout */
|
#define TP_STATUS_HARDDATALOST 0x1000
|
#define TP_STATUS_HARDDATALOST 0x1000
|
#define TP_STATUS_SOFTDATALOST 0x2000
|
#define TP_STATUS_SOFTDATALOST 0x2000
|
#define TP_STATUS_PENCONTACT 0x4000
|
#define TP_STATUS_PENCONTACT 0x4000
|
#define TP_STATUS_DATAVALID 0x8000
|
#define TP_STATUS_DATAVALID 0x8000
|
|
|
/* Fix these when we know the right size */
|
/* Fix these when we know the right size */
|
|
|
#define TP_MIN_X_SIZE 291
|
#define TP_MIN_X_SIZE 291
|
#define TP_MIN_Y_SIZE 355
|
#define TP_MIN_Y_SIZE 355
|
|
|
#define TP_MAX_X_SIZE 3839
|
#define TP_MAX_X_SIZE 3839
|
#define TP_MAX_Y_SIZE 3711
|
#define TP_MAX_Y_SIZE 3711
|
|
|
#define DATA_STATUS 0
|
#define DATA_STATUS 0
|
#define DATA_YPLUS 1
|
#define DATA_YPLUS 1
|
#define DATA_YMINUS 2
|
#define DATA_YMINUS 2
|
#define DATA_XPLUS 3
|
#define DATA_XPLUS 3
|
#define DATA_XMINUS 4
|
#define DATA_XMINUS 4
|
#define DATA_Z 5
|
#define DATA_Z 5
|
|
|
|
|
#ifdef USE_FILTER
|
#ifdef USE_FILTER
|
#define MOU_SAMPLE_RATE 1
|
#define MOU_SAMPLE_RATE 1
|
#else
|
#else
|
#define MOU_SAMPLE_RATE 10
|
#define MOU_SAMPLE_RATE 10
|
#endif
|
#endif
|
|
|
#define MOU_READ_INTERVAL 5000
|
#define MOU_READ_INTERVAL 5000
|
|
|
/* Data format (from kernel driver): */
|
/* Data format (from kernel driver): */
|
/* unsigned short status */
|
/* unsigned short status */
|
/* unsigned short x+ (raw) */
|
/* unsigned short x+ (raw) */
|
/* unsigned short x- (raw) */
|
/* unsigned short x- (raw) */
|
/* unsigned short y+ (raw) */
|
/* unsigned short y+ (raw) */
|
/* unsigned short y- (raw) */
|
/* unsigned short y- (raw) */
|
/* unsigned short z (presssure, raw) */
|
/* unsigned short z (presssure, raw) */
|
|
|
static int pd_fd = -1;
|
static int pd_fd = -1;
|
int enable_pointing_coordinate_transform = 1;
|
int enable_pointing_coordinate_transform = 1;
|
|
|
static TRANSFORMATION_COEFFICIENTS tc;
|
static TRANSFORMATION_COEFFICIENTS tc;
|
|
|
#ifndef TEST
|
#ifndef TEST
|
extern SCREENDEVICE scrdev;
|
extern SCREENDEVICE scrdev;
|
#endif
|
#endif
|
|
|
#ifdef TEST
|
#ifdef TEST
|
#undef EPRINTF
|
#undef EPRINTF
|
#undef DPRINTF
|
#undef DPRINTF
|
|
|
#define EPRINTF printf
|
#define EPRINTF printf
|
#define DPRINTF printf
|
#define DPRINTF printf
|
#endif
|
#endif
|
|
|
int GetPointerCalibrationData(void)
|
int GetPointerCalibrationData(void)
|
{
|
{
|
/*
|
/*
|
* Read the calibration data from the calibration file.
|
* Read the calibration data from the calibration file.
|
* Calibration file format is seven coefficients separated by spaces.
|
* Calibration file format is seven coefficients separated by spaces.
|
*/
|
*/
|
|
|
/* Get pointer calibration data from this file */
|
/* Get pointer calibration data from this file */
|
const char cal_filename[] = "/etc/pointercal";
|
const char cal_filename[] = "/etc/pointercal";
|
|
|
int items;
|
int items;
|
|
|
FILE* f = fopen(cal_filename, "r");
|
FILE* f = fopen(cal_filename, "r");
|
if ( f == NULL )
|
if ( f == NULL )
|
{
|
{
|
EPRINTF("Error %d opening pointer calibration file %s.\n",
|
EPRINTF("Error %d opening pointer calibration file %s.\n",
|
errno, cal_filename);
|
errno, cal_filename);
|
EPRINTF("Please type \"/usr/bin/tpcal > %s\" to calibrate\n",
|
EPRINTF("Please type \"/usr/bin/tpcal > %s\" to calibrate\n",
|
cal_filename);
|
cal_filename);
|
return -1;
|
return -1;
|
}
|
}
|
|
|
items = fscanf(f, "%d %d %d %d %d %d %d",
|
items = fscanf(f, "%d %d %d %d %d %d %d",
|
&tc.a, &tc.b, &tc.c, &tc.d, &tc.e, &tc.f, &tc.s);
|
&tc.a, &tc.b, &tc.c, &tc.d, &tc.e, &tc.f, &tc.s);
|
if ( items != 7 )
|
if ( items != 7 )
|
{
|
{
|
EPRINTF("Improperly formatted pointer calibration file %s.\n",
|
EPRINTF("Improperly formatted pointer calibration file %s.\n",
|
cal_filename);
|
cal_filename);
|
return -1;
|
return -1;
|
}
|
}
|
|
|
#if TEST
|
#if TEST
|
EPRINTF("a=%d b=%d c=%d d=%d e=%d f=%d s=%d\n",
|
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);
|
tc.a, tc.b, tc.c, tc.d, tc.e, tc.f, tc.s);
|
#endif
|
#endif
|
|
|
return 0;
|
return 0;
|
}
|
}
|
|
|
inline MWPOINT DeviceToScreen(MWPOINT p)
|
inline MWPOINT DeviceToScreen(MWPOINT p)
|
{
|
{
|
/*
|
/*
|
* Transform device coordinates to screen coordinates.
|
* Transform device coordinates to screen coordinates.
|
* Take a point p in device coordinates and return the corresponding
|
* Take a point p in device coordinates and return the corresponding
|
* point in screen coodinates.
|
* point in screen coodinates.
|
* This can scale, translate, rotate and/or skew, based on the
|
* This can scale, translate, rotate and/or skew, based on the
|
* coefficients calculated above based on the list of screen
|
* coefficients calculated above based on the list of screen
|
* vs. device coordinates.
|
* vs. device coordinates.
|
*/
|
*/
|
|
|
static MWPOINT prev;
|
static MWPOINT prev;
|
/* set slop at 3/4 pixel */
|
/* set slop at 3/4 pixel */
|
const short slop = TRANSFORMATION_UNITS_PER_PIXEL * 3 / 4;
|
const short slop = TRANSFORMATION_UNITS_PER_PIXEL * 3 / 4;
|
MWPOINT new, out;
|
MWPOINT new, out;
|
|
|
/* transform */
|
/* transform */
|
new.x = (tc.a * p.x + tc.b * p.y + tc.c) / tc.s;
|
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;
|
new.y = (tc.d * p.x + tc.e * p.y + tc.f) / tc.s;
|
|
|
/* hysteresis (thanks to John Siau) */
|
/* hysteresis (thanks to John Siau) */
|
if ( abs(new.x - prev.x) >= slop )
|
if ( abs(new.x - prev.x) >= slop )
|
out.x = (new.x | 0x3) ^ 0x3;
|
out.x = (new.x | 0x3) ^ 0x3;
|
else
|
else
|
out.x = prev.x;
|
out.x = prev.x;
|
|
|
if ( abs(new.y - prev.y) >= slop )
|
if ( abs(new.y - prev.y) >= slop )
|
out.y = (new.y | 0x3) ^ 0x3;
|
out.y = (new.y | 0x3) ^ 0x3;
|
else
|
else
|
out.y = prev.y;
|
out.y = prev.y;
|
|
|
prev = out;
|
prev = out;
|
|
|
return out;
|
return out;
|
}
|
}
|
|
|
static int PD_Open(MOUSEDEVICE *pmd)
|
static int PD_Open(MOUSEDEVICE *pmd)
|
{
|
{
|
struct scanparam s;
|
struct scanparam s;
|
int settle_upper_limit;
|
int settle_upper_limit;
|
int result;
|
int result;
|
|
|
/* Open the device */
|
/* Open the device */
|
pd_fd = open("/dev/tpanel", O_NONBLOCK);
|
pd_fd = open("/dev/tpanel", O_NONBLOCK);
|
|
|
if (pd_fd < 0)
|
if (pd_fd < 0)
|
{
|
{
|
EPRINTF("Error %d opening touch panel\n", errno);
|
EPRINTF("Error %d opening touch panel\n", errno);
|
return -1;
|
return -1;
|
}
|
}
|
|
|
s.interval = MOU_READ_INTERVAL;
|
s.interval = MOU_READ_INTERVAL;
|
|
|
/*
|
/*
|
* Upper limit on settle time is approximately (scan_interval / 5) - 60
|
* Upper limit on settle time is approximately (scan_interval / 5) - 60
|
* (5 conversions and some fixed overhead)
|
* (5 conversions and some fixed overhead)
|
* The opmtimal value is the lowest that doesn't cause significant
|
* The opmtimal value is the lowest that doesn't cause significant
|
* distortion.
|
* distortion.
|
*/
|
*/
|
|
|
settle_upper_limit = (s.interval / 5) - 60;
|
settle_upper_limit = (s.interval / 5) - 60;
|
s.settletime = settle_upper_limit * 50 / 100;
|
s.settletime = settle_upper_limit * 50 / 100;
|
result = ioctl(pd_fd, TPSETSCANPARM, &s);
|
result = ioctl(pd_fd, TPSETSCANPARM, &s);
|
|
|
if ( result < 0 )
|
if ( result < 0 )
|
EPRINTF("Error %d, result %d setting scan parameters.\n",
|
EPRINTF("Error %d, result %d setting scan parameters.\n",
|
result, errno);
|
result, errno);
|
|
|
if (enable_pointing_coordinate_transform)
|
if (enable_pointing_coordinate_transform)
|
{
|
{
|
if (GetPointerCalibrationData() < 0)
|
if (GetPointerCalibrationData() < 0)
|
{
|
{
|
close(pd_fd);
|
close(pd_fd);
|
return -1;
|
return -1;
|
}
|
}
|
}
|
}
|
|
|
/* We choose not to hide the cursor for now, others may want to */
|
/* We choose not to hide the cursor for now, others may want to */
|
|
|
#ifdef NOTUSED
|
#ifdef NOTUSED
|
#ifndef TEST
|
#ifndef TEST
|
/* Hide the cursor */
|
/* Hide the cursor */
|
GdHideCursor(&scrdev);
|
GdHideCursor(&scrdev);
|
#endif
|
#endif
|
#endif
|
#endif
|
|
|
return(pd_fd);
|
return(pd_fd);
|
}
|
}
|
|
|
static void PD_Close(void)
|
static void PD_Close(void)
|
{
|
{
|
/* Close the touch panel device. */
|
/* Close the touch panel device. */
|
if (pd_fd >= 0)
|
if (pd_fd >= 0)
|
close(pd_fd);
|
close(pd_fd);
|
pd_fd = -1;
|
pd_fd = -1;
|
}
|
}
|
|
|
static int PD_GetButtonInfo(void)
|
static int PD_GetButtonInfo(void)
|
{
|
{
|
/* get "mouse" buttons supported */
|
/* get "mouse" buttons supported */
|
return MWBUTTON_L;
|
return MWBUTTON_L;
|
}
|
}
|
|
|
static void PD_GetDefaultAccel(int *pscale,int *pthresh)
|
static void PD_GetDefaultAccel(int *pscale,int *pthresh)
|
{
|
{
|
/*
|
/*
|
* Get default mouse acceleration settings
|
* Get default mouse acceleration settings
|
* This doesn't make sense for a touch panel.
|
* This doesn't make sense for a touch panel.
|
* Just return something inconspicuous for now.
|
* Just return something inconspicuous for now.
|
*/
|
*/
|
*pscale = 3;
|
*pscale = 3;
|
*pthresh = 5;
|
*pthresh = 5;
|
}
|
}
|
|
|
#define MAX_DEVICE_READS 10
|
#define MAX_DEVICE_READS 10
|
static int read_tp(unsigned short *x, unsigned short *y,
|
static int read_tp(unsigned short *x, unsigned short *y,
|
unsigned short *z, int *b, unsigned short *status, unsigned char block)
|
unsigned short *z, int *b, unsigned short *status, unsigned char block)
|
{
|
{
|
unsigned char read_count = 0;
|
unsigned char read_count = 0;
|
unsigned short tempx, tempy;
|
unsigned short tempx, tempy;
|
int bytes_read;
|
int bytes_read;
|
unsigned short data[6];
|
unsigned short data[6];
|
|
|
/* Uh, oh -- The driver is slow and fat, so we get lots of EAGAINS between */
|
/* Uh, oh -- The driver is slow and fat, so we get lots of EAGAINS between */
|
/* reads. Thats never good. So we loop here for some count before we bail */
|
/* reads. Thats never good. So we loop here for some count before we bail */
|
|
|
while(read_count < MAX_DEVICE_READS)
|
while(read_count < MAX_DEVICE_READS)
|
{
|
{
|
bytes_read = read(pd_fd, data, sizeof(data));
|
bytes_read = read(pd_fd, data, sizeof(data));
|
|
|
if (bytes_read != sizeof(data))
|
if (bytes_read != sizeof(data))
|
{
|
{
|
if (errno != EAGAIN)
|
if (errno != EAGAIN)
|
{
|
{
|
EPRINTF("Error reading touch panel. errno = %d\n", errno);
|
EPRINTF("Error reading touch panel. errno = %d\n", errno);
|
return(errno);
|
return(errno);
|
}
|
}
|
|
|
if (block)
|
if (block)
|
{
|
{
|
if (read_count++ == MAX_DEVICE_READS)
|
if (read_count++ == MAX_DEVICE_READS)
|
return(EAGAIN);
|
return(EAGAIN);
|
else
|
else
|
usleep(MOU_READ_INTERVAL / MAX_DEVICE_READS);
|
usleep(MOU_READ_INTERVAL / MAX_DEVICE_READS);
|
}
|
}
|
else
|
else
|
return(EAGAIN);
|
return(EAGAIN);
|
}
|
}
|
else
|
else
|
break;
|
break;
|
}
|
}
|
|
|
tempx = data[DATA_XPLUS];
|
tempx = data[DATA_XPLUS];
|
tempy = data[DATA_YPLUS];
|
tempy = data[DATA_YPLUS];
|
|
|
/* Sanity check */
|
/* Sanity check */
|
/* This is based on measured values. Occassionally, we get a bad read from the board */
|
/* This is based on measured values. Occassionally, we get a bad read from the board */
|
/* This is to ensure that really wacked out reads don't get through. */
|
/* This is to ensure that really wacked out reads don't get through. */
|
|
|
if ((data[DATA_STATUS] & TP_STATUS_DATAVALID) == TP_STATUS_DATAVALID)
|
if ((data[DATA_STATUS] & TP_STATUS_DATAVALID) == TP_STATUS_DATAVALID)
|
{
|
{
|
if (enable_pointing_coordinate_transform)
|
if (enable_pointing_coordinate_transform)
|
{
|
{
|
if (tempx < TP_MIN_X_SIZE || tempx > TP_MAX_X_SIZE)
|
if (tempx < TP_MIN_X_SIZE || tempx > TP_MAX_X_SIZE)
|
{
|
{
|
#ifdef TEST
|
#ifdef TEST
|
EPRINTF("Got an out of range X value. X=%d,Y=%d,B=%d\n",
|
EPRINTF("Got an out of range X value. X=%d,Y=%d,B=%d\n",
|
tempx, tempy,
|
tempx, tempy,
|
((data[DATA_STATUS] & TP_STATUS_PENCONTACT) ? MWBUTTON_L : 0));
|
((data[DATA_STATUS] & TP_STATUS_PENCONTACT) ? MWBUTTON_L : 0));
|
#endif
|
#endif
|
return(EAGAIN);
|
return(EAGAIN);
|
}
|
}
|
|
|
if (tempy < TP_MIN_Y_SIZE || tempy > TP_MAX_Y_SIZE)
|
if (tempy < TP_MIN_Y_SIZE || tempy > TP_MAX_Y_SIZE)
|
{
|
{
|
#ifdef TEST
|
#ifdef TEST
|
EPRINTF("Got an out of range Y value. X=%d,Y=%d,B=%d\n",
|
EPRINTF("Got an out of range Y value. X=%d,Y=%d,B=%d\n",
|
tempx, tempy,
|
tempx, tempy,
|
((data[DATA_STATUS] & TP_STATUS_PENCONTACT) ? MWBUTTON_L : 0));
|
((data[DATA_STATUS] & TP_STATUS_PENCONTACT) ? MWBUTTON_L : 0));
|
#endif
|
#endif
|
return(EAGAIN);
|
return(EAGAIN);
|
}
|
}
|
}
|
}
|
|
|
*x = tempx;
|
*x = tempx;
|
*y = tempy;
|
*y = tempy;
|
*z = data[DATA_Z];
|
*z = data[DATA_Z];
|
}
|
}
|
else
|
else
|
{
|
{
|
*x = 0;
|
*x = 0;
|
*y = 0;
|
*y = 0;
|
*z = 0;
|
*z = 0;
|
}
|
}
|
|
|
*b = ((data[DATA_STATUS] & TP_STATUS_PENCONTACT) ? MWBUTTON_L : 0);
|
*b = ((data[DATA_STATUS] & TP_STATUS_PENCONTACT) ? MWBUTTON_L : 0);
|
*status = data[DATA_STATUS];
|
*status = data[DATA_STATUS];
|
|
|
return(0);
|
return(0);
|
}
|
}
|
|
|
|
|
static int PD_Read(MWCOORD *px, MWCOORD *py, MWCOORD *pz, int *pb)
|
static int PD_Read(MWCOORD *px, MWCOORD *py, MWCOORD *pz, int *pb)
|
{
|
{
|
#ifdef USE_FILTER
|
#ifdef USE_FILTER
|
/* Filter stuff borrowed from mou_tp.c */
|
/* Filter stuff borrowed from mou_tp.c */
|
const int iir_shift_bits = 3;
|
const int iir_shift_bits = 3;
|
const int iir_sample_depth = (1 << iir_shift_bits);
|
const int iir_sample_depth = (1 << iir_shift_bits);
|
|
|
static int iir_accum_x = 0;
|
static int iir_accum_x = 0;
|
static int iir_accum_y = 0;
|
static int iir_accum_y = 0;
|
static int iir_accum_z = 0;
|
static int iir_accum_z = 0;
|
static int iir_count = 0;
|
static int iir_count = 0;
|
#else
|
#else
|
double cx, cy, cz;
|
double cx, cy, cz;
|
#endif
|
#endif
|
|
|
/* Other local variables */
|
/* Other local variables */
|
MWPOINT transformed;
|
MWPOINT transformed;
|
int err = 0;
|
int err = 0;
|
unsigned short samples = 0;
|
unsigned short samples = 0;
|
unsigned short xpos = 0;
|
unsigned short xpos = 0;
|
unsigned short ypos = 0;
|
unsigned short ypos = 0;
|
unsigned short zpos = 0;
|
unsigned short zpos = 0;
|
unsigned short status = 0;
|
unsigned short status = 0;
|
|
|
*pb = 0;
|
*pb = 0;
|
*px = 0;
|
*px = 0;
|
*py = 0;
|
*py = 0;
|
*pz = 0;
|
*pz = 0;
|
|
|
#ifndef USE_FILTER
|
#ifndef USE_FILTER
|
cx = 0;
|
cx = 0;
|
cy = 0;
|
cy = 0;
|
cz = 0;
|
cz = 0;
|
#endif
|
#endif
|
|
|
if ((err = read_tp(&xpos, &ypos, &zpos, pb, &status, 0)))
|
if ((err = read_tp(&xpos, &ypos, &zpos, pb, &status, 0)))
|
{
|
{
|
if (err == EAGAIN)
|
if (err == EAGAIN)
|
return(0);
|
return(0);
|
else
|
else
|
return(1);
|
return(1);
|
}
|
}
|
|
|
/* Check the status of the button */
|
/* Check the status of the button */
|
|
|
if ( (status & TP_STATUS_DATAVALID) != TP_STATUS_DATAVALID)
|
if ( (status & TP_STATUS_DATAVALID) != TP_STATUS_DATAVALID)
|
{
|
{
|
if (*pb)
|
if (*pb)
|
return(0);
|
return(0);
|
else
|
else
|
goto button_up;
|
goto button_up;
|
}
|
}
|
|
|
while((status & TP_STATUS_DATAVALID) == TP_STATUS_DATAVALID)
|
while((status & TP_STATUS_DATAVALID) == TP_STATUS_DATAVALID)
|
{
|
{
|
int tempb = 0;
|
int tempb = 0;
|
|
|
err = read_tp(&xpos, &ypos, &zpos, &tempb, &status, 1);
|
err = read_tp(&xpos, &ypos, &zpos, &tempb, &status, 1);
|
|
|
if (err == EAGAIN)
|
if (err == EAGAIN)
|
{
|
{
|
if (!samples)
|
if (!samples)
|
continue; /* We need at least one reading! */
|
continue; /* We need at least one reading! */
|
else
|
else
|
break; /* The device continues to not respond. Bail */
|
break; /* The device continues to not respond. Bail */
|
}
|
}
|
else if (err)
|
else if (err)
|
return(-1);
|
return(-1);
|
|
|
/* If the data is invalid and the button is down, then bail */
|
/* If the data is invalid and the button is down, then bail */
|
/* Otherwise, record the button data */
|
/* Otherwise, record the button data */
|
|
|
if ( (status & TP_STATUS_DATAVALID) != TP_STATUS_DATAVALID)
|
if ( (status & TP_STATUS_DATAVALID) != TP_STATUS_DATAVALID)
|
{
|
{
|
if (tempb)
|
if (tempb)
|
return(0); /* Button is down, but data is invalid */
|
return(0); /* Button is down, but data is invalid */
|
else
|
else
|
{
|
{
|
*pb = tempb; /* Record button up */
|
*pb = tempb; /* Record button up */
|
goto button_up;
|
goto button_up;
|
}
|
}
|
}
|
}
|
|
|
#ifdef USE_FILTER
|
#ifdef USE_FILTER
|
|
|
/* Run the newly aquired data through a filter */
|
/* Run the newly aquired data through a filter */
|
/* is filter ready? */
|
/* is filter ready? */
|
if ( iir_count == iir_sample_depth )
|
if ( iir_count == iir_sample_depth )
|
{
|
{
|
/* make room for new sample */
|
/* make room for new sample */
|
iir_accum_x -= iir_accum_x >> iir_shift_bits;
|
iir_accum_x -= iir_accum_x >> iir_shift_bits;
|
iir_accum_y -= iir_accum_y >> iir_shift_bits;
|
iir_accum_y -= iir_accum_y >> iir_shift_bits;
|
iir_accum_z -= iir_accum_z >> iir_shift_bits;
|
iir_accum_z -= iir_accum_z >> iir_shift_bits;
|
|
|
/* feed new sample to filter */
|
/* feed new sample to filter */
|
iir_accum_x += xpos;
|
iir_accum_x += xpos;
|
iir_accum_y += ypos;
|
iir_accum_y += ypos;
|
iir_accum_z += zpos;
|
iir_accum_z += zpos;
|
}
|
}
|
else
|
else
|
{
|
{
|
iir_accum_x += xpos;
|
iir_accum_x += xpos;
|
iir_accum_y += ypos;
|
iir_accum_y += ypos;
|
iir_accum_z += zpos;
|
iir_accum_z += zpos;
|
iir_count += 1;
|
iir_count += 1;
|
}
|
}
|
|
|
#else
|
#else
|
cx += xpos;
|
cx += xpos;
|
cy += ypos;
|
cy += ypos;
|
cz += zpos;
|
cz += zpos;
|
#endif
|
#endif
|
|
|
samples++;
|
samples++;
|
|
|
/* Enough samples?? */
|
/* Enough samples?? */
|
if (samples >= MOU_SAMPLE_RATE)
|
if (samples >= MOU_SAMPLE_RATE)
|
break;
|
break;
|
}
|
}
|
|
|
if (!samples)
|
if (!samples)
|
return(0);
|
return(0);
|
|
|
#ifdef USE_FILTER
|
#ifdef USE_FILTER
|
/* We're not done gathering samples yet */
|
/* We're not done gathering samples yet */
|
if (iir_count < iir_sample_depth)
|
if (iir_count < iir_sample_depth)
|
return(0);
|
return(0);
|
|
|
if (enable_pointing_coordinate_transform)
|
if (enable_pointing_coordinate_transform)
|
{
|
{
|
/* transform x,y to screen coords */
|
/* transform x,y to screen coords */
|
transformed.x = iir_accum_x;
|
transformed.x = iir_accum_x;
|
transformed.y = iir_accum_y;
|
transformed.y = iir_accum_y;
|
transformed = DeviceToScreen(transformed);
|
transformed = DeviceToScreen(transformed);
|
|
|
*px = transformed.x >> 2;
|
*px = transformed.x >> 2;
|
*py = transformed.y >> 2;
|
*py = transformed.y >> 2;
|
}
|
}
|
else
|
else
|
{
|
{
|
*px = (MWCOORD) abs(iir_accum_x);
|
*px = (MWCOORD) abs(iir_accum_x);
|
*py = (MWCOORD) abs(iir_accum_y);
|
*py = (MWCOORD) abs(iir_accum_y);
|
}
|
}
|
#else
|
#else
|
|
|
if (enable_pointing_coordinate_transform)
|
if (enable_pointing_coordinate_transform)
|
{
|
{
|
transformed.x = (cx / samples);
|
transformed.x = (cx / samples);
|
transformed.y = (cy / samples);
|
transformed.y = (cy / samples);
|
|
|
transformed = DeviceToScreen(transformed);
|
transformed = DeviceToScreen(transformed);
|
|
|
*px = (MWCOORD) transformed.x >> 2;
|
*px = (MWCOORD) transformed.x >> 2;
|
*py = (MWCOORD) transformed.y >> 2;
|
*py = (MWCOORD) transformed.y >> 2;
|
}
|
}
|
else
|
else
|
{
|
{
|
*px = (MWCOORD) abs(cx / samples);
|
*px = (MWCOORD) abs(cx / samples);
|
*py = (MWCOORD) abs(cy / samples);
|
*py = (MWCOORD) abs(cy / samples);
|
}
|
}
|
#endif
|
#endif
|
|
|
button_up:
|
button_up:
|
if (! *pb)
|
if (! *pb)
|
{
|
{
|
#ifdef USE_FILTER
|
#ifdef USE_FILTER
|
/* reset the filter */
|
/* reset the filter */
|
iir_count = 0;
|
iir_count = 0;
|
iir_accum_x = 0;
|
iir_accum_x = 0;
|
iir_accum_y = 0;
|
iir_accum_y = 0;
|
iir_accum_z = 0;
|
iir_accum_z = 0;
|
#endif
|
#endif
|
return(3);
|
return(3);
|
}
|
}
|
else
|
else
|
return(2); /* XYZ and button data */
|
return(2); /* XYZ and button data */
|
|
|
}
|
}
|
|
|
#ifndef TEST
|
#ifndef TEST
|
MOUSEDEVICE mousedev = {
|
MOUSEDEVICE mousedev = {
|
PD_Open,
|
PD_Open,
|
PD_Close,
|
PD_Close,
|
PD_GetButtonInfo,
|
PD_GetButtonInfo,
|
PD_GetDefaultAccel,
|
PD_GetDefaultAccel,
|
PD_Read,
|
PD_Read,
|
NULL
|
NULL
|
};
|
};
|
#endif
|
#endif
|
|
|
#ifdef TEST
|
#ifdef TEST
|
int main(int argc, char ** v)
|
int main(int argc, char ** v)
|
{
|
{
|
int x, y, z;
|
int x, y, z;
|
|
|
int b;
|
int b;
|
int result;
|
int result;
|
|
|
DPRINTF("Opening touch panel...\n");
|
DPRINTF("Opening touch panel...\n");
|
|
|
if((result=PD_Open(0)) < 0)
|
if((result=PD_Open(0)) < 0)
|
{
|
{
|
|
|
DPRINTF("Error %d, result %d opening touch-panel\n", errno, result);
|
DPRINTF("Error %d, result %d opening touch-panel\n", errno, result);
|
exit(0);
|
exit(0);
|
}
|
}
|
|
|
DPRINTF("Reading touch panel...\n");
|
DPRINTF("Reading touch panel...\n");
|
|
|
while(1)
|
while(1)
|
{
|
{
|
result = PD_Read(&x, &y, &z, &b);
|
result = PD_Read(&x, &y, &z, &b);
|
|
|
if( result > 0)
|
if( result > 0)
|
{
|
{
|
DPRINTF("(%d,%d,%d) b = %d\n",x, y, z, b);
|
DPRINTF("(%d,%d,%d) b = %d\n",x, y, z, b);
|
}
|
}
|
}
|
}
|
}
|
}
|
#endif
|
#endif
|
|
|
|
|