-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathwaveshare-touch-driver.py
More file actions
166 lines (134 loc) · 6.26 KB
/
waveshare-touch-driver.py
File metadata and controls
166 lines (134 loc) · 6.26 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
#!/usr/bin/env python
import argparse
import uinput
import pyudev
import os
import sys
import string
import glob
import struct
import time
def grab_device(device_file, serial, packet_length=None):
"""
Grab an active touchscreen
"""
emulated_device = uinput.Device([
uinput.BTN_TOUCH,
uinput.ABS_X + (0, 4000, 0, 0),
uinput.ABS_Y + (0, 4000, 0, 0),
uinput.ABS_PRESSURE,
],
name="Waveshare Touchscreen (%s)" % serial,
vendor=0x0eef,
product=0x0005)
print("Device file found! Reading...")
try:
with open(device_file, 'rb') as f:
# We don't know the packet length yet
if packet_length == None:
packet_length = 0
found_tag = False
zero_byte_count = 0
print("Packet length unknown for this device, keep poking the screen until I figure it out.")
while True:
sample = f.read(1)
# Each packet starts with the tag 'aa' in hex
# After we find the first tag, we start counting the number of bytes
# until the next tag
# Also make sure the tag is followed by two or more zero bytes so we don't mistakenly
# pick the tag from elsewhere
if sample[0] == b'\x00' and found_tag:
zero_byte_count += 1
packet_length += len(sample)
elif sample[0] == b'\xaa' and not found_tag:
found_tag = True
packet_length += len(sample)
elif sample[0] == b'\xaa' and found_tag and zero_byte_count >= 2:
# We found the tag again and it was followed by two or more zero bytes
break
else:
zero_byte_count = 0
packet_length += len(sample)
# Packet length is now known, this blocking read is done
# so that the following reads always start with the tag as they should
f.read(packet_length-1)
print("Packet length for this device is %d bytes." % packet_length)
else:
print("Using provided packet length: %d" % packet_length)
# The last coordinates for the device when it was touched
last_x = 0
last_y = 0
while True:
try:
packet = f.read(packet_length)
except OSError:
print("Read failed, device was probably disconnected")
emulated_device.destroy()
exit()
(tag, clicked, x, y) = struct.unpack_from('>c?HH', packet)
if clicked:
last_x = x
last_y = y
#print("%dx%d" % (x, y))
emulated_device.emit(uinput.BTN_TOUCH, 1, False)
emulated_device.emit(uinput.ABS_X, x, False)
emulated_device.emit(uinput.ABS_Y, y, False)
emulated_device.emit(uinput.ABS_PRESSURE, 255, True)
else:
emulated_device.emit(uinput.BTN_TOUCH, 0, False)
emulated_device.emit(uinput.ABS_X, last_x, False)
emulated_device.emit(uinput.ABS_Y, last_y, False)
emulated_device.emit(uinput.ABS_PRESSURE, 0, True)
except OSError:
print("Device disconnected.")
emulated_device.destroy()
exit()
def get_serial(sys_name):
"""
Get the serial number for a device based on its sys_name
"""
devices = context.list_devices(sys_name=sys_name)
for device in devices:
try:
serial = device.attributes["serial"]
# Serial numbers appear to have non-printable characters inside them
# Remove those characters here
serial = "".join(filter(lambda x: x in string.printable, serial))
return serial
except:
pass
return None
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Userspace driver for Waveshare touchscreens.")
parser.add_argument('--devpath', type=str, required=True,
help="Devpath of the USB device (eg. /devices/usb.1/12000000.dwc3/xhci-hcd.2.auto/usb3/3-1/3-1.1/3-1.1.1/3-1.1.1.4). In normal operation this is passed automatically by udev.")
parser.add_argument("--packet_length", type=int, required=False,
help="Packet length for the device. The driver should be able to determine this automatically.")
args = parser.parse_args()
devpath = args.devpath
if "packet_length" in args:
packet_length = args.packet_length
else:
packet_length = None
# Get the sys_name from the full devpath (eg. 3-1.1.1.4)
sys_name = devpath[devpath.rfind("/")+1:]
os.system("modprobe uinput")
context = pyudev.Context()
# Get the device loaded as /dev/hidraw*
devices = context.list_devices().match(subsystem = "hidraw")
for device in devices:
if "0EEF:0005" in device.sys_path and "%s/" % sys_name in device.sys_path:
# We found a matching device, let's try to grab it
print("Device found!")
# Get the serial number for this device, since it allows
# us to give each device a deterministic name (eg. changing the USB slot it's plugged into
# shouldn't affect the configuration)
serial = get_serial(sys_name)
if serial != None:
print("Serial number for this device: %s" % serial)
else:
print("Couldn't find the serial number for this device!")
serial = "UNKNOWN SN"
device_file = "/dev/%s" % (device.sys_path[device.sys_path.rfind('/')+1:])
grab_device(device_file, serial, packet_length)
print("Device not found!")