/*
* Copyright 2010 by Red Hat, Inc.
*
* 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.
*/
#ifndef ISDV4_H
#define ISDV4_H
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#define ISDV4_QUERY "*" /* ISDV4 query command */
#define ISDV4_RESET "&" /* ISDV4 touch panel reset command */
#define ISDV4_TOUCH_QUERY "%" /* ISDV4 touch query command */
#define ISDV4_STOP "0" /* ISDV4 stop command */
#define ISDV4_SAMPLING "1" /* ISDV4 sampling command */
/* packet length for individual models */
#define ISDV4_PKGLEN_TOUCH93 5
#define ISDV4_PKGLEN_TOUCH9A 7
#define ISDV4_PKGLEN_TPCPEN 9
#define ISDV4_PKGLEN_TPCCTL 11
#define ISDV4_PKGLEN_TOUCH2FG 13
#define HEADER_BIT 0x80
#define CONTROL_BIT 0x40
#define DATA_ID_MASK 0x3F
#define TOUCH_CONTROL_BIT 0x10
/* Only for touch devices: use serial ID as index to get packet length for device */
int ISDV4PacketLengths[] = {
/* 0x00 => */ ISDV4_PKGLEN_TOUCH93,
/* 0x01 => */ ISDV4_PKGLEN_TOUCH9A,
/* 0x02 => */ ISDV4_PKGLEN_TOUCH93,
/* 0x03 => */ ISDV4_PKGLEN_TOUCH9A,
/* 0x04 => */ ISDV4_PKGLEN_TOUCH9A,
/* 0x05 => */ ISDV4_PKGLEN_TOUCH2FG
};
/* ISDV4 protocol parsing structs. */
/* Query reply data */
typedef struct {
unsigned char data_id; /* always 00H */
uint16_t x_max;
uint16_t y_max;
uint16_t pressure_max;
uint8_t tilt_x_max;
uint8_t tilt_y_max;
uint16_t version;
} ISDV4QueryReply;
/* Touch Query reply data */
typedef struct {
uint8_t data_id; /* always 01H */
uint8_t panel_resolution;
uint8_t sensor_id;
uint16_t x_max;
uint16_t y_max;
uint8_t capacity_resolution;
uint16_t version;
} ISDV4TouchQueryReply;
/* Touch Data format. Note that capacity and finger2 are only set for some
* devices (0 on all others) */
typedef struct {
uint8_t status; /* touch down/up */
uint16_t x;
uint16_t y;
uint16_t capacity;
struct {
uint8_t status; /* touch down/up */
uint16_t x;
uint16_t y;
} finger2;
} ISDV4TouchData;
/* Coordinate data format */
typedef struct {
uint8_t proximity; /* in proximity? */
uint8_t tip; /* tip/eraser pressed? */
uint8_t side; /* side switch pressed? */
uint8_t eraser; /* eraser pressed? */
uint16_t x;
uint16_t y;
uint16_t pressure;
uint8_t tilt_x;
uint8_t tilt_y;
} ISDV4CoordinateData;
static inline int isdv4ParseQuery(const unsigned char *buffer, const size_t len,
ISDV4QueryReply *reply)
{
int header, control;
if (!reply || len < ISDV4_PKGLEN_TPCCTL)
return 0;
header = !!(buffer[0] & HEADER_BIT);
control = !!(buffer[0] & CONTROL_BIT);
if (!header || !control)
return -1;
reply->data_id = buffer[0] & DATA_ID_MASK;
/* FIXME: big endian? */
reply->x_max = (buffer[1] << 9) | (buffer[2] << 2) | ((buffer[6] >> 5) & 0x3);
reply->y_max = (buffer[3] << 9) | (buffer[4] << 2) | ((buffer[6] >> 3) & 0x3);
reply->pressure_max = (buffer[6] & 0x7) << 7 | buffer[5];
reply->tilt_y_max = buffer[7];
reply->tilt_x_max = buffer[8];
reply->version = buffer[9] << 7 | buffer[10];
return ISDV4_PKGLEN_TPCCTL;
}
static inline int isdv4ParseTouchQuery(const unsigned char *buffer, const size_t len,
ISDV4TouchQueryReply *reply)
{
int header, control;
if (!reply || len < ISDV4_PKGLEN_TPCCTL)
return 0;
header = !!(buffer[0] & HEADER_BIT);
control = !!(buffer[0] & CONTROL_BIT);
if (!header || !control)
return -1;
reply->data_id = buffer[0] & DATA_ID_MASK;
reply->sensor_id = buffer[2] & 0x7;
reply->panel_resolution = buffer[1];
/* FIXME: big endian? */
reply->x_max = (buffer[3] << 9) | (buffer[4] << 2) | ((buffer[2] >> 5) & 0x3);
reply->y_max = (buffer[5] << 9) | (buffer[6] << 2) | ((buffer[2] >> 3) & 0x3);
reply->capacity_resolution = buffer[7];
reply->version = buffer[9] << 7 | buffer[10];
return ISDV4_PKGLEN_TPCCTL;
}
/* pktlen defines what touch type we parse */
static inline int isdv4ParseTouchData(const unsigned char *buffer, const size_t buff_len,
const size_t pktlen, ISDV4TouchData *touchdata)
{
int header, touch;
if (!touchdata || buff_len < pktlen)
return 0;
header = !!(buffer[0] & HEADER_BIT);
touch = !!(buffer[0] & TOUCH_CONTROL_BIT);
if (header != 1 || touch != 1)
return -1;
memset(touchdata, 0, sizeof(*touchdata));
touchdata->status = buffer[0] & 0x1;
/* FIXME: big endian */
touchdata->x = buffer[1] << 7 | buffer[2];
touchdata->y = buffer[3] << 7 | buffer[4];
if (pktlen == ISDV4_PKGLEN_TOUCH9A)
touchdata->capacity = buffer[5] << 7 | buffer[6];
if (pktlen == ISDV4_PKGLEN_TOUCH2FG)
{
touchdata->finger2.x = buffer[7] << 7 | buffer[8];
touchdata->finger2.y = buffer[9] << 7 | buffer[10];
touchdata->finger2.status = !!(buffer[0] & 0x2);
/* FIXME: is there a fg2 capacity? */
}
return pktlen;
}
static inline int isdv4ParseCoordinateData(const unsigned char *buffer, const size_t len,
ISDV4CoordinateData *coord)
{
int header, control;
if (!coord || len < ISDV4_PKGLEN_TPCPEN)
return 0;
header = !!(buffer[0] & HEADER_BIT);
control = !!(buffer[0] & TOUCH_CONTROL_BIT);
if (header != 1 || control != 0)
return -1;
coord->proximity = (buffer[0] >> 5) & 0x1;
coord->tip = buffer[0] & 0x1;
coord->side = (buffer[0] >> 1) & 0x1;
coord->eraser = (buffer[0] >> 2) & 0x1;
/* FIXME: big endian */
coord->x = (buffer[1] << 9) | (buffer[2] << 2) | ((buffer[6] >> 5) & 0x3);
coord->y = (buffer[3] << 9) | (buffer[4] << 2) | ((buffer[6] >> 3) & 0x3);
coord->pressure = ((buffer[6] & 0x7) << 7) | buffer[5];
coord->tilt_x = buffer[7];
coord->tilt_y = buffer[8];
return ISDV4_PKGLEN_TPCPEN;
}
#endif /* ISDV4_H */
/* vim: set noexpandtab tabstop=8 shiftwidth=8: */