Skip to content

Commit 4bbe81f

Browse files
Synchronize qemu with t-display-s3
1 parent 9f041f0 commit 4bbe81f

1 file changed

Lines changed: 122 additions & 42 deletions

File tree

  • internal_filesystem/lib/mpos/board

internal_filesystem/lib/mpos/board/qemu.py

Lines changed: 122 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
data5=46,
2020
data6=47,
2121
data7=48,
22-
reverse_color_bits=False # doesnt seem to do anything?
22+
#reverse_color_bits=False # doesnt seem to do anything?
2323
)
2424
except Exception as e:
2525
print(f"Error initializing display bus: {e}")
@@ -31,91 +31,171 @@
3131
fb1 = display_bus.allocate_framebuffer(_BUFFER_SIZE, lcd_bus.MEMORY_INTERNAL | lcd_bus.MEMORY_DMA)
3232
fb2 = display_bus.allocate_framebuffer(_BUFFER_SIZE, lcd_bus.MEMORY_INTERNAL | lcd_bus.MEMORY_DMA)
3333

34-
import mpos.ui
3534
import drivers.display.st7789 as st7789
36-
# 320x200 => make 320x240 screenshot => it's 240x200 (but the display shows more than 200)
35+
import mpos.ui
3736
mpos.ui.main_display = st7789.ST7789(
3837
data_bus=display_bus,
3938
frame_buffer1=fb1,
4039
frame_buffer2=fb2,
4140
display_width=170,
4241
display_height=320,
43-
color_space=lv.COLOR_FORMAT.RGB565,
42+
color_space=lv.COLOR_FORMAT.RGB565, # gives bad colors
43+
#color_space=lv.COLOR_FORMAT.RGB888, # not supported by qemu
4444
color_byte_order=st7789.BYTE_ORDER_RGB,
4545
# rgb565_byte_swap=False, # always False is data_bus.get_lane_count() == 8
46+
power_pin=9, # Must set RD pin to high, otherwise blank screen as soon as LVGL's task_handler starts
4647
reset_pin=5,
47-
backlight_pin=38,
48+
reset_state=st7789.STATE_LOW, # needs low: high will not enable the display
49+
backlight_pin=38, # needed
4850
backlight_on_state=st7789.STATE_PWM,
51+
offset_x=0,
52+
offset_y=35
4953
)
54+
mpos.ui.main_display.set_power(True) # set RD pin to high before the rest, otherwise garbled output
5055
mpos.ui.main_display.init()
51-
mpos.ui.main_display.set_power(True)
52-
mpos.ui.main_display.set_backlight(100)
56+
mpos.ui.main_display.set_backlight(100) # works
5357

5458
lv.init()
55-
#mpos.ui.main_display.set_rotation(lv.DISPLAY_ROTATION._90) # must be done after initializing display and creating the touch drivers, to ensure proper handling
56-
mpos.ui.main_display.set_color_inversion(True) # doesnt seem to do anything?
59+
mpos.ui.main_display.set_rotation(lv.DISPLAY_ROTATION._270) # must be done after initializing display and creating the touch drivers, to ensure proper handling
60+
mpos.ui.main_display.set_color_inversion(True)
61+
5762

5863
# Button handling code:
5964
from machine import Pin
60-
btn_a = Pin(0, Pin.IN, Pin.PULL_UP) # 1
61-
btn_b = Pin(14, Pin.IN, Pin.PULL_UP) # 2
62-
btn_c = Pin(3, Pin.IN, Pin.PULL_UP) # 3
65+
btn_a = Pin(0, Pin.IN, Pin.PULL_UP)
66+
btn_b = Pin(14, Pin.IN, Pin.PULL_UP)
6367

