OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [tags/] [MW_0_8_9PRE7/] [mw/] [src/] [drivers/] [mou_harrier.c] - Blame information for rev 674

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 673 markom
/*
2
 * Microwindows touch screen driver for NEC Harrier Demo Board.
3
 *
4
 * Copyright (c) 2000 Century Software Embedded Technologies
5
 *
6
 * Requires /dev/tpanel kernel device driver for the VRC4173 chip
7
 */
8
#include <stdio.h>
9
#include <stdlib.h>
10
#include <unistd.h>
11
#include <errno.h>
12
#include <fcntl.h>
13
#include <math.h>
14
#include <sys/ioctl.h>
15
#include <linux/tpanel.h>
16
#include "device.h"
17
#include "mou_tp.h"
18
 
19
/* Very basic handling for the touch panel */
20
/* Mostly borrowed from mou_ipaq.c which I believe was mostly */
21
/* borrowed from mou_tp.c */
22
 
23
/* Define this if you want to use the filter instead of the average method */
24
/* #define USE_FILTER */
25
 
26
/* Defines used throughout */
27
#define TP_STATUS_HARDDATALOST 0x1000
28
#define TP_STATUS_SOFTDATALOST 0x2000
29
#define TP_STATUS_PENCONTACT   0x4000
30
#define TP_STATUS_DATAVALID    0x8000
31
 
32
/* Fix these when we know the right size */
33
 
34
#define TP_MIN_X_SIZE          291
35
#define TP_MIN_Y_SIZE          355
36
 
37
#define TP_MAX_X_SIZE          3839
38
#define TP_MAX_Y_SIZE          3711
39
 
40
#define DATA_STATUS  0
41
#define DATA_YPLUS   1
42
#define DATA_YMINUS  2
43
#define DATA_XPLUS   3
44
#define DATA_XMINUS  4
45
#define DATA_Z       5
46
 
47
 
48
#ifdef USE_FILTER
49
#define MOU_SAMPLE_RATE   1
50
#else
51
#define MOU_SAMPLE_RATE   10
52
#endif
53
 
54
#define MOU_READ_INTERVAL 5000
55
 
56
  /* Data format (from kernel driver): */
57
  /* unsigned short status */
58
  /* unsigned short x+ (raw) */
59
  /* unsigned short x- (raw) */
60
  /* unsigned short y+ (raw) */
61
  /* unsigned short y- (raw) */
62
  /* unsigned short z (presssure, raw) */
63
 
64
static int pd_fd = -1;
65
int enable_pointing_coordinate_transform = 1;
66
 
67
static TRANSFORMATION_COEFFICIENTS tc;
68
 
69
#ifndef TEST
70
extern SCREENDEVICE scrdev;
71
#endif
72
 
73
#ifdef TEST
74
#undef EPRINTF
75
#undef DPRINTF
76
 
77
#define EPRINTF printf
78
#define DPRINTF printf
79
#endif
80
 
81
int GetPointerCalibrationData(void)
82
{
83
        /*
84
         * Read the calibration data from the calibration file.
85
         * Calibration file format is seven coefficients separated by spaces.
86
         */
87
 
88
        /* Get pointer calibration data from this file */
89
        const char cal_filename[] = "/etc/pointercal";
90
 
91
        int items;
92
 
93
        FILE* f = fopen(cal_filename, "r");
94
        if ( f == NULL )
95
        {
96
                EPRINTF("Error %d opening pointer calibration file %s.\n",
97
                        errno, cal_filename);
98
                EPRINTF("Please type \"/usr/bin/tpcal > %s\" to calibrate\n",
99
                        cal_filename);
100
                return -1;
101
        }
102
 
103
        items = fscanf(f, "%d %d %d %d %d %d %d",
104
                &tc.a, &tc.b, &tc.c, &tc.d, &tc.e, &tc.f, &tc.s);
105
        if ( items != 7 )
106
        {
107
                EPRINTF("Improperly formatted pointer calibration file %s.\n",
108
                        cal_filename);
109
                return -1;
110
        }
111
 
112
#if TEST
113
                EPRINTF("a=%d b=%d c=%d d=%d e=%d f=%d s=%d\n",
114
                        tc.a, tc.b, tc.c, tc.d, tc.e, tc.f, tc.s);
115
#endif
116
 
117
        return 0;
118
}
119
 
