Skip to content

Commit 9d7c7e3

Browse files
author
Dozen Crows
committed
Switched to separate states for input handling and IR sending
1 parent 998f422 commit 9d7c7e3

File tree

3 files changed

+76
-60
lines changed

3 files changed

+76
-60
lines changed

IR.py

+2-21
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,11 @@
11
import socket
2-
import threading
3-
import Queue
42

53
LIRCD_ADDRESS = "/var/run/lirc/lircd"
6-
message_queue = Queue.Queue()
7-
ir_thread = None
84

95
def init():
10-
global message_queue, ir_thread
11-
ir_thread = threading.Thread(target=ir_thread_queue_handler, args=(message_queue,))
12-
ir_thread.start()
136
print "IR initialised"
147

158
def deinit():
16-
global message_queue, ir_thread
17-
message_queue.put("QUIT")
18-
ir_thread.join()
199
print "IR deinitialised"
2010

2111
def send_ir(message):
@@ -32,15 +22,6 @@ def send_ir(message):
3222
lircd_socket_file.close()
3323
lircd_socket.shutdown(socket.SHUT_RDWR)
3424
lircd_socket.close()
35-
36-
def ir_thread_queue_handler(queue):
37-
while True:
38-
msg = queue.get()
39-
if msg != 'QUIT':
40-
send_ir(msg)
41-
else:
42-
break
43-
25+
4426
def send_once(message):
45-
global message_queue
46-
message_queue.put('SEND_ONCE ' + message)
27+
send_ir('SEND_ONCE ' + message)

PyGameInterface.py

+53-39
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ def __getattr__(self, attr):
3333
BUTTON_COLUMN_WIDTH = (SCREEN_WIDTH / BUTTON_COLUMNS)
3434
BUTTON_ROW_HEIGHT = (SCREEN_HEIGHT / BUTTON_ROWS)
3535

36-
BOUNCE_LIMIT = 3
36+
BUTTON_TIMEOUT = 0.3
3737