6468
# Key repeat configuration
6569
# This whole debounce logic is only necessary because LVGL 9.2.2 seems to have an issue where
6670
# the lv_keyboard widget doesn't handle PRESSING (long presses) properly, it loses focus.
6771
REPEAT_INITIAL_DELAY_MS = 300 # Delay before first repeat
6872
REPEAT_RATE_MS = 100 # Interval between repeats
73+
REPEAT_PREV_BECOMES_BACK = 700 # Long previous press becomes back button
74+
COMBO_GRACE_MS = 60 # Accept near-simultaneous A+B as ENTER
6975
last_key = None
7076
last_state = lv.INDEV_STATE.RELEASED
71-
#key_press_start = 0 # Time when key was first pressed
72-
#last_repeat_time = 0 # Time of last repeat event
77+
key_press_start = 0 # Time when key was first pressed
78+
last_repeat_time = 0 # Time of last repeat event
79+
last_a_down_time = 0
80+
last_b_down_time = 0
81+
last_a_pressed = False
82+
last_b_pressed = False
7383

7484
# Read callback
7585
# Warning: This gets called several times per second, and if it outputs continuous debugging on the serial line,
7686
# that will break tools like mpremote from working properly to upload new files over the serial line, thus needing a reflash.
7787
def keypad_read_cb(indev, data):
78-
global last_key, last_state #, key_press_start, last_repeat_time
79-
since_last_repeat = 0
88+
global last_key, last_state, key_press_start, last_repeat_time, last_a_down_time, last_b_down_time
89+
global last_a_pressed, last_b_pressed
8090