120
inline MWPOINT DeviceToScreen(MWPOINT p)
121
{
122
        /*
123
         * Transform device coordinates to screen coordinates.
124
         * Take a point p in device coordinates and return the corresponding
125
         * point in screen coodinates.
126
         * This can scale, translate, rotate and/or skew, based on the
127
         * coefficients calculated above based on the list of screen
128
         * vs. device coordinates.
129
         */
130
 
131
        static MWPOINT prev;
132
        /* set slop at 3/4 pixel */
133
        const short slop = TRANSFORMATION_UNITS_PER_PIXEL * 3 / 4;
134
        MWPOINT new, out;
135
 
136
        /* transform */
137
        new.x = (tc.a * p.x + tc.b * p.y + tc.c) / tc.s;
138
        new.y = (tc.d * p.x + tc.e * p.y + tc.f) / tc.s;
139
 
140
        /* hysteresis (thanks to John Siau) */
141
        if ( abs(new.x - prev.x) >= slop )
142
                out.x = (new.x | 0x3) ^ 0x3;
143
        else
144
                out.x = prev.x;
145
 
146
        if ( abs(new.y - prev.y) >= slop )
147
                out.y = (new.y | 0x3) ^ 0x3;
148
        else
149
                out.y = prev.y;
150
 
151
        prev = out;
152
 
153
        return out;
154
}
155
 
156
static int PD_Open(MOUSEDEVICE *pmd)
157
{
158
  struct scanparam s;
159
  int settle_upper_limit;
160
  int result;
161
 
162
  /* Open the device */
163
  pd_fd = open("/dev/tpanel", O_NONBLOCK);
164
 
165
  if (pd_fd < 0)
166
    {
167
      EPRINTF("Error %d opening touch panel\n", errno);
168
      return -1;
169
    }
170
 
171
  s.interval = MOU_READ_INTERVAL;
172
 
173
  /*
174
   * Upper limit on settle time is approximately (scan_interval / 5) - 60
175
   * (5 conversions and some fixed overhead)
176
   * The opmtimal value is the lowest that doesn't cause significant
177
   * distortion.
178
   */
179
 
180
  settle_upper_limit = (s.interval / 5) - 60;
181
  s.settletime = settle_upper_limit * 50 / 100;
182
  result = ioctl(pd_fd, TPSETSCANPARM, &s);
183
 
184
  if ( result < 0 )
185
    EPRINTF("Error %d, result %d setting scan parameters.\n",
186
            result, errno);
187
 
188
  if (enable_pointing_coordinate_transform)
189
    {
190
      if (GetPointerCalibrationData() < 0)
191
        {
192
          close(pd_fd);
193
          return -1;
194
        }
195
    }
196
 
197
  /* We choose not to hide the cursor for now, others may want to */
198
 
199
#ifdef NOTUSED
200
#ifndef TEST
201
    /* Hide the cursor */
202
  GdHideCursor(&scrdev);
203
#endif
204
#endif
205
 
206
  return(pd_fd);
207
}
208
 
209
static void PD_Close(void)
210
{
211
        /* Close the touch panel device. */
212
        if (pd_fd >= 0)
213
                close(pd_fd);
214
        pd_fd = -1;
215
}
216
 
217
static int PD_GetButtonInfo(void)
218
{
219
        /* get "mouse" buttons supported */
220
        return MWBUTTON_L;
221
}
222
 
223
static void PD_GetDefaultAccel(int *pscale,int *pthresh)
224
{
225
        /*
226
         * Get default mouse acceleration settings
227
         * This doesn't make sense for a touch panel.
228
         * Just return something inconspicuous for now.
229
         */
230
        *pscale = 3;
231
        *pthresh = 5;
232
}
233
 
234
#define MAX_DEVICE_READS 10
235
static int read_tp(unsigned short *x, unsigned short *y,
236
                   unsigned short *z, int *b, unsigned short *status, unsigned char block)
