128 lines
4.3 KiB
Python
128 lines
4.3 KiB
Python
import subprocess
|
|
import time
|
|
import threading
|
|
import runtime.whisplay_client
|
|
|
|
|
|
class WhisplayInterface:
|
|
LONG_PRESS_THRESHOLD = 0.5
|
|
DOUBLE_PRESS_THRESHOLD = 0.3
|
|
|
|
def __init__(self):
|
|
self.board = None
|
|
self._lock = threading.Lock()
|
|
self._button_press_start = None
|
|
self._button_press_end = None
|
|
self._button_is_pressed = False
|
|
self._button_was_pressed = False
|
|
self._button_is_long_pressed = False
|
|
self._button_was_long_pressed = False
|
|
self._button_was_double_pressed = False
|
|
|
|
# Edge-detection state
|
|
self._prev_is_pressed = False
|
|
self._prev_press_end = None
|
|
|
|
self.set_wm8960_volume_stable(speaker=250, mic=30)
|
|
|
|
# -- Properties --
|
|
|
|
@property
|
|
def is_pressed(self):
|
|
return self._button_is_pressed
|
|
|
|
@property
|
|
def was_pressed(self):
|
|
return self._button_was_pressed
|
|
|
|
@property
|
|
def is_long_pressed(self):
|
|
return self._button_is_long_pressed
|
|
|
|
@property
|
|
def was_long_pressed(self):
|
|
return self._button_was_long_pressed
|
|
|
|
@property
|
|
def was_double_pressed(self):
|
|
return self._button_was_double_pressed
|
|
|
|
@property
|
|
def press_duration(self):
|
|
if self._button_press_start is None:
|
|
return 0.0
|
|
end = self._button_press_end if self._button_press_end is not None else time.time()
|
|
return end - self._button_press_start
|
|
|
|
# -- Attachment --
|
|
|
|
def create_board(self,
|
|
app_id,
|
|
display_name,
|
|
icon,
|
|
use_daemon_default_log=True):
|
|
self.board = runtime.whisplay_client.create_whisplay_hardware(app_id=app_id, display_name=display_name, icon=icon, use_daemon_default_log=use_daemon_default_log)
|
|
self.board.on_button_press(self._on_button_press)
|
|
self.board.on_button_release(self._on_button_release)
|
|
|
|
# -- Internal press/release (called from GPIO thread) --
|
|
|
|
def _on_button_press(self):
|
|
with self._lock:
|
|
self._button_is_pressed = True
|
|
self._button_press_start = time.time()
|
|
|
|
def _on_button_release(self):
|
|
with self._lock:
|
|
self._button_is_pressed = False
|
|
self._button_press_end = time.time()
|
|
|
|
# -- Polled update (called from gesture thread) --
|
|
|
|
def update_gestures(self):
|
|
self._button_was_pressed = False
|
|
self._button_was_long_pressed = False
|
|
self._button_was_double_pressed = False
|
|
|
|
with self._lock:
|
|
is_pressed = self._button_is_pressed
|
|
press_start = self._button_press_start
|
|
press_end = self._button_press_end
|
|
|
|
now = time.time()
|
|
|
|
# Press edge: transitioned from not-pressed to pressed
|
|
if not self._prev_is_pressed and is_pressed:
|
|
if self._prev_press_end is not None and press_start is not None:
|
|
gap = press_start - self._prev_press_end
|
|
if gap < WhisplayInterface.DOUBLE_PRESS_THRESHOLD:
|
|
self._button_was_double_pressed = True
|
|
|
|
# Release edge: transitioned from pressed to not-pressed
|
|
if self._prev_is_pressed and not is_pressed:
|
|
self._button_was_pressed = True
|
|
if press_start is not None and press_end is not None:
|
|
duration = press_end - press_start
|
|
if duration >= WhisplayInterface.LONG_PRESS_THRESHOLD:
|
|
self._button_was_long_pressed = True
|
|
self._prev_press_end = press_end
|
|
|
|
# Level flag: currently held past threshold
|
|
if is_pressed and press_start is not None:
|
|
self._button_is_long_pressed = (now - press_start) >= WhisplayInterface.LONG_PRESS_THRESHOLD
|
|
else:
|
|
self._button_is_long_pressed = False
|
|
|
|
self._prev_is_pressed = is_pressed
|
|
|
|
def set_wm8960_volume_stable(self, speaker: int = 0, mic: int = 0):
|
|
CARD_NAME = 'wm8960soundcard'
|
|
DEVICE_ARG = f'hw:{CARD_NAME}'
|
|
try:
|
|
subprocess.run(['amixer', '-D', DEVICE_ARG, 'sset', 'Speaker',
|
|
str(speaker)], check=False, capture_output=True)
|
|
subprocess.run(['amixer', '-D', DEVICE_ARG, 'sset',
|
|
'Capture', str(mic)], check=False, capture_output=True)
|
|
except Exception as e:
|
|
print(f"ERROR: Failed to set volume: {e}")
|