mirror of
https://github.com/armel/uv-k1-k5v3-firmware-custom.git
synced 2026-10-02 03:15:37 +00:00
Add long press
This commit is contained in:
1 parent
f072b3eb02
commit
a244a25513
4 files changed
+72
-46
No files matched your search
+31
-12
@@ -28,22 +28,37 @@ uint16_t gDebounceCounter = 0;
|
||||
bool gWasFKeyPressed = false;
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
|
||||
// Number of consecutive KEYBOARD_Poll() calls that return the injected key.
|
||||
// Must exceed key_debounce_10ms (typically 2) to pass the debounce gate in app.c.
|
||||
// After HOLD polls the key is cleared, which triggers a natural release cycle.
|
||||
#define SERIAL_KEY_HOLD_POLLS 5
|
||||
// Short press: hold key for SERIAL_KEY_SHORT_POLLS calls.
|
||||
// Must exceed key_debounce_10ms (2) to trigger ProcessKey(key, true, false).
|
||||
#define SERIAL_KEY_SHORT_POLLS 5
|
||||
|
||||
// Long press: hold key for SERIAL_KEY_LONG_POLLS calls.
|
||||
// Must exceed key_repeat_delay_10ms (40) to trigger ProcessKey(key, true, true).
|
||||
#define SERIAL_KEY_LONG_POLLS 45
|
||||
|
||||
volatile KEY_Code_t gKeyFromSerial = KEY_INVALID;
|
||||
static uint8_t gSerialKeyHoldCount = 0;
|
||||
static uint8_t gSerialKeyLong = 0; // 0 = short press, 1 = long press
|
||||
|
||||
// Inject a key received from serial (UART or VCP).
|
||||
// keyCode is the raw packet byte; validated against KEY_Code_e range before use.
|
||||
// Inject a short press from serial (UART or VCP).
|
||||
// KEY_PTT is explicitly blocked — PTT release cannot be guaranteed over serial.
|
||||
void KEYBOARD_InjectKey(uint8_t keyCode)
|
||||
{
|
||||
if (keyCode < KEY_INVALID && keyCode != KEY_PTT) {
|
||||
gKeyFromSerial = (KEY_Code_t)keyCode;
|
||||
gSerialKeyHoldCount = 0;
|
||||
gSerialKeyLong = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Inject a long press from serial (UART or VCP).
|
||||
// KEY_PTT is explicitly blocked — PTT release cannot be guaranteed over serial.
|
||||
void KEYBOARD_InjectKeyLong(uint8_t keyCode)
|
||||
{
|
||||
if (keyCode < KEY_INVALID && keyCode != KEY_PTT) {
|
||||
gKeyFromSerial = (KEY_Code_t)keyCode;
|
||||
gSerialKeyHoldCount = 0;
|
||||
gSerialKeyLong = 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -100,15 +115,19 @@ static const KEY_Code_t keyboard[5][4] = {
|
||||
KEY_Code_t KEYBOARD_Poll(void)
|
||||
{
|
||||
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
|
||||
// Serial-injected key: hold it for SERIAL_KEY_HOLD_POLLS consecutive calls
|
||||
// so the debounce counter in app.c has time to reach key_debounce_10ms.
|
||||
// Once the hold count is exhausted we clear it — the next call returns
|
||||
// KEY_INVALID, which triggers the release path in app.c naturally.
|
||||
// Serial-injected key: hold it for SHORT or LONG polls depending on press type,
|
||||
// so the debounce counter in app.c reaches the right threshold:
|
||||
// - Short: key_debounce_10ms (2) → ProcessKey(key, true, false)
|
||||
// - Long: key_repeat_delay_10ms (40) → ProcessKey(key, true, true)
|
||||
// Once the hold count is exhausted we clear it — next call returns KEY_INVALID,
|
||||
// which triggers the release path in app.c naturally.
|
||||
if (gKeyFromSerial != KEY_INVALID) {
|
||||
KEY_Code_t injected = gKeyFromSerial;
|
||||
if (++gSerialKeyHoldCount >= SERIAL_KEY_HOLD_POLLS) {
|
||||
KEY_Code_t injected = gKeyFromSerial;
|
||||
uint8_t threshold = gSerialKeyLong ? SERIAL_KEY_LONG_POLLS : SERIAL_KEY_SHORT_POLLS;
|
||||
if (++gSerialKeyHoldCount >= threshold) {
|
||||
gKeyFromSerial = KEY_INVALID;
|
||||
gSerialKeyHoldCount = 0;
|
||||
gSerialKeyLong = 0;
|
||||
}
|
||||
return injected;
|
||||
}
|
||||
|
||||
@@ -52,13 +52,13 @@ extern bool gWasFKeyPressed;
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
|
||||
// Serial-injected key (written by UART/VCP parser, consumed by KEYBOARD_Poll).
|
||||
// Held for SERIAL_KEY_HOLD_POLLS calls to satisfy the debounce logic in app.c.
|
||||
extern volatile KEY_Code_t gKeyFromSerial;
|
||||
|
||||
// Inject a key received from serial (UART or VCP), bypasses physical matrix.
|
||||
// keyCode is the raw byte from the serial packet — validated against KEY_Code_e range.
|
||||
// KEY_PTT is explicitly blocked — PTT release cannot be guaranteed over serial.
|
||||
// Inject a short press received from serial (UART or VCP).
|
||||
void KEYBOARD_InjectKey(uint8_t keyCode);
|
||||
|
||||
// Inject a long press received from serial (UART or VCP).
|
||||
void KEYBOARD_InjectKeyLong(uint8_t keyCode);
|
||||
#endif
|
||||
|
||||
KEY_Code_t KEYBOARD_Poll(void);
|
||||
|
||||
+13
-6
@@ -25,8 +25,9 @@
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
|
||||
#include "driver/keyboard.h"
|
||||
// Packet type for serial key injection (K5Viewer → radio)
|
||||
#define UART_TYPE_KEY 0x03
|
||||
// Packet types for serial key injection (K5Viewer → radio)
|
||||
#define UART_TYPE_KEY 0x03
|
||||
#define UART_TYPE_KEY_LONG 0x04
|
||||
#endif
|
||||
|
||||
#define USARTx USART1
|
||||
@@ -165,15 +166,17 @@ void UART_LogSend(const void *pBuffer, uint32_t Size)
|
||||
connected = true;
|
||||
}
|
||||
else if (b == 0xAA) {
|
||||
// Possible start of a key packet: 0xAA 0x55 0x03 <keycode>
|
||||
// Check if the next 3 bytes are available and match
|
||||
// Possible start of a key packet: 0xAA 0x55 <type> <keycode>
|
||||
// type 0x03 = short press, 0x04 = long press
|
||||
size_t i1 = (i + 1) % sizeof(UART_DMA_Buffer);
|
||||
size_t i2 = (i + 2) % sizeof(UART_DMA_Buffer);
|
||||
size_t i3 = (i + 3) % sizeof(UART_DMA_Buffer);
|
||||
|
||||
if (UART_DMA_Buffer[i1] == 0x55 &&
|
||||
UART_DMA_Buffer[i2] == UART_TYPE_KEY)
|
||||
(UART_DMA_Buffer[i2] == UART_TYPE_KEY ||
|
||||
UART_DMA_Buffer[i2] == UART_TYPE_KEY_LONG))
|
||||
{
|
||||
uint8_t type = UART_DMA_Buffer[i2];
|
||||
uint8_t keyCode = UART_DMA_Buffer[i3];
|
||||
|
||||
// Consume all 4 bytes
|
||||
@@ -182,7 +185,11 @@ void UART_LogSend(const void *pBuffer, uint32_t Size)
|
||||
UART_DMA_Buffer[i2] = 0x00;
|
||||
UART_DMA_Buffer[i3] = 0x00;
|
||||
|
||||
KEYBOARD_InjectKey(keyCode);
|
||||
if (type == UART_TYPE_KEY_LONG)
|
||||
KEYBOARD_InjectKeyLong(keyCode);
|
||||
else
|
||||
KEYBOARD_InjectKey(keyCode);
|
||||
|
||||
connected = true;
|
||||
}
|
||||
}
|
||||
|
||||
+24
-24
@@ -20,8 +20,9 @@
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
|
||||
#include "driver/keyboard.h"
|
||||
// Packet type for serial key injection (K5Viewer → radio)
|
||||
#define VCP_TYPE_KEY 0x03
|
||||
// Packet types for serial key injection (K5Viewer → radio)
|
||||
#define VCP_TYPE_KEY 0x03
|
||||
#define VCP_TYPE_KEY_LONG 0x04
|
||||
#endif
|
||||
|
||||
uint8_t VCP_RxBuf[VCP_RX_BUF_SIZE];
|
||||
@@ -46,21 +47,23 @@ void VCP_Init()
|
||||
|
||||
bool VCP_ScreenshotPing(void)
|
||||
{
|
||||
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
|
||||
// State machine for parsing incoming packets:
|
||||
// Keepalive: 0x55 0xAA 0x00 0x00 → viewer alive
|
||||
// Key packet: 0xAA 0x55 0x03 <key> → inject key
|
||||
// Keepalive: 0x55 0xAA 0x00 0x00 → viewer alive
|
||||
// Short key press: 0xAA 0x55 0x03 <key> → inject short press
|
||||
// Long key press: 0xAA 0x55 0x04 <key> → inject long press
|
||||
//
|
||||
// State transitions:
|
||||
// IDLE → 0x55 → KA_1
|
||||
// KA_1 → 0xAA → KA_2 (else IDLE)
|
||||
// KA_2 → 0x00 → KA_3 (else IDLE)
|
||||
// KA_1 → 0xAA → KA_2 (else IDLE)
|
||||
// KA_2 → 0x00 → KA_3 (else IDLE)
|
||||
// KA_3 → 0x00 → keepalive OK, IDLE
|
||||
//
|
||||
// IDLE → 0xAA → KEY_1
|
||||
// KEY_1 → 0x55 → KEY_2 (else IDLE)
|
||||
// KEY_2 → 0x03 → KEY_3 (else IDLE)
|
||||
// KEY_3 → <b> → inject key, IDLE
|
||||
// IDLE → 0xAA → KEY_1
|
||||
// KEY_1 → 0x55 → KEY_2 (else IDLE)
|
||||
// KEY_2 → 0x03 → KEY_3 (short press, else check long)
|
||||
// KEY_2 → 0x04 → KEY_3L (long press, else IDLE)
|
||||
// KEY_3 → <b> → InjectKey(b), IDLE
|
||||
// KEY_3L → <b> → InjectKeyLong(b), IDLE
|
||||
|
||||
typedef enum {
|
||||
STATE_IDLE = 0,
|
||||
@@ -70,6 +73,7 @@ bool VCP_ScreenshotPing(void)
|
||||
STATE_KEY_1,
|
||||
STATE_KEY_2,
|
||||
STATE_KEY_3,
|
||||
STATE_KEY_3L,
|
||||
} ParseState_t;
|
||||
|
||||
static uint32_t read_ptr = 0;
|
||||
@@ -110,7 +114,9 @@ bool VCP_ScreenshotPing(void)
|
||||
break;
|
||||
|
||||
case STATE_KEY_2:
|
||||
state = (b == VCP_TYPE_KEY) ? STATE_KEY_3 : STATE_IDLE;
|
||||
if (b == VCP_TYPE_KEY) state = STATE_KEY_3;
|
||||
else if (b == VCP_TYPE_KEY_LONG) state = STATE_KEY_3L;
|
||||
else state = STATE_IDLE;
|
||||
break;
|
||||
|
||||
case STATE_KEY_3:
|
||||
@@ -119,6 +125,12 @@ bool VCP_ScreenshotPing(void)
|
||||
state = STATE_IDLE;
|
||||
break;
|
||||
|
||||
case STATE_KEY_3L:
|
||||
KEYBOARD_InjectKeyLong(b);
|
||||
connected = true;
|
||||
state = STATE_IDLE;
|
||||
break;
|
||||
|
||||
default:
|
||||
state = STATE_IDLE;
|
||||
break;
|
||||
@@ -126,16 +138,4 @@ bool VCP_ScreenshotPing(void)
|
||||
}
|
||||
|
||||
return connected;
|
||||
|
||||
#else
|
||||
// Simple ping: just detect any incoming byte from the viewer
|
||||
static uint32_t read_ptr = 0;
|
||||
uint32_t write_ptr = VCP_RxBufPointer;
|
||||
|
||||
if (read_ptr != write_ptr) {
|
||||
read_ptr = write_ptr;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
Reference in new issue
Block a user