237
{
238
  unsigned char read_count = 0;
239
  unsigned short tempx, tempy;
240
  int bytes_read;
241
  unsigned short data[6];
242
 
243
  /* Uh, oh -- The driver is slow and fat, so we get lots of EAGAINS between   */
244
  /* reads.  Thats never good.  So we loop here for some count before we bail  */
245
 
246
  while(read_count < MAX_DEVICE_READS)
247
    {
248
      bytes_read = read(pd_fd, data, sizeof(data));
249
 
250
      if (bytes_read != sizeof(data))
251
        {
252
          if (errno != EAGAIN)
253
            {
254
              EPRINTF("Error reading touch panel.  errno = %d\n", errno);
255
              return(errno);
256
            }
257
 
258
          if (block)
259
            {
260
              if (read_count++ == MAX_DEVICE_READS)
261
                return(EAGAIN);
262
              else
263
                usleep(MOU_READ_INTERVAL / MAX_DEVICE_READS);
264
            }
265
          else
266
            return(EAGAIN);
267
        }
268
      else
269
        break;
270
    }
271
 
272
  tempx = data[DATA_XPLUS];
273
  tempy = data[DATA_YPLUS];
274
 
275
  /* Sanity check */
276
  /* This is based on measured values.  Occassionally, we get a bad read from the board */
277
  /* This is to ensure that really wacked out reads don't get through.                  */
278
 
279
  if ((data[DATA_STATUS] & TP_STATUS_DATAVALID) == TP_STATUS_DATAVALID)
280
    {
281
       if (enable_pointing_coordinate_transform)
282
         {
283
           if (tempx < TP_MIN_X_SIZE || tempx > TP_MAX_X_SIZE)
284
             {
285
#ifdef TEST
286
               EPRINTF("Got an out of range X value.  X=%d,Y=%d,B=%d\n",
287
                       tempx, tempy,
288
                       ((data[DATA_STATUS] & TP_STATUS_PENCONTACT) ? MWBUTTON_L : 0));
289
#endif
290
               return(EAGAIN);
291
             }
292
 
293
           if (tempy < TP_MIN_Y_SIZE || tempy > TP_MAX_Y_SIZE)
294
             {
295
#ifdef TEST
296
               EPRINTF("Got an out of range Y value.  X=%d,Y=%d,B=%d\n",
297
                       tempx, tempy,
298
                       ((data[DATA_STATUS] & TP_STATUS_PENCONTACT) ? MWBUTTON_L : 0));
299
#endif
300
               return(EAGAIN);
301
             }
302
         }
303
 
304
       *x = tempx;
305
       *y = tempy;
306
       *z = data[DATA_Z];
307
    }
308
  else
309
    {
310
      *x = 0;
311
      *y = 0;
312
      *z = 0;
313
    }
314
 
315
  *b = ((data[DATA_STATUS] & TP_STATUS_PENCONTACT) ? MWBUTTON_L : 0);
316
  *status = data[DATA_STATUS];
317
 
318
  return(0);
319
}
320
 
321
 
