PTT for whisplay
This commit is contained in:
@@ -28,14 +28,27 @@ Single-file Python application for managing LXST Channel connections via Reticul
|
|||||||
|
|
||||||
## Whisplay GUI Controls
|
## Whisplay GUI Controls
|
||||||
|
|
||||||
|
### Channel list (STATE_READY)
|
||||||
|
|
||||||
Short press (<1s) Cycle to next channel in list
|
Short press (<1s) Cycle to next channel in list
|
||||||
Long press (>=1s) Call the selected channel
|
Long press (>=1s) Call the selected channel
|
||||||
Press (while in call) Hang up
|
|
||||||
|
|
||||||
RGB LED indicates state:
|
### In call (STATE_IN_CALL) — Push-to-Talk mode (default)
|
||||||
|
|
||||||
|
Press & hold Talk (unmute microphone)
|
||||||
|
Release Stop talking (mute microphone)
|
||||||
|
Double-press Toggle to always-on mode
|
||||||
|
|
||||||
|
### In call — Always-on mode (toggled)
|
||||||
|
|
||||||
|
Press Hang up
|
||||||
|
Double-press Toggle to push-to-talk mode
|
||||||
|
|
||||||
|
### RGB LED indicates state:
|
||||||
Blue = ready, showing channels
|
Blue = ready, showing channels
|
||||||
Orange = calling
|
Orange = calling
|
||||||
Green = in call
|
Green = in call
|
||||||
|
Yellow = transmitting (PTT mode, mic active)
|
||||||
|
|
||||||
## Initial Setup Order
|
## Initial Setup Order
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ if _WHISPLAY_AVAILABLE:
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
LONG_PRESS_THRESHOLD = 1.0
|
LONG_PRESS_THRESHOLD = 1.0
|
||||||
|
DOUBLE_PRESS_THRESHOLD = 0.4
|
||||||
|
|
||||||
|
|
||||||
class Terminal:
|
class Terminal:
|
||||||
@@ -71,6 +72,10 @@ class ChannelClient:
|
|||||||
self.selected_index = 0
|
self.selected_index = 0
|
||||||
self._press_time = 0.0
|
self._press_time = 0.0
|
||||||
self._wm8960_device = None
|
self._wm8960_device = None
|
||||||
|
self._ptt_enabled = True
|
||||||
|
self._ptt_active = False
|
||||||
|
self._last_release_time = 0.0
|
||||||
|
self._double_pressed = False
|
||||||
if use_whisplay and _WHISPLAY_AVAILABLE and _HAS_PIL:
|
if use_whisplay and _WHISPLAY_AVAILABLE and _HAS_PIL:
|
||||||
try:
|
try:
|
||||||
self._init_whisplay()
|
self._init_whisplay()
|
||||||
@@ -304,8 +309,13 @@ class ChannelClient:
|
|||||||
lines = [f"Channel {self.selected_index + 1}"]
|
lines = [f"Channel {self.selected_index + 1}"]
|
||||||
if ch:
|
if ch:
|
||||||
lines.append(ch["hash"][:16] + "..")
|
lines.append(ch["hash"][:16] + "..")
|
||||||
lines += ["", "Press to hang up"]
|
if self._ptt_enabled:
|
||||||
fb = self._render("In Call", lines, accent=(60, 220, 120), footer="Press button to end")
|
lines += ["", "PTT: hold to talk", "Release to mute"]
|
||||||
|
footer = "Double-press: toggle"
|
||||||
|
else:
|
||||||
|
lines += ["", "Mic always-on", "Press to hang up"]
|
||||||
|
footer = "Double-press: toggle"
|
||||||
|
fb = self._render("In Call", lines, accent=(60, 220, 120), footer=footer)
|
||||||
self.board.draw_image(0, 0, self.board.LCD_WIDTH, self.board.LCD_HEIGHT, fb)
|
self.board.draw_image(0, 0, self.board.LCD_WIDTH, self.board.LCD_HEIGHT, fb)
|
||||||
|
|
||||||
def _show_status(self, title, detail="", accent=(255, 180, 60)):
|
def _show_status(self, title, detail="", accent=(255, 180, 60)):
|
||||||
@@ -317,14 +327,41 @@ class ChannelClient:
|
|||||||
|
|
||||||
def _on_button_press(self):
|
def _on_button_press(self):
|
||||||
self._press_time = time.time()
|
self._press_time = time.time()
|
||||||
|
if self.state == self.STATE_IN_CALL:
|
||||||
|
if time.time() - self._last_release_time < DOUBLE_PRESS_THRESHOLD:
|
||||||
|
self._double_pressed = True
|
||||||
|
self._ptt_enabled = not self._ptt_enabled
|
||||||
|
if self._ptt_enabled:
|
||||||
|
self.telephone.mute_transmit()
|
||||||
|
else:
|
||||||
|
self.telephone.unmute_transmit()
|
||||||
|
if self.board:
|
||||||
|
self._show_in_call()
|
||||||
|
return
|
||||||
|
if self._ptt_enabled:
|
||||||
|
self._ptt_active = True
|
||||||
|
self.telephone.unmute_transmit()
|
||||||
|
if self.board:
|
||||||
|
self.board.set_rgb(255, 255, 0)
|
||||||
|
|
||||||
def _on_button_release(self):
|
def _on_button_release(self):
|
||||||
elapsed = time.time() - self._press_time
|
self._last_release_time = time.time()
|
||||||
if self.state == self.STATE_IN_CALL:
|
if self.state == self.STATE_IN_CALL:
|
||||||
self.telephone.hangup()
|
if self._double_pressed:
|
||||||
return
|
self._double_pressed = False
|
||||||
|
return
|
||||||
|
if self._ptt_enabled:
|
||||||
|
self._ptt_active = False
|
||||||
|
self.telephone.mute_transmit()
|
||||||
|
if self.board:
|
||||||
|
self.board.set_rgb(0, 255, 80)
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
self.telephone.hangup()
|
||||||
|
return
|
||||||
if self.state != self.STATE_READY:
|
if self.state != self.STATE_READY:
|
||||||
return
|
return
|
||||||
|
elapsed = time.time() - self._press_time
|
||||||
if elapsed >= LONG_PRESS_THRESHOLD:
|
if elapsed >= LONG_PRESS_THRESHOLD:
|
||||||
if self.channels:
|
if self.channels:
|
||||||
self.board.set_rgb(255, 180, 0)
|
self.board.set_rgb(255, 180, 0)
|
||||||
@@ -457,6 +494,8 @@ class ChannelClient:
|
|||||||
f"\nCall established with "
|
f"\nCall established with "
|
||||||
f"{RNS.prettyhexrep(remote_identity.hash)}"
|
f"{RNS.prettyhexrep(remote_identity.hash)}"
|
||||||
)
|
)
|
||||||
|
if self._ptt_enabled:
|
||||||
|
self.telephone.mute_transmit()
|
||||||
if self.board:
|
if self.board:
|
||||||
self.board.set_rgb(0, 255, 80)
|
self.board.set_rgb(0, 255, 80)
|
||||||
self._show_in_call()
|
self._show_in_call()
|
||||||
@@ -465,6 +504,8 @@ class ChannelClient:
|
|||||||
was_in_call = self.state == self.STATE_IN_CALL
|
was_in_call = self.state == self.STATE_IN_CALL
|
||||||
was_calling = self.state == self.STATE_CALLING
|
was_calling = self.state == self.STATE_CALLING
|
||||||
self.state = self.STATE_READY
|
self.state = self.STATE_READY
|
||||||
|
self._ptt_active = False
|
||||||
|
self._double_pressed = False
|
||||||
if was_in_call:
|
if was_in_call:
|
||||||
print(f"\nCall ended")
|
print(f"\nCall ended")
|
||||||
elif was_calling:
|
elif was_calling:
|
||||||
|
|||||||
Reference in New Issue
Block a user