asynctouch.py replaced by generic version of touch.py

pull/7/head
Peter Hinch 2016-04-23 11:35:03 +01:00
rodzic 702485d288
commit d2f4e9e79b
4 zmienionych plików z 97 dodań i 49 usunięć

Wyświetl plik

@ -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

Wyświetl plik

@ -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)

Wyświetl plik

@ -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
# 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
# margin: Difference from mean centre at which touches are considered at the same position
# delay: Delay between samples in ms. (n/a if asynchronous)
# #
def __init__(self, objsched, controller = "XPT2046", calibration = None, raw = False): DEFAULT_CAL = (-3917, -0.127, -3923, -0.1267, -3799, -0.07572, -3738, -0.07814)
self.raw = raw 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):
if not self.asynchronous: # Ignore attempts to change on the fly.
confidence = max(min(confidence, 25), 5) confidence = max(min(confidence, 25), 5)
if confidence != self.buf_length:
self.buff = [[0,0] for x in range(confidence)]
self.buf_length = confidence
self.delay = max(min(delay, 100), 5)
margin = max(min(margin, 100), 1) margin = max(min(margin, 100), 1)
m = margin * margin
if confidence != len(self.buff):
self.buff = [[-m, -m] for x in range(confidence)] # impossible values
self.margin = margin * margin # store the square value self.margin = margin * margin # store the square value
if calibration: if calibration:
self.calibration = calibration self.calibration = calibration
#
# get_touch(): get a touch value; Parameters: # 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

Wyświetl plik

@ -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)