322
static int PD_Read(MWCOORD *px, MWCOORD *py, MWCOORD *pz, int *pb)
323
{
324
#ifdef USE_FILTER
325
  /* Filter stuff borrowed from mou_tp.c */
326
  const int iir_shift_bits = 3;
327
  const int iir_sample_depth = (1 << iir_shift_bits);
328
 
329
  static int iir_accum_x = 0;
330
  static int iir_accum_y = 0;
331
  static int iir_accum_z = 0;
332
  static int iir_count = 0;
333
#else
334
  double cx, cy, cz;
335
#endif
336
 
337
  /* Other local variables */
338
  MWPOINT transformed;
339
  int err = 0;
340
  unsigned short samples = 0;
341
  unsigned short xpos = 0;
342
  unsigned short ypos = 0;
343
  unsigned short zpos = 0;
344
  unsigned short status = 0;
345
 
346
  *pb = 0;
347
  *px = 0;
348
  *py = 0;
349
  *pz = 0;
350
 
351
#ifndef USE_FILTER
352
  cx = 0;
353
  cy = 0;
354
  cz = 0;
355
#endif
356
 
357
  if ((err = read_tp(&xpos, &ypos, &zpos, pb, &status, 0)))
358
    {
359
      if (err == EAGAIN)
360
        return(0);
361
      else
362
        return(1);
363
    }
364
 
365
  /* Check the status of the button */
366
 
367
  if ( (status & TP_STATUS_DATAVALID) != TP_STATUS_DATAVALID)
368
    {
369
      if (*pb)
370
        return(0);
371
      else
372
        goto button_up;
373
    }
374
 
375
  while((status & TP_STATUS_DATAVALID) == TP_STATUS_DATAVALID)
376
    {
377
      int tempb = 0;
378
 
379
      err = read_tp(&xpos, &ypos, &zpos, &tempb, &status, 1);
380
 
381
      if (err == EAGAIN)
382
        {
383
          if (!samples)
384
            continue; /* We need at least one reading! */
385
          else
386
            break; /* The device continues to not respond.  Bail */
387
        }
388
      else if (err)
389
        return(-1);
390
 
391
      /* If the data is invalid and the button is down, then bail */
392
      /* Otherwise, record the button data */
393
 
394
      if ( (status & TP_STATUS_DATAVALID) != TP_STATUS_DATAVALID)
395
        {
396
          if (tempb)
397
            return(0); /* Button is down, but data is invalid */
398
          else
399
            {
400
              *pb = tempb; /* Record button up */
401
              goto button_up;
402
            }
403
        }
404
 
405
#ifdef USE_FILTER
406
 
407
      /* Run the newly aquired data through a filter */
408
      /* is filter ready? */
409
      if ( iir_count == iir_sample_depth )
410
        {
411
          /* make room for new sample */
412
          iir_accum_x -= iir_accum_x >> iir_shift_bits;
413
          iir_accum_y -= iir_accum_y >> iir_shift_bits;
414
          iir_accum_z -= iir_accum_z >> iir_shift_bits;
415
 
416
          /* feed new sample to filter */
417
          iir_accum_x += xpos;
418
          iir_accum_y += ypos;
419
          iir_accum_z += zpos;
420
        }
421
      else
422
        {
423
          iir_accum_x += xpos;
424
          iir_accum_y += ypos;
425
          iir_accum_z += zpos;
426
          iir_count += 1;
427
        }
428
 
429
#else
430
      cx += xpos;
431
      cy += ypos;
432
      cz += zpos;
433
#endif
434
 
435
      samples++;
436
 
437
      /* Enough samples?? */
438
      if (samples >= MOU_SAMPLE_RATE)
439
        break;
440
    }
441
 
442
  if (!samples)
443
    return(0);
444
 
445
#ifdef USE_FILTER  
446
  /* We're not done gathering samples yet */
447
  if (iir_count < iir_sample_depth)
448
    return(0);
449
 
450
  if (enable_pointing_coordinate_transform)
451
    {
452
      /* transform x,y to screen coords */
453
      transformed.x = iir_accum_x;
454
      transformed.y = iir_accum_y;
455
      transformed = DeviceToScreen(transformed);
456
 
457
      *px = transformed.x >> 2;
458
      *py = transformed.y >> 2;
459
    }
460
  else
461
    {
462
      *px = (MWCOORD) abs(iir_accum_x);
463
      *py = (MWCOORD) abs(iir_accum_y);
464
    }
465
#else
466
 
467
  if (enable_pointing_coordinate_transform)
468
    {
469
      transformed.x = (cx / samples);
470
      transformed.y = (cy / samples);
471
 
472
      transformed = DeviceToScreen(transformed);
473
 
474
      *px = (MWCOORD) transformed.x >> 2;
475
      *py = (MWCOORD) transformed.y >> 2;
476
    }
477
  else
478
    {
479
      *px = (MWCOORD) abs(cx / samples);
480
      *py = (MWCOORD) abs(cy / samples);
481
    }
482
#endif
483
 
484
 button_up:
485
  if (! *pb)
486
    {
487
#ifdef USE_FILTER 
488
     /* reset the filter */
489
      iir_count = 0;
490
      iir_accum_x = 0;
491
      iir_accum_y = 0;
492
      iir_accum_z = 0;
493
#endif
494
      return(3);
495
    }
496
  else
497
    return(2); /* XYZ and button data */
498
 
499
}
500
 
501
#ifndef TEST
502
MOUSEDEVICE mousedev = {
503
        PD_Open,
504
        PD_Close,
505
        PD_GetButtonInfo,
506
        PD_GetDefaultAccel,
507
        PD_Read,
508
        NULL
509
};
510
#endif
511
 
512
#ifdef TEST
513
int main(int argc, char ** v)
514
{
515
        int x, y, z;
516
 
517
        int     b;
518
        int result;
519
 
520
        DPRINTF("Opening touch panel...\n");
521
 
522
        if((result=PD_Open(0)) < 0)
523
          {
524
 
525
            DPRINTF("Error %d, result %d opening touch-panel\n", errno, result);
526
            exit(0);
527
          }
528
 
529
        DPRINTF("Reading touch panel...\n");
530
 
531
        while(1)
532
          {
533
            result = PD_Read(&x, &y, &z, &b);
534
 
535
            if( result > 0)
536
              {
537
                DPRINTF("(%d,%d,%d) b = %d\n",x, y, z, b);
538
              }
539
          }
540
}
541
#endif
542
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.