#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>
#include "tablet.h"

#define BUFLEN 100


int tablet_fd = -1;
int tablet_x = 0, tablet_y = 0;
int tablet_button = 0, tablet_touch = 0, tablet_pressure = 0;

static void (*callback_func)(void) = NULL;


/* returns 1 for success */
int
tablet_init(void)
{
	int fd;
	struct termios t;

	fd=open(TABLET_FILE,O_RDWR);

	if (fd<0)
		return perror(TABLET_FILE),0;

	tcgetattr(fd,&t);
	t.c_cflag|=CLOCAL|CS8;
	t.c_cflag&=~CRTSCTS;
	t.c_iflag&=~IGNPAR;
	t.c_oflag&=~ONLCR;
	t.c_lflag&=~(ECHOE|ECHOK|ECHOKE|ECHOCTL);
	cfsetospeed(&t,B9600);
	t.c_cc[VTIME]=1;
	tcsetattr(fd,TCSANOW,&t);

	tablet_fd = fd;
	return 1;
}


static void
got_packet(unsigned char *s, int len)
{
	if ((len == 1) && ((s[0] & 0x0F) == 0x08)) {
		/* so far as I can tell this is just a pen-in-range
		 * notification.  big deal. */
	} else if (len == 6) {
/* the packets look like this (second line is bit significance):
 *  1??? 00bt 0xxx xxxx 0xx0 0xxx 0yyy yyyy 0y00 yyyy 00pp pppp
 *             876 5432  10   ba9  765 4321  0   ba98   54 3210
 * so 12-bits of X, 12-bits of Y, button, touch, 6-bits of pressure,
 * and 3 mystery bits */
		tablet_button = (s[0] & 0x02) ? 1 : 0;
		tablet_touch = (s[0] & 0x01) ? 1 : 0;
		tablet_x = (s[2] >> 5) | ((s[1] & 0x7F) << 2) | ((s[2] & 0x07) << 9);
		tablet_y = (s[4] >> 6) | ((s[3] & 0x7F) << 1) | ((s[4] & 0x0F) << 8);
		tablet_pressure = s[5] & 0x3F;

		if (callback_func)
			callback_func();
	} else {
		/* craziness */
	}
}

/* returns the number of complete packets read */
int
tablet_read(void)
{
	static unsigned char buf[BUFLEN];
	static int buflen = 0;
	unsigned char s[BUFLEN];
	int i,j;
	int ret = 0;

	i = read(tablet_fd, s, BUFLEN);

	if (i <= 0)
		return 0;

	for (j = 0; j < i; j++) {
		if (s[j] & 0x80) {
			if (buflen) {
				got_packet(buf, buflen);
				ret++;
			}
			buflen = 0;
		}
		buf[buflen++] = s[j];
		if (buflen >= BUFLEN) {
			buflen = 0;
			printf("overflow in tablet packetizing\n");
		}
	}

	return ret;
}

void
tablet_register(void (*func)(void))
{
	callback_func = func;
}

void
tablet_close(void)
{
	close(tablet_fd);
	tablet_fd = -1;
}
