HelenOS sources
This source file includes following definitions.
- isdv4_event_init
- parse_event
- parse_response_stylus
- parse_response_touch
- read_packets
- write_command
- isdv4_init
- isdv4_init_tablet
- isdv4_read_events
- isdv4_fini
#include <errno.h>
#include <fibril.h>
#include <io/chardev.h>
#include <mem.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include "isdv4.h"
#define BUF_SIZE 64
#define START_OF_PACKET 128
#define CONTROL_PACKET 64
#define TOUCH_EVENT 16
#define FINGER1 1
#define FINGER2 2
#define TIP 1
#define BUTTON1 2
#define BUTTON2 4
#define PROXIMITY 32
#define CMD_START '1'
#define CMD_STOP '0'
#define CMD_QUERY_STYLUS '*'
#define CMD_QUERY_TOUCH '%'
typedef bool (*packet_consumer_fn)(uint8_t *packet, size_t size,
isdv4_state_t *state);
static void isdv4_event_init(isdv4_event_t *event)
{
memset(event, 0, sizeof(isdv4_event_t));
}
static bool parse_event(uint8_t *packet, size_t size, isdv4_state_t *state)
{
if (size < 1)
return false;
bool control_packet = ((packet[0] & CONTROL_PACKET) > 0);
if (control_packet)
return true;
isdv4_event_t event;
isdv4_event_init(&event);
if (packet[0] & TOUCH_EVENT) {
if (size != 5)
return true;
bool finger1 = (packet[0] & FINGER1) > 0;
event.x = ((packet[1] & 127) << 7) | (packet[2] & 127);
event.y = ((packet[3] & 127) << 7) | (packet[4] & 127);
event.source = TOUCH;
if (!state->stylus_in_proximity) {
if (!finger1 && state->finger1_pressed) {
state->finger1_pressed = false;
event.type = RELEASE;
event.button = 1;
state->emit_event_fn(&event);
} else if (finger1 && !state->finger1_pressed) {
state->finger1_pressed = true;
event.type = PRESS;
event.button = 1;
state->emit_event_fn(&event);
} else {
event.type = MOVE;
event.button = 1;
state->emit_event_fn(&event);
}
}
} else {
if (size != 9)
return true;
bool tip = packet[0] & TIP;
bool button1 = packet[0] & BUTTON1;
bool button2 = packet[0] & BUTTON2;
bool proximity = packet[0] & PROXIMITY;
event.x = ((packet[1] & 127) << 7) | (packet[2] & 124) | ((packet[6] >> 5) & 3);
event.y = ((packet[3] & 127) << 7) | (packet[4] & 124) | ((packet[6] >> 3) & 3);
event.pressure = (packet[5] & 127) | ((packet[6] & 7) << 7);
if (proximity && !state->stylus_in_proximity) {
state->stylus_in_proximity = true;
state->stylus_is_eraser = !tip && button2;
event.source = (state->stylus_is_eraser ? STYLUS_ERASER : STYLUS_TIP);
event.type = PROXIMITY_IN;
state->emit_event_fn(&event);
} else if (!proximity && state->stylus_in_proximity) {
state->stylus_in_proximity = false;
event.source = (state->stylus_is_eraser ? STYLUS_ERASER : STYLUS_TIP);
event.type = PROXIMITY_OUT;
state->emit_event_fn(&event);
} else {
if (state->stylus_is_eraser && !button2) {
event.type = PROXIMITY_OUT;
event.source = STYLUS_ERASER;
state->emit_event_fn(&event);
event.type = PROXIMITY_IN;
event.source = STYLUS_TIP;
state->emit_event_fn(&event);
state->stylus_is_eraser = false;
} else if (!state->stylus_is_eraser && !tip && button2) {
event.type = PROXIMITY_OUT;
event.source = STYLUS_TIP;
state->emit_event_fn(&event);
event.type = PROXIMITY_IN;
event.source = STYLUS_ERASER;
state->emit_event_fn(&event);
state->stylus_is_eraser = true;
}
}
if (!state->stylus_is_eraser) {
if (tip && !state->tip_pressed) {
state->tip_pressed = true;
event.type = PRESS;
event.source = STYLUS_TIP;
event.button = 1;
state->emit_event_fn(&event);
} else if (!tip && state->tip_pressed) {
state->tip_pressed = false;
event.type = RELEASE;
event.source = STYLUS_TIP;
event.button = 1;
state->emit_event_fn(&event);
}
if (button1 && !state->button1_pressed) {
state->button1_pressed = true;
event.type = PRESS;
event.source = STYLUS_TIP;
event.button = 2;
state->emit_event_fn(&event);
} else if (!button1 && state->button1_pressed) {
state->button1_pressed = false;
event.type = RELEASE;
event.source = STYLUS_TIP;
event.button = 2;
state->emit_event_fn(&event);
}
if (button2 && !state->button2_pressed) {
state->button2_pressed = true;
event.type = PRESS;
event.source = STYLUS_TIP;
event.button = 3;
state->emit_event_fn(&event);
} else if (!button2 && state->button2_pressed) {
state->button2_pressed = false;
event.type = RELEASE;
event.source = STYLUS_TIP;
event.button = 3;
state->emit_event_fn(&event);
}
event.type = MOVE;
event.source = STYLUS_TIP;
event.button = 0;
state->emit_event_fn(&event);
} else {
if (tip && !state->tip_pressed) {
state->tip_pressed = true;
event.type = PRESS;
event.source = STYLUS_ERASER;
event.button = 1;
state->emit_event_fn(&event);
} else if (!tip && state->tip_pressed) {
state->tip_pressed = false;
event.type = RELEASE;
event.source = STYLUS_ERASER;
event.button = 1;
state->emit_event_fn(&event);
}
event.type = MOVE;
event.source = STYLUS_ERASER;
event.button = 0;
state->emit_event_fn(&event);
}
}
return true;
}
static bool parse_response_stylus(uint8_t *packet, size_t size,
isdv4_state_t *state)
{
if (size < 1)
return false;
bool control_packet = ((packet[0] & CONTROL_PACKET) > 0);
if (!control_packet)
return true;
if (size != 11)
return false;
state->stylus_max_x = ((packet[1] & 127) << 7) | (packet[2] & 124) |
((packet[6] >> 5) & 3);
state->stylus_max_y = ((packet[3] & 127) << 7) | (packet[4] & 124) |
((packet[6] >> 3) & 3);
state->stylus_max_pressure = (packet[5] & 63) | ((packet[6] & 7) << 7);
state->stylus_max_xtilt = packet[8] & 127;
state->stylus_max_ytilt = packet[7] & 127;
state->stylus_tilt_supported = (state->stylus_max_xtilt &&
state->stylus_max_ytilt);
return false;
}
static bool parse_response_touch(uint8_t *packet, size_t size,
isdv4_state_t *state)
{
if (size < 1)
return false;
bool control_packet = ((packet[0] & CONTROL_PACKET) > 0);
if (!control_packet)
return true;
if (size != 11)
return false;
state->touch_type = (packet[0] & 63);
unsigned int touch_resolution = packet[1] & 127;
state->touch_max_x = ((packet[2] >> 5) & 3) | ((packet[3] & 127) << 7) |
(packet[4] & 124);
state->touch_max_y = ((packet[2] >> 3) & 3) | ((packet[5] & 127) << 7) |
(packet[6] & 124);
if (touch_resolution == 0)
touch_resolution = 10;
if (state->touch_max_x == 0 || state->touch_max_y == 0) {
state->touch_max_x = (1 << touch_resolution);
state->touch_max_y = (1 << touch_resolution);
}
return false;
}
static errno_t read_packets(isdv4_state_t *state, packet_consumer_fn consumer)
{
bool reading = true;
while (reading) {
size_t nread;
errno_t rc;
rc = chardev_read(state->chardev, state->buf + state->buf_end,
state->buf_size - state->buf_end, &nread, chardev_f_none);
if (rc != EOK && nread == 0)
return EIO;
state->buf_end += nread;
size_t i = 0;
while (i < state->buf_end && (state->buf[i] & START_OF_PACKET) == 0)
i++;
size_t start = i;
size_t end = i;
size_t processed_end = i;
while (reading && i < state->buf_end) {
size_t packet_remaining;
if (state->buf[i] & CONTROL_PACKET) {
packet_remaining = 11;
} else if (state->buf[i] & TOUCH_EVENT) {
packet_remaining = 5;
} else {
packet_remaining = 9;
}
i++;
packet_remaining--;
while (packet_remaining > 0 && i < state->buf_end &&
(state->buf[i] & START_OF_PACKET) == 0) {
i++;
packet_remaining--;
}
end = i;
if (end > start && packet_remaining == 0) {
reading = consumer(state->buf + start, end - start, state);
start = end;
processed_end = end;
}
}
if (processed_end == 0 && state->buf_end == state->buf_size) {
state->buf_end = 0;
}
size_t unprocessed_len = state->buf_end - processed_end;
memcpy(state->buf, state->buf + processed_end, unprocessed_len);
state->buf_end = unprocessed_len;
}
return EOK;
}
static bool write_command(chardev_t *chardev, uint8_t command)
{
errno_t rc;
size_t nwr;
rc = chardev_write(chardev, &command, 1, &nwr);
return rc == EOK;
}
errno_t isdv4_init(isdv4_state_t *state, async_sess_t *sess,
isdv4_event_fn event_fn)
{
chardev_t *chardev;
errno_t rc;
rc = chardev_open(sess, &chardev);
if (rc != EOK)
return rc;
memset(state, 0, sizeof(isdv4_state_t));
state->sess = sess;
state->chardev = chardev;
state->buf = malloc(BUF_SIZE);
if (state->buf == NULL) {
chardev_close(chardev);
return ENOMEM;
}
state->buf_size = BUF_SIZE;
state->emit_event_fn = event_fn;
return EOK;
}
errno_t isdv4_init_tablet(isdv4_state_t *state)
{
if (!write_command(state->chardev, CMD_STOP))
return EIO;
fibril_usleep(250000);
if (!write_command(state->chardev, CMD_QUERY_STYLUS))
return EIO;
errno_t rc = read_packets(state, parse_response_stylus);
if (rc != EOK)
return rc;
if (!write_command(state->chardev, CMD_QUERY_TOUCH))
return EIO;
rc = read_packets(state, parse_response_touch);
if (rc != EOK)
return rc;
if (!write_command(state->chardev, CMD_START))
return EIO;
return EOK;
}
errno_t isdv4_read_events(isdv4_state_t *state)
{
return read_packets(state, parse_event);
}
void isdv4_fini(isdv4_state_t *state)
{
free(state->buf);
}
HelenOS homepage, sources at GitHub