mirror of
https://github.com/armel/uv-k1-k5v3-firmware-custom.git
synced 2026-10-02 03:15:37 +00:00
Fix spectrum: reliable serial key input + USB-C unplug freeze fix (issue #212)
This commit is contained in:
1 parent
fcf94e34ce
commit
9f0547f6af
10 files changed
+106
-55
No files matched your search
+3
-3
@@ -139,7 +139,7 @@ static void AIRCOPY_clear()
|
|||||||
crc[i] = 0;
|
crc[i] = 0;
|
||||||
}
|
}
|
||||||
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
|
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
|
||||||
getScreenShot(true);
|
SCREENSHOT_Update(true);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,7 +167,7 @@ static inline void AIRCOPY_CheckComplete(void)
|
|||||||
{
|
{
|
||||||
gAircopyState = AIRCOPY_COMPLETE;
|
gAircopyState = AIRCOPY_COMPLETE;
|
||||||
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
|
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
|
||||||
getScreenShot(false);
|
SCREENSHOT_Update(false);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -212,7 +212,7 @@ bool AIRCOPY_SendMessage(void)
|
|||||||
if (CurrentSegmentIndex >= map->num_segments) {
|
if (CurrentSegmentIndex >= map->num_segments) {
|
||||||
gAircopyState = AIRCOPY_COMPLETE;
|
gAircopyState = AIRCOPY_COMPLETE;
|
||||||
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
|
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
|
||||||
getScreenShot(false);
|
SCREENSHOT_Update(false);
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -1406,7 +1406,7 @@ void APP_TimeSlice10ms(void)
|
|||||||
|
|
||||||
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
|
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
|
||||||
if (gUpdateDisplayCurrent || gUpdateStatusCurrent) {
|
if (gUpdateDisplayCurrent || gUpdateStatusCurrent) {
|
||||||
getScreenShot(false);
|
SCREENSHOT_Update(false);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -484,7 +484,7 @@ void APP_RunBreakout(void) {
|
|||||||
|
|
||||||
// For screenshot
|
// For screenshot
|
||||||
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
|
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
|
||||||
getScreenShot(false);
|
SCREENSHOT_Update(false);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+7
-1
@@ -1667,6 +1667,12 @@ static void UpdateListening()
|
|||||||
|
|
||||||
static void Tick()
|
static void Tick()
|
||||||
{
|
{
|
||||||
|
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
|
||||||
|
// Parse incoming packets on every tick so serial keys are never missed,
|
||||||
|
// regardless of whether the screen needs redrawing.
|
||||||
|
SCREENSHOT_ParseInput();
|
||||||
|
#endif
|
||||||
|
|
||||||
if (gNextTimeslice)
|
if (gNextTimeslice)
|
||||||
{
|
{
|
||||||
gNextTimeslice = false;
|
gNextTimeslice = false;
|
||||||
@@ -1737,7 +1743,7 @@ static void Tick()
|
|||||||
Render();
|
Render();
|
||||||
// For screenshot
|
// For screenshot
|
||||||
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
|
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
|
||||||
getScreenShot(false);
|
SCREENSHOT_Update(false);
|
||||||
#endif
|
#endif
|
||||||
redrawScreen = false;
|
redrawScreen = false;
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -165,7 +165,7 @@ void ST7565_DrawLine(const unsigned int Column, const unsigned int Line, const u
|
|||||||
{
|
{
|
||||||
ST7565_BlitScreen(line + 1);
|
ST7565_BlitScreen(line + 1);
|
||||||
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
|
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
|
||||||
getScreenShot(true); // Force immediate capture
|
SCREENSHOT_Update(true); // Force immediate capture
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+59
-32
@@ -155,43 +155,70 @@ void UART_LogSend(const void *pBuffer, uint32_t Size)
|
|||||||
|
|
||||||
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
|
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
|
||||||
bool UART_IsCableConnected(void) {
|
bool UART_IsCableConnected(void) {
|
||||||
|
typedef enum {
|
||||||
|
STATE_IDLE = 0,
|
||||||
|
STATE_KA_1,
|
||||||
|
STATE_KA_2,
|
||||||
|
STATE_KA_3,
|
||||||
|
STATE_KEY_1,
|
||||||
|
STATE_KEY_2,
|
||||||
|
STATE_KEY_3,
|
||||||
|
STATE_KEY_3L,
|
||||||
|
} ParseState_t;
|
||||||
|
|
||||||
|
static uint8_t read_ptr = 0;
|
||||||
|
static ParseState_t state = STATE_IDLE;
|
||||||
|
|
||||||
bool connected = false;
|
bool connected = false;
|
||||||
|
|
||||||
for (size_t i = 0; i < sizeof(UART_DMA_Buffer); i++) {
|
// DMA write position: NbData counts DOWN from 256
|
||||||
uint8_t b = UART_DMA_Buffer[i];
|
uint8_t write_ptr = (uint8_t)(sizeof(UART_DMA_Buffer) -
|
||||||
|
LL_DMA_GetDataLength(DMA1, DMA_CHANNEL));
|
||||||
|
|
||||||
if (b == 0x55) {
|
uint8_t processed = 0;
|
||||||
// Keepalive byte — viewer is alive
|
while (read_ptr != write_ptr && processed < sizeof(UART_DMA_Buffer))
|
||||||
UART_DMA_Buffer[i] = 0x00;
|
{
|
||||||
connected = true;
|
uint8_t b = UART_DMA_Buffer[read_ptr++];
|
||||||
}
|
// read_ptr wraps naturally at 256 since it's uint8_t
|
||||||
else if (b == 0xAA) {
|
processed++;
|
||||||
// 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_LONG))
|
|
||||||
{
|
|
||||||
uint8_t type = UART_DMA_Buffer[i2];
|
|
||||||
uint8_t keyCode = UART_DMA_Buffer[i3];
|
|
||||||
|
|
||||||
// Consume all 4 bytes
|
|
||||||
UART_DMA_Buffer[i] = 0x00;
|
|
||||||
UART_DMA_Buffer[i1] = 0x00;
|
|
||||||
UART_DMA_Buffer[i2] = 0x00;
|
|
||||||
UART_DMA_Buffer[i3] = 0x00;
|
|
||||||
|
|
||||||
if (type == UART_TYPE_KEY_LONG)
|
|
||||||
KEYBOARD_InjectKeyLong(keyCode);
|
|
||||||
else
|
|
||||||
KEYBOARD_InjectKey(keyCode);
|
|
||||||
|
|
||||||
|
switch (state)
|
||||||
|
{
|
||||||
|
case STATE_IDLE:
|
||||||
|
if (b == 0x55) state = STATE_KA_1;
|
||||||
|
else if (b == 0xAA) state = STATE_KEY_1;
|
||||||
|
break;
|
||||||
|
case STATE_KA_1:
|
||||||
|
state = (b == 0xAA) ? STATE_KA_2 : STATE_IDLE;
|
||||||
|
break;
|
||||||
|
case STATE_KA_2:
|
||||||
|
state = (b == 0x00) ? STATE_KA_3 : STATE_IDLE;
|
||||||
|
break;
|
||||||
|
case STATE_KA_3:
|
||||||
|
if (b == 0x00) connected = true;
|
||||||
|
state = STATE_IDLE;
|
||||||
|
break;
|
||||||
|
case STATE_KEY_1:
|
||||||
|
state = (b == 0x55) ? STATE_KEY_2 : STATE_IDLE;
|
||||||
|
break;
|
||||||
|
case STATE_KEY_2:
|
||||||
|
if (b == UART_TYPE_KEY) state = STATE_KEY_3;
|
||||||
|
else if (b == UART_TYPE_KEY_LONG) state = STATE_KEY_3L;
|
||||||
|
else state = STATE_IDLE;
|
||||||
|
break;
|
||||||
|
case STATE_KEY_3:
|
||||||
|
KEYBOARD_InjectKey(b);
|
||||||
connected = true;
|
connected = true;
|
||||||
}
|
state = STATE_IDLE;
|
||||||
|
break;
|
||||||
|
case STATE_KEY_3L:
|
||||||
|
KEYBOARD_InjectKeyLong(b);
|
||||||
|
connected = true;
|
||||||
|
state = STATE_IDLE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
state = STATE_IDLE;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+25
-13
@@ -21,7 +21,26 @@
|
|||||||
#include "driver/vcp.h"
|
#include "driver/vcp.h"
|
||||||
#include "driver/keyboard.h"
|
#include "driver/keyboard.h"
|
||||||
|
|
||||||
static void Screenshot_Send(const uint8_t *buf, uint16_t len)
|
// SRAM optimization: minimize static allocations
|
||||||
|
// - previousFrame: 1024 bytes (REQUIRED - need to compare for delta)
|
||||||
|
// - No currentFrame or deltaFrame static buffers
|
||||||
|
static uint8_t previousFrame[1024] = {0};
|
||||||
|
static uint8_t forcedBlock = 0;
|
||||||
|
static uint8_t keepAlive = 10;
|
||||||
|
|
||||||
|
void SCREENSHOT_ParseInput(void)
|
||||||
|
{
|
||||||
|
if (UART_IsCableConnected()) {
|
||||||
|
keepAlive = 10;
|
||||||
|
gUSB_ScreenshotEnabled = false;
|
||||||
|
}
|
||||||
|
if (VCP_ScreenshotPing()) {
|
||||||
|
keepAlive = 10;
|
||||||
|
gUSB_ScreenshotEnabled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SCREENSHOT_Send(const uint8_t *buf, uint16_t len)
|
||||||
{
|
{
|
||||||
if (gUSB_ScreenshotEnabled) {
|
if (gUSB_ScreenshotEnabled) {
|
||||||
cdc_acm_data_send_with_dtr(buf, len);
|
cdc_acm_data_send_with_dtr(buf, len);
|
||||||
@@ -30,14 +49,7 @@ static void Screenshot_Send(const uint8_t *buf, uint16_t len)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SRAM optimization: minimize static allocations
|
void SCREENSHOT_Update(bool force)
|
||||||
// - previousFrame: 1024 bytes (REQUIRED - need to compare for delta)
|
|
||||||
// - No currentFrame or deltaFrame static buffers
|
|
||||||
static uint8_t previousFrame[1024] = {0};
|
|
||||||
static uint8_t forcedBlock = 0;
|
|
||||||
static uint8_t keepAlive = 10;
|
|
||||||
|
|
||||||
void getScreenShot(bool force)
|
|
||||||
{
|
{
|
||||||
// Build frame in a temporary stack buffer
|
// Build frame in a temporary stack buffer
|
||||||
// This is 1024 bytes but it's temporary and gets freed after the function
|
// This is 1024 bytes but it's temporary and gets freed after the function
|
||||||
@@ -135,7 +147,7 @@ void getScreenShot(bool force)
|
|||||||
// New format: sends 0xFF before header
|
// New format: sends 0xFF before header
|
||||||
// Old format: doesn't exist, so viewers can differentiate
|
// Old format: doesn't exist, so viewers can differentiate
|
||||||
uint8_t versionMarker = 0xFF;
|
uint8_t versionMarker = 0xFF;
|
||||||
Screenshot_Send(&versionMarker, 1);
|
SCREENSHOT_Send(&versionMarker, 1);
|
||||||
|
|
||||||
// ==== Send header ====
|
// ==== Send header ====
|
||||||
uint8_t header[5] = {
|
uint8_t header[5] = {
|
||||||
@@ -144,7 +156,7 @@ void getScreenShot(bool force)
|
|||||||
(uint8_t)(deltaLen & 0xFF)
|
(uint8_t)(deltaLen & 0xFF)
|
||||||
};
|
};
|
||||||
|
|
||||||
Screenshot_Send(header, 5);
|
SCREENSHOT_Send(header, 5);
|
||||||
|
|
||||||
// ==== SECOND PASS: Send only changed chunks ====
|
// ==== SECOND PASS: Send only changed chunks ====
|
||||||
uint8_t chunk[9];
|
uint8_t chunk[9];
|
||||||
@@ -157,12 +169,12 @@ void getScreenShot(bool force)
|
|||||||
chunk[0] = chunkIdx;
|
chunk[0] = chunkIdx;
|
||||||
memcpy(&chunk[1], cur, 8);
|
memcpy(&chunk[1], cur, 8);
|
||||||
|
|
||||||
Screenshot_Send(chunk, 9);
|
SCREENSHOT_Send(chunk, 9);
|
||||||
|
|
||||||
// Update previousFrame for next comparison
|
// Update previousFrame for next comparison
|
||||||
memcpy(prev, cur, 8);
|
memcpy(prev, cur, 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t end = 0x0A;
|
uint8_t end = 0x0A;
|
||||||
Screenshot_Send(&end, 1);
|
SCREENSHOT_Send(&end, 1);
|
||||||
}
|
}
|
||||||
+2
-1
@@ -17,6 +17,7 @@
|
|||||||
#ifndef SCREENSHOT_H
|
#ifndef SCREENSHOT_H
|
||||||
#define SCREENSHOT_H
|
#define SCREENSHOT_H
|
||||||
|
|
||||||
void getScreenShot(bool force);
|
void SCREENSHOT_Update(bool force);
|
||||||
|
void SCREENSHOT_ParseInput(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
+1
-1
@@ -222,7 +222,7 @@ void UI_DisplayWelcome(void)
|
|||||||
ST7565_BlitFullScreen();
|
ST7565_BlitFullScreen();
|
||||||
|
|
||||||
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
|
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
|
||||||
getScreenShot(true);
|
SCREENSHOT_Update(true);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -190,8 +190,13 @@ void cdc_acm_data_send_with_dtr(const uint8_t *buf, uint32_t size)
|
|||||||
{
|
{
|
||||||
ep_tx_busy_flag = true;
|
ep_tx_busy_flag = true;
|
||||||
usbd_ep_start_write(CDC_IN_EP, buf, size);
|
usbd_ep_start_write(CDC_IN_EP, buf, size);
|
||||||
while (ep_tx_busy_flag)
|
uint32_t timeout = 100000;
|
||||||
|
while (ep_tx_busy_flag && --timeout)
|
||||||
;
|
;
|
||||||
|
if (!timeout) {
|
||||||
|
ep_tx_busy_flag = false;
|
||||||
|
dtr_enable = 0; // Consider USB disconnected
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user