Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add an evdev touchscreen driver #228

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 110 additions & 0 deletions driver/linux/evdev.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,19 @@
import select
import lvgl as lv

EV_REL = 0x02
EV_ABS = 0x03
EV_KEY = 0x01
REL_X = 0x00
REL_Y = 0x01
ABS_X = 0x00
ABS_Y = 0x01
ABS_MT_POSITION_X = 0x35
ABS_MT_POSITION_Y = 0x36
ABS_MT_TRACKING_ID = 0x39
BTN_MOUSE = 0x110
BTN_TOUCH = 0x14a

# Default crosshair cursor
class crosshair_cursor:
def __init__(self, scr=None):
Expand Down Expand Up @@ -80,3 +93,100 @@ def delete(self):
if self.cursor and hasattr(self.cursor, 'delete'):
self.cursor.delete()
self.indev.enable(False)

# evdev driver for touchscreen
class touch_indev:
def __init__(self, scr=None, device='/dev/input/event1', evdev_swap_axes=False):

# Open evdev and initialize members
self.evdev = open(device, 'rb')
self.poll = select.poll()
self.poll.register(self.evdev.fileno())
self.scr = scr if scr else lv.scr_act()
self.hor_res = self.scr.get_width()
self.ver_res = self.scr.get_height()
self.evdev_button = lv.INDEV_STATE.RELEASED
self.evdev_swap_axes = evdev_swap_axes
self.evdev_calibrate = False
self.last_evdev_root_x = 0
self.last_evdev_root_y = 0

def read(self, indev_drv, data) -> int:

# Check if there is input to be read from evdev
if not self.poll.poll()[0][1] & select.POLLIN:
return 0

FORMAT = 'llHHI'
EVENT_SIZE = ustruct.calcsize(FORMAT)

evdev_root_x = self.last_evdev_root_x
evdev_root_y = self.last_evdev_root_y

raw_data = self.evdev.read(EVENT_SIZE)

while(self.poll.poll()[0][1] & select.POLLIN):

# Read and parse evdev data
raw_data = self.evdev.read(EVENT_SIZE)
(_, _, event_type, code, value) = ustruct.unpack(FORMAT, raw_data)

if event_type == EV_ABS:
if (code == ABS_X) or (code == ABS_MT_POSITION_X):
if self.evdev_swap_axes:
evdev_root_y = value
else:
evdev_root_x = value
elif (code == ABS_Y) or (code == ABS_MT_POSITION_Y):
if self.evdev_swap_axes:
evdev_root_x = value
else:
evdev_root_y = value
elif code == ABS_MT_TRACKING_ID:
if value == -1:
self.evdev_button = lv.INDEV_STATE.RELEASED
else:
self.evdev_button = lv.INDEV_STATE.PRESSED
elif (event_type == EV_KEY) and (code == BTN_TOUCH):
if value == 0:
self.evdev_button = lv.INDEV_STATE.RELEASED
elif value == 1:
self.evdev_button = lv.INDEV_STATE.PRESSED

self.last_evdev_root_x = evdev_root_x
self.last_evdev_root_y = evdev_root_y

# Scaling
if self.evdev_calibrate:
evdev_root_x = self._map_horizontal(evdev_root_x)
evdev_root_y = self._map_vertical(evdev_root_y)

# Handle coordinate overflow cases
data.point.x = min(evdev_root_x, self.hor_res - 1)
data.point.y = min(evdev_root_y, self.ver_res - 1)
data.point.x = max(evdev_root_x, 0)
data.point.y = max(evdev_root_y, 0)

# Update "pressed" status
data.state = self.evdev_button

return 0

# Scaling: if range of evdev readouts is different than screen resolution
# Example for Waveshare 7inch HDMI LCD (C) Rev4.1
# touch.calibrate(0, 4096, 0, 4096)
def calibrate(self, evdev_min_hor, evdev_max_hor, evdev_min_ver, evdev_max_ver):
self.evdev_calibrate = True
self.evdev_min_hor = evdev_min_hor
self.evdev_max_hor = evdev_max_hor
self.evdev_min_ver = evdev_min_ver
self.evdev_max_ver = evdev_max_ver

def _map_vertical(self, val):
return int((val - self.evdev_min_ver) * (self.ver_res) / (self.evdev_max_ver - self.evdev_min_ver))

def _map_horizontal(self, val):
return int((val - self.evdev_min_hor) * (self.hor_res) / (self.evdev_max_hor - self.evdev_min_hor))

def delete(self):
self.evdev.close()