3838
test_button_layout = [
3939
dotdict({ 'x':0, 'y':0, 'width':2, 'height':1, 'text':"Power", 'code':"RM-ED050-12 KEY_POWER;Phillips-HTS KEY_POWER" }),
@@ -90,6 +90,17 @@ def render_current_button(self):
9090
self.dirty_rect.union_ip(self.current_button)
9191
self.current_button.render(self.screen)
9292

93+
def release_current_button(self):
94+
self.current_button.highlight(False)
95+
self.render_current_button()
96+
self.current_button = None
97+
98+
def update_display(self):
99+
if self.display_dirty:
100+
pygame.display.update(self.dirty_rect)
101+
self.display_dirty = False
102+
self.dirty_rect.inflate_ip(-self.dirty_rect.w, -self.dirty_rect.h)
103+
93104
def run(self):
94105
signal.signal(signal.SIGTERM, signal_handler)
95106
signal.signal(signal.SIGINT, signal_handler)
@@ -113,49 +124,52 @@ def run(self):
113124

114125
self.display_dirty = False
115126
self.current_button = None
116-
self.loop_count = 0
117127
self.dirty_rect = pygame.Rect(0, 0, 0, 0)
118128

119129
while running:
120-
self.loop_count += 1
121-
if self.display_dirty:
122-
pygame.display.update(self.dirty_rect)
123-
self.display_dirty = False
124-
self.dirty_rect.inflate_ip(-self.dirty_rect.w, -self.dirty_rect.h)
125-
126-
# Can't use pygame.event.wait() as this blocks signals
127-
time.sleep(0.008)
128-
event = pygame.event.poll()
129130

130-
while event.type != pygame.NOEVENT:
131-
if event.type == pygame.MOUSEBUTTONDOWN and self.current_button == None:
132-
#print self.loop_count,":",event
133-
for button in self.buttons:
134-
if button.hit_test(event.pos):
135-
self.current_button = button
136-
button.highlight(True)
137-
self.render_current_button()
138-
self.send_ir(self.current_button.code)
139-
break
140-
141-
if event.type == pygame.MOUSEMOTION and self.current_button:
142-
if not self.current_button.hit_test(event.pos):
143-
#print self.loop_count,":",event
144-
self.current_button.highlight(False)
145-
self.render_current_button()
146-
self.current_button = None
147-
148-
if event.type == pygame.MOUSEBUTTONUP:
149-
#print self.loop_count,":",event
150-
if self.current_button:
151-
self.current_button.highlight(False)
152-
self.render_current_button()
153-
self.current_button = None
154-
155-
if event.type == pygame.QUIT:
156-
running = False
157-
131+
waiting_for_input = True
132+
133+
while running and waiting_for_input:
134+
self.update_display()
135+
136+
# Can't use pygame.event.wait() as this blocks signals
137+
time.sleep(0.008)
158138
event = pygame.event.poll()
139+
140+
while event.type != pygame.NOEVENT:
141+
if event.type == pygame.MOUSEBUTTONDOWN and self.current_button == None:
142+
for button in self.buttons:
143+
if button.hit_test(event.pos):
144+
self.current_button = button
145+
button.highlight(True)
146+
self.render_current_button()
147+
self.press_time = time.time()
148+
waiting_for_input = False
149+
pygame.event.clear()
150+
break
151+
152+
if event.type == pygame.MOUSEBUTTONUP and self.current_button:
153+
self.release_current_button()
154+
155+
if event.type == pygame.MOUSEMOTION and self.current_button:
156+
if not self.current_button.hit_test(event.pos):
157+
self.release_current_button()
158+
159+
if event.type == pygame.QUIT:
160+
running = False
161+
162+
event = pygame.event.poll()
163+
164+
if self.current_button and time.time() - self.press_time > BUTTON_TIMEOUT:
165+
self.release_current_button()
166+
167+
if not waiting_for_input:
168+
self.update_display()
169+
pygame.event.set_blocked([pygame.MOUSEBUTTONDOWN, pygame.MOUSEBUTTONUP, pygame.MOUSEMOTION])
170+
self.send_ir(self.current_button.code)
171+
time.sleep(0.1)
172+
pygame.event.set_allowed([pygame.MOUSEBUTTONDOWN, pygame.MOUSEBUTTONUP, pygame.MOUSEMOTION])
159173

160174
IR.deinit()
161175

plan.txt

+21
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,27 @@ socket in PyMony code.
4848
Results:
4949
- This worked, but didn't alleviate the bouncing/repeating issue
5050
- Not sending IR keeps the UI nice and stable, without bouncing
51+
- Wrote a test C++ app to try sending IR regularly and use SDL to read touchscreen - same bounce issue
52+
- Modified the C++ app to directly read touchscreen via tslib and not SDL - same bounce issue
53+
- Investigated lirc_rpi driver source and touchscreen source (stmpe_ts.c):
54+
- http://harctoolbox.org/downloads/lirc_rpi.c
55+
- http://lxr.free-electrons.com/source/drivers/input/touchscreen/stmpe-ts.c
56+
- lirc_rpi uses bitbanging on gpio port to generate output waveform, and uses a kernel spinlock with
57+
interrupts disabled when sending an entire code - this can be at least 75ms for a 12 bit Sony IR
58+
code (2 repeats with delay between).
59+
- stmpe_ts uses an IRQ to read data from the touchscreen, and also schedules a 'delayed work' timeout
60+
callback which sets a 'no touch' after kernel HZ / 50 delay (which will be about 20ms)
61+
- hypothesis is that the disable interrupt period can cause the touchscreen to timeout and generate
62+
'no touch' events as a result, leading to the bouncing observed.
63+
- Rewrote Python app main loop to separate input reading and IR sending:
64+
- Input event handling loop runs until a button press is detected
65+
- Then any further events are flushed, touch screen events are disabled
66+
- Then IR codes are sent, and a 100ms delay occurs
67+
- Then touch screen events are enabled and loop back to input event handling
68+
- current button is still set to avoid repeats
69+
- This doesn't bounce...
70+
- Seems fairly responsive
71+
- Doesn't repeat send; but could be added
5172

5273
Phase 5 - Devices
5374
=================

0 commit comments

Comments
 (0)