kopia lustrzana https://github.com/peterhinch/micropython-samples
asynctouch.py replaced by generic version of touch.py
rodzic
702485d288
commit
d2f4e9e79b
|
@ -3,7 +3,7 @@ import gc
|
||||||
from font14 import font14
|
from font14 import font14
|
||||||
from tft import TFT, LANDSCAPE
|
from tft import TFT, LANDSCAPE
|
||||||
from usched import Sched
|
from usched import Sched
|
||||||
from asynctouch import TOUCH
|
from touch import TOUCH
|
||||||
from button import Button, Buttonset, RadioButtons
|
from button import Button, Buttonset, RadioButtons
|
||||||
from ui import CIRCLE, RECTANGLE, CLIPPED_RECT
|
from ui import CIRCLE, RECTANGLE, CLIPPED_RECT
|
||||||
#gc.collect()
|
#gc.collect()
|
||||||
|
@ -66,7 +66,7 @@ def test(duration = 0):
|
||||||
print('Testing TFT...')
|
print('Testing TFT...')
|
||||||
objsched = Sched() # Instantiate the scheduler
|
objsched = Sched() # Instantiate the scheduler
|
||||||
mytft = TFT("SSD1963", "LB04301", LANDSCAPE)
|
mytft = TFT("SSD1963", "LB04301", LANDSCAPE)
|
||||||
mytouch = TOUCH(objsched, "XPT2046")
|
mytouch = TOUCH("XPT2046", objsched)
|
||||||
mytft.backlight(100) # light on
|
mytft.backlight(100) # light on
|
||||||
|
|
||||||
# Button assortment
|
# Button assortment
|
||||||
|
|
|
@ -3,7 +3,7 @@ import gc
|
||||||
from font10 import font10
|
from font10 import font10
|
||||||
from tft import TFT, LANDSCAPE
|
from tft import TFT, LANDSCAPE
|
||||||
from usched import Sched
|
from usched import Sched
|
||||||
from asynctouch import TOUCH
|
from touch import TOUCH
|
||||||
from slider import Slider
|
from slider import Slider
|
||||||
from button import Button
|
from button import Button
|
||||||
from ui import CLIPPED_RECT
|
from ui import CLIPPED_RECT
|
||||||
|
@ -84,7 +84,7 @@ def test(duration = 0):
|
||||||
print('Test TFT panel...')
|
print('Test TFT panel...')
|
||||||
objsched = Sched() # Instantiate the scheduler
|
objsched = Sched() # Instantiate the scheduler
|
||||||
mytft = TFT("SSD1963", "LB04301", LANDSCAPE)
|
mytft = TFT("SSD1963", "LB04301", LANDSCAPE)
|
||||||
mytouch = TOUCH(objsched, "XPT2046")
|
mytouch = TOUCH("XPT2046", objsched)
|
||||||
mytft.backlight(100) # light on
|
mytft.backlight(100) # light on
|
||||||
Button(objsched, mytft, mytouch, (400, 240), font = font10, callback = doquit, fgcolor = (255, 0, 0),
|
Button(objsched, mytft, mytouch, (400, 240), font = font10, callback = doquit, fgcolor = (255, 0, 0),
|
||||||
height = 30, text = 'Quit', shape = CLIPPED_RECT)
|
height = 30, text = 'Quit', shape = CLIPPED_RECT)
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
# asynctouch.py Asynchronous version of XPT2046 touchscreen controller.
|
#
|
||||||
|
|
||||||
# The MIT License (MIT)
|
# The MIT License (MIT)
|
||||||
#
|
#
|
||||||
# Copyright (c) 2016 Robert Hammelrath, Peter Hinch
|
# Copyright (c) 2016 Robert Hammelrath
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
# of this software and associated documentation files (the "Software"), to deal
|
# of this software and associated documentation files (the "Software"), to deal
|
||||||
|
@ -58,9 +57,14 @@ Y_HIGH = const(4090) ## highest reasonable Y value
|
||||||
class TOUCH:
|
class TOUCH:
|
||||||
#
|
#
|
||||||
# Init just sets the PIN's to In / out as required
|
# Init just sets the PIN's to In / out as required
|
||||||
#
|
# objsched: scheduler if asynchronous operation intended
|
||||||
def __init__(self, objsched, controller = "XPT2046", calibration = None, raw = False):
|
# confidence: confidence level - number of consecutive touches with a margin smaller than the given level
|
||||||
self.raw = raw
|
# which the function will sample until it accepts it as a valid touch
|
||||||
|
# margin: Difference from mean centre at which touches are considered at the same position
|
||||||
|
# delay: Delay between samples in ms. (n/a if asynchronous)
|
||||||
|
#
|
||||||
|
DEFAULT_CAL = (-3917, -0.127, -3923, -0.1267, -3799, -0.07572, -3738, -0.07814)
|
||||||
|
def __init__(self, controller = "XPT2046", objsched = None, *, confidence = 5, margin = 50, delay = 10, calibration = None):
|
||||||
if PCB_VERSION == 1:
|
if PCB_VERSION == 1:
|
||||||
self.pin_clock = pyb.Pin("Y8", pyb.Pin.OUT_PP)
|
self.pin_clock = pyb.Pin("Y8", pyb.Pin.OUT_PP)
|
||||||
self.pin_clock.value(0)
|
self.pin_clock.value(0)
|
||||||
|
@ -74,37 +78,38 @@ class TOUCH:
|
||||||
self.pin_d_in = pyb.Pin("Y1", pyb.Pin.IN)
|
self.pin_d_in = pyb.Pin("Y1", pyb.Pin.IN)
|
||||||
self.pin_irq = pyb.Pin("Y2", pyb.Pin.IN)
|
self.pin_irq = pyb.Pin("Y2", pyb.Pin.IN)
|
||||||
# set default values
|
# set default values
|
||||||
self.margin = 50 * 50 # tolerance margin: standard deviation of distance of touch from mean; store square
|
|
||||||
self.buff = [[-self.margin, -self.margin] for x in range(5)] # confidence == 5. Impossible coords
|
|
||||||
if calibration:
|
|
||||||
self.calibration = calibration
|
|
||||||
else: # default values for my tft
|
|
||||||
self.calibration = (-3917,-0.127,-3923,-0.1267,-3799,-0.07572,-3738,-0.07814)
|
|
||||||
self.position = [0, 0]
|
|
||||||
self.ready = False
|
self.ready = False
|
||||||
self.touched = False
|
self.touched = False
|
||||||
objsched.add_thread(self.main_thread())
|
self.x = 0
|
||||||
|
self.y = 0
|
||||||
|
self.buf_length = 0
|
||||||
|
cal = TOUCH.DEFAULT_CAL if calibration is None else calibration
|
||||||
|
self.asynchronous = False
|
||||||
|
self.touch_parameter(confidence, margin, delay, cal)
|
||||||
|
if objsched is not None:
|
||||||
|
self.asynchronous = True
|
||||||
|
objsched.add_thread(self._main_thread())
|
||||||
|
|
||||||
#
|
|
||||||
# Now I'm up to get my touches
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# set parameters for get_touch()
|
# set parameters for get_touch()
|
||||||
|
# res: Resolution in bits of the returned values, default = 10
|
||||||
# confidence: confidence level - number of consecutive touches with a margin smaller than the given level
|
# confidence: confidence level - number of consecutive touches with a margin smaller than the given level
|
||||||
# which the function will sample until it accepts it as a valid touch
|
# which the function will sample until it accepts it as a valid touch
|
||||||
# margin: Difference from mean centre at which touches are considered at the same position
|
# margin: Difference from mean centre at which touches are considered at the same position
|
||||||
|
# delay: Delay between samples in ms.
|
||||||
#
|
#
|
||||||
def touch_parameter(self, confidence = 5, margin = 50, calibration = None):
|
def touch_parameter(self, confidence = 5, margin = 50, delay = 10, calibration = None):
|
||||||
confidence = max(min(confidence, 25), 5)
|
if not self.asynchronous: # Ignore attempts to change on the fly.
|
||||||
margin = max(min(margin, 100), 1)
|
confidence = max(min(confidence, 25), 5)
|
||||||
m = margin * margin
|
if confidence != self.buf_length:
|
||||||
if confidence != len(self.buff):
|
self.buff = [[0,0] for x in range(confidence)]
|
||||||
self.buff = [[-m, -m] for x in range(confidence)] # impossible values
|
self.buf_length = confidence
|
||||||
self.margin = margin * margin # store the square value
|
self.delay = max(min(delay, 100), 5)
|
||||||
if calibration:
|
margin = max(min(margin, 100), 1)
|
||||||
self.calibration = calibration
|
self.margin = margin * margin # store the square value
|
||||||
#
|
if calibration:
|
||||||
# get_touch(): get a touch value; Parameters:
|
self.calibration = calibration
|
||||||
|
|
||||||
|
# get_touch(): Synchronous use. get a touch value; Parameters:
|
||||||
#
|
#
|
||||||
# initital: Wait for a non-touch state before getting a sample.
|
# initital: Wait for a non-touch state before getting a sample.
|
||||||
# True = Initial wait for a non-touch state
|
# True = Initial wait for a non-touch state
|
||||||
|
@ -114,11 +119,57 @@ class TOUCH:
|
||||||
# True: Wait until a touch is pressed.
|
# True: Wait until a touch is pressed.
|
||||||
# raw: Setting whether raw touch coordinates (True) or normalized ones (False) are returned
|
# raw: Setting whether raw touch coordinates (True) or normalized ones (False) are returned
|
||||||
# setting the calibration vector to (0, 1, 0, 1, 0, 1, 0, 1) result in a identity mapping
|
# setting the calibration vector to (0, 1, 0, 1, 0, 1, 0, 1) result in a identity mapping
|
||||||
|
# timeout: Longest time (ms, or None = 1 hr) to wait for a touch or release
|
||||||
# updates self.position
|
#
|
||||||
def main_thread(self):
|
# Return (x,y) or None
|
||||||
|
#
|
||||||
|
def get_touch(self, initial = True, wait = True, raw = False, timeout = None):
|
||||||
|
if self.asynchronous:
|
||||||
|
return None # Should only be called in synhronous mode
|
||||||
|
if timeout == None:
|
||||||
|
timeout = 3600000 # set timeout to 1 hour
|
||||||
|
#
|
||||||
|
if initial: ## wait for a non-touch state
|
||||||
|
sample = True
|
||||||
|
while sample and timeout > 0:
|
||||||
|
sample = self.raw_touch()
|
||||||
|
pyb.delay(self.delay)
|
||||||
|
timeout -= self.delay
|
||||||
|
if timeout <= 0: # after timeout, return None
|
||||||
|
return None
|
||||||
|
#
|
||||||
buff = self.buff
|
buff = self.buff
|
||||||
buf_length = len(buff)
|
buf_length = self.buf_length
|
||||||
|
buffptr = 0
|
||||||
|
nsamples = 0
|
||||||
|
while timeout > 0:
|
||||||
|
if nsamples == buf_length:
|
||||||
|
meanx = sum([c[0] for c in buff]) // buf_length
|
||||||
|
meany = sum([c[1] for c in buff]) // buf_length
|
||||||
|
dev = sum([(c[0] - meanx)**2 + (c[1] - meany)**2 for c in buff]) / buf_length
|
||||||
|
if dev <= self.margin: # got one; compare against the square value
|
||||||
|
if raw:
|
||||||
|
return (meanx, meany)
|
||||||
|
else:
|
||||||
|
return self.do_normalize((meanx, meany))
|
||||||
|
# get a new value
|
||||||
|
sample = self.raw_touch() # get a touch
|
||||||
|
if sample == None:
|
||||||
|
if not wait:
|
||||||
|
return None
|
||||||
|
nsamples = 0 # Invalidate buff
|
||||||
|
else:
|
||||||
|
buff[buffptr] = sample # put in buff
|
||||||
|
buffptr = (buffptr + 1) % buf_length
|
||||||
|
nsamples = min(nsamples +1, buf_length)
|
||||||
|
pyb.delay(self.delay)
|
||||||
|
timeout -= self.delay
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Asynchronous use: this thread maintains self.x and self.y
|
||||||
|
def _main_thread(self):
|
||||||
|
buff = self.buff
|
||||||
|
buf_length = self.buf_length
|
||||||
buffptr = 0
|
buffptr = 0
|
||||||
nsamples = 0
|
nsamples = 0
|
||||||
yield # Initialisation complete, wait for scheduler to start
|
yield # Initialisation complete, wait for scheduler to start
|
||||||
|
@ -129,11 +180,7 @@ class TOUCH:
|
||||||
dev = sum([(c[0] - meanx)**2 + (c[1] - meany)**2 for c in buff]) / buf_length
|
dev = sum([(c[0] - meanx)**2 + (c[1] - meany)**2 for c in buff]) / buf_length
|
||||||
if dev <= self.margin: # got one; compare against the square value
|
if dev <= self.margin: # got one; compare against the square value
|
||||||
self.ready = True
|
self.ready = True
|
||||||
if self.raw:
|
self.x, self.y = self.do_normalize((meanx, meany))
|
||||||
self.position[0] = meanx
|
|
||||||
self.position[1] = meany
|
|
||||||
else:
|
|
||||||
self.do_normalize((meanx, meany))
|
|
||||||
sample = self.raw_touch() # get a touch
|
sample = self.raw_touch() # get a touch
|
||||||
if sample == None:
|
if sample == None:
|
||||||
self.touched = False
|
self.touched = False
|
||||||
|
@ -143,13 +190,14 @@ class TOUCH:
|
||||||
self.touched = True
|
self.touched = True
|
||||||
buff[buffptr] = sample # put in buff
|
buff[buffptr] = sample # put in buff
|
||||||
buffptr = (buffptr + 1) % buf_length
|
buffptr = (buffptr + 1) % buf_length
|
||||||
nsamples = min(nsamples +1, buf_length)
|
nsamples = min(nsamples + 1, buf_length)
|
||||||
yield
|
yield
|
||||||
|
|
||||||
def get_touch(self):
|
# Asynchronous get_touch
|
||||||
|
def get_touch_async(self):
|
||||||
if self.ready:
|
if self.ready:
|
||||||
self.ready = False
|
self.ready = False
|
||||||
return self.position
|
return self.x, self.y
|
||||||
return None
|
return None
|
||||||
#
|
#
|
||||||
# do_normalize(touch)
|
# do_normalize(touch)
|
||||||
|
@ -161,9 +209,9 @@ class TOUCH:
|
||||||
xadd = self.calibration[2] + (self.calibration[0] - self.calibration[2]) * (touch[1] / 4096)
|
xadd = self.calibration[2] + (self.calibration[0] - self.calibration[2]) * (touch[1] / 4096)
|
||||||
ymul = self.calibration[7] + (self.calibration[5] - self.calibration[7]) * (touch[0] / 4096)
|
ymul = self.calibration[7] + (self.calibration[5] - self.calibration[7]) * (touch[0] / 4096)
|
||||||
yadd = self.calibration[6] + (self.calibration[4] - self.calibration[6]) * (touch[0] / 4096)
|
yadd = self.calibration[6] + (self.calibration[4] - self.calibration[6]) * (touch[0] / 4096)
|
||||||
self.position[0] = int((touch[0] + xadd) * xmul)
|
x = int((touch[0] + xadd) * xmul)
|
||||||
self.position[1] = int((touch[1] + yadd) * ymul)
|
y = int((touch[1] + yadd) * ymul)
|
||||||
|
return (x, y)
|
||||||
#
|
#
|
||||||
# raw_touch(tuple)
|
# raw_touch(tuple)
|
||||||
# raw read touch. Returns (x,y) or None
|
# raw read touch. Returns (x,y) or None
|
|
@ -28,7 +28,7 @@ class touchable(object):
|
||||||
while True:
|
while True:
|
||||||
yield
|
yield
|
||||||
if mytouch.ready:
|
if mytouch.ready:
|
||||||
x, y = mytouch.get_touch()
|
x, y = mytouch.get_touch_async()
|
||||||
for obj in cls.touchlist:
|
for obj in cls.touchlist:
|
||||||
if obj.enabled:
|
if obj.enabled:
|
||||||
obj.touched(x, y)
|
obj.touched(x, y)
|
||||||
|
|
Ładowanie…
Reference in New Issue