8191
# Check buttons
82-
current_key = None
8392
current_time = time.ticks_ms()
84-
if btn_a.value() == 0:
85-
current_key = lv.KEY.PREV
86-
elif btn_b.value() == 0:
93+
btn_a_pressed = btn_a.value() == 0
94+
btn_b_pressed = btn_b.value() == 0
95+
if btn_a_pressed and not last_a_pressed:
96+
last_a_down_time = current_time
97+
if btn_b_pressed and not last_b_pressed:
98+
last_b_down_time = current_time
99+
last_a_pressed = btn_a_pressed
100+
last_b_pressed = btn_b_pressed
101+
102+
near_simul = False
103+
if btn_a_pressed and btn_b_pressed:
104+
near_simul = True
105+
elif btn_a_pressed and last_b_down_time and time.ticks_diff(current_time, last_b_down_time) <= COMBO_GRACE_MS:
106+
near_simul = True
107+
elif btn_b_pressed and last_a_down_time and time.ticks_diff(current_time, last_a_down_time) <= COMBO_GRACE_MS:
108+
near_simul = True
109+
110+
single_press_wait = False
111+
if btn_a_pressed ^ btn_b_pressed:
112+
if btn_a_pressed and time.ticks_diff(current_time, last_a_down_time) < COMBO_GRACE_MS:
113+
single_press_wait = True
114+
elif btn_b_pressed and time.ticks_diff(current_time, last_b_down_time) < COMBO_GRACE_MS:
115+
single_press_wait = True
116+
117+
if near_simul or single_press_wait:
118+
dt_a = time.ticks_diff(current_time, last_a_down_time) if last_a_down_time else None
119+
dt_b = time.ticks_diff(current_time, last_b_down_time) if last_b_down_time else None
120+
print(f"combo guard: a={btn_a_pressed} b={btn_b_pressed} near={near_simul} wait={single_press_wait} dt_a={dt_a} dt_b={dt_b}")
121+
122+
# While in an on-screen keyboard, PREV button is LEFT and NEXT button is RIGHT
123+
focus_group = lv.group_get_default()
124+
focus_keyboard = False
125+
if focus_group:
126+
current_focused = focus_group.get_focused()
127+
if isinstance(current_focused, lv.keyboard):
128+
#print("focus is on a keyboard")
129+
focus_keyboard = True
130+
131+
if near_simul:
87132
current_key = lv.KEY.ENTER
88-
elif btn_c.value() == 0:
89-
current_key = lv.KEY.NEXT
90-
91-
if (btn_a.value() == 0) and (btn_c.value() == 0):
92-
current_key = lv.KEY.ESC
93-
94-
if current_key:
95-
if current_key != last_key:
96-
# New key press
97-
data.key = current_key
98-
data.state = lv.INDEV_STATE.PRESSED
99-
last_key = data.key
100-
last_state = data.state
101-
#key_press_start = current_time
102-
#last_repeat_time = current_time
133+
elif single_press_wait:
134+
current_key = None
135+
elif btn_a_pressed:
136+
if focus_keyboard:
137+
current_key = lv.KEY.LEFT
103138
else:
104-
print(f"should {current_key} be repeated?")
139+
current_key = lv.KEY.PREV
140+
elif btn_b_pressed:
141+
if focus_keyboard:
142+
current_key = lv.KEY.RIGHT
143+
else:
144+
current_key = lv.KEY.NEXT
105145
else:
146+
current_key = None
147+
148+
if current_key is None:
106149
# No key pressed
107-
data.key = last_key if last_key else lv.KEY.ENTER
150+
data.key = last_key if last_key else -1
108151
data.state = lv.INDEV_STATE.RELEASED
109152
last_key = None
110-
last_state = data.state
111-
#key_press_start = 0
112-
#last_repeat_time = 0
153+
last_state = lv.INDEV_STATE.RELEASED
154+
key_press_start = 0
155+
last_repeat_time = 0
156+
elif last_key is None or current_key != last_key:
157+
print(f"New key press: {current_key}")
158+
data.key = current_key
159+
data.state = lv.INDEV_STATE.PRESSED
160+
last_key = current_key
161+
last_state = lv.INDEV_STATE.PRESSED
162+
key_press_start = current_time
163+
last_repeat_time = current_time
164+
else:
165+
print(f"key repeat because current_key {current_key} == last_key {last_key}")
166+
elapsed = time.ticks_diff(current_time, key_press_start)
167+
since_last_repeat = time.ticks_diff(current_time, last_repeat_time)
168+
if elapsed >= REPEAT_INITIAL_DELAY_MS and since_last_repeat >= REPEAT_RATE_MS:
169+
next_state = lv.INDEV_STATE.PRESSED if last_state == lv.INDEV_STATE.RELEASED else lv.INDEV_STATE.RELEASED
170+
if current_key == lv.KEY.PREV:
171+
print("Repeated PREV does not do anything, instead it triggers ESC (back) if long enough")
172+
if since_last_repeat > REPEAT_PREV_BECOMES_BACK:
173+
print("back button trigger!")
174+
data.key = lv.KEY.ESC
175+
data.state = next_state
176+
last_key = current_key
177+
last_state = data.state
178+
last_repeat_time = current_time
179+
else:
180+
print("repeat PREV ignored because not pressed long enough")
181+
else:
182+
print("Send a new PRESSED/RELEASED pair for repeat")
183+
data.key = current_key
184+
data.state = next_state
185+
last_key = current_key
186+
last_state = data.state
187+
last_repeat_time = current_time
188+
else:
189+
# This doesn't seem to make the key navigation in on-screen keyboards work, unlike on the m5stack_fire...?
190+
#print("No repeat yet, send RELEASED to avoid PRESSING, which breaks keyboard navigation...")
191+
data.state = lv.INDEV_STATE.RELEASED
192+
last_state = lv.INDEV_STATE.RELEASED
113193

114194
# Handle ESC for back navigation (only on initial PRESSED)
115195
if data.state == lv.INDEV_STATE.PRESSED and data.key == lv.KEY.ESC:
116196
mpos.ui.back_screen()
117197

118-
198+
'''
119199
group = lv.group_create()
120200
group.set_default()
121201
@@ -129,5 +209,5 @@ def keypad_read_cb(indev, data):
129209
indev.enable(True) # NOQA
130210
from mpos import InputManager
131211
InputManager.register_indev(indev)
132-
212+
'''
133213
print("qemu.py finished")

0 commit comments

Comments
 (0)