diff --git a/App/app/aircopy.c b/App/app/aircopy.c index 9d716d17..34276077 100644 --- a/App/app/aircopy.c +++ b/App/app/aircopy.c @@ -139,7 +139,7 @@ static void AIRCOPY_clear() crc[i] = 0; } #ifdef ENABLE_FEAT_F4HWN_SCREENSHOT - getScreenShot(true); + SCREENSHOT_Update(true); #endif } @@ -167,7 +167,7 @@ static inline void AIRCOPY_CheckComplete(void) { gAircopyState = AIRCOPY_COMPLETE; #ifdef ENABLE_FEAT_F4HWN_SCREENSHOT - getScreenShot(false); + SCREENSHOT_Update(false); #endif } } @@ -212,7 +212,7 @@ bool AIRCOPY_SendMessage(void) if (CurrentSegmentIndex >= map->num_segments) { gAircopyState = AIRCOPY_COMPLETE; #ifdef ENABLE_FEAT_F4HWN_SCREENSHOT - getScreenShot(false); + SCREENSHOT_Update(false); #endif return 0; } diff --git a/App/app/app.c b/App/app/app.c index f26eb57b..264bf7ce 100644 --- a/App/app/app.c +++ b/App/app/app.c @@ -1406,7 +1406,7 @@ void APP_TimeSlice10ms(void) #ifdef ENABLE_FEAT_F4HWN_SCREENSHOT if (gUpdateDisplayCurrent || gUpdateStatusCurrent) { - getScreenShot(false); + SCREENSHOT_Update(false); } #endif diff --git a/App/app/breakout.c b/App/app/breakout.c index fdf1fcb5..26460830 100644 --- a/App/app/breakout.c +++ b/App/app/breakout.c @@ -484,7 +484,7 @@ void APP_RunBreakout(void) { // For screenshot #ifdef ENABLE_FEAT_F4HWN_SCREENSHOT - getScreenShot(false); + SCREENSHOT_Update(false); #endif } diff --git a/App/app/spectrum.c b/App/app/spectrum.c index 2fa38995..e6b9d8ea 100644 --- a/App/app/spectrum.c +++ b/App/app/spectrum.c @@ -1667,6 +1667,12 @@ static void UpdateListening() 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) { gNextTimeslice = false; @@ -1737,7 +1743,7 @@ static void Tick() Render(); // For screenshot #ifdef ENABLE_FEAT_F4HWN_SCREENSHOT - getScreenShot(false); + SCREENSHOT_Update(false); #endif redrawScreen = false; } diff --git a/App/driver/st7565.c b/App/driver/st7565.c index 1be740a0..b6b0a655 100644 --- a/App/driver/st7565.c +++ b/App/driver/st7565.c @@ -165,7 +165,7 @@ void ST7565_DrawLine(const unsigned int Column, const unsigned int Line, const u { ST7565_BlitScreen(line + 1); #ifdef ENABLE_FEAT_F4HWN_SCREENSHOT - getScreenShot(true); // Force immediate capture + SCREENSHOT_Update(true); // Force immediate capture #endif } diff --git a/App/driver/uart.c b/App/driver/uart.c index de99a5e7..73c87d6b 100644 --- a/App/driver/uart.c +++ b/App/driver/uart.c @@ -155,43 +155,70 @@ void UART_LogSend(const void *pBuffer, uint32_t Size) #ifdef ENABLE_FEAT_F4HWN_SCREENSHOT 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; - for (size_t i = 0; i < sizeof(UART_DMA_Buffer); i++) { - uint8_t b = UART_DMA_Buffer[i]; + // DMA write position: NbData counts DOWN from 256 + uint8_t write_ptr = (uint8_t)(sizeof(UART_DMA_Buffer) - + LL_DMA_GetDataLength(DMA1, DMA_CHANNEL)); - if (b == 0x55) { - // Keepalive byte — viewer is alive - UART_DMA_Buffer[i] = 0x00; - connected = true; - } - else if (b == 0xAA) { - // Possible start of a key packet: 0xAA 0x55 - // 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); + uint8_t processed = 0; + while (read_ptr != write_ptr && processed < sizeof(UART_DMA_Buffer)) + { + uint8_t b = UART_DMA_Buffer[read_ptr++]; + // read_ptr wraps naturally at 256 since it's uint8_t + processed++; + 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; - } + state = STATE_IDLE; + break; + case STATE_KEY_3L: + KEYBOARD_InjectKeyLong(b); + connected = true; + state = STATE_IDLE; + break; + default: + state = STATE_IDLE; + break; } } diff --git a/App/screenshot.c b/App/screenshot.c index 73c18c29..6781c905 100644 --- a/App/screenshot.c +++ b/App/screenshot.c @@ -21,7 +21,26 @@ #include "driver/vcp.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) { 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 -// - 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) +void SCREENSHOT_Update(bool force) { // Build frame in a temporary stack buffer // 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 // Old format: doesn't exist, so viewers can differentiate uint8_t versionMarker = 0xFF; - Screenshot_Send(&versionMarker, 1); + SCREENSHOT_Send(&versionMarker, 1); // ==== Send header ==== uint8_t header[5] = { @@ -144,7 +156,7 @@ void getScreenShot(bool force) (uint8_t)(deltaLen & 0xFF) }; - Screenshot_Send(header, 5); + SCREENSHOT_Send(header, 5); // ==== SECOND PASS: Send only changed chunks ==== uint8_t chunk[9]; @@ -157,12 +169,12 @@ void getScreenShot(bool force) chunk[0] = chunkIdx; memcpy(&chunk[1], cur, 8); - Screenshot_Send(chunk, 9); + SCREENSHOT_Send(chunk, 9); // Update previousFrame for next comparison memcpy(prev, cur, 8); } uint8_t end = 0x0A; - Screenshot_Send(&end, 1); + SCREENSHOT_Send(&end, 1); } \ No newline at end of file diff --git a/App/screenshot.h b/App/screenshot.h index d2811879..1ad17c4b 100644 --- a/App/screenshot.h +++ b/App/screenshot.h @@ -17,6 +17,7 @@ #ifndef SCREENSHOT_H #define SCREENSHOT_H -void getScreenShot(bool force); +void SCREENSHOT_Update(bool force); +void SCREENSHOT_ParseInput(void); #endif \ No newline at end of file diff --git a/App/ui/welcome.c b/App/ui/welcome.c index cb6f3d9d..0cecf63b 100644 --- a/App/ui/welcome.c +++ b/App/ui/welcome.c @@ -222,7 +222,7 @@ void UI_DisplayWelcome(void) ST7565_BlitFullScreen(); #ifdef ENABLE_FEAT_F4HWN_SCREENSHOT - getScreenShot(true); + SCREENSHOT_Update(true); #endif } } \ No newline at end of file diff --git a/App/usb/usbd_cdc_if.c b/App/usb/usbd_cdc_if.c index 61bace17..080c9f6e 100644 --- a/App/usb/usbd_cdc_if.c +++ b/App/usb/usbd_cdc_if.c @@ -190,8 +190,13 @@ void cdc_acm_data_send_with_dtr(const uint8_t *buf, uint32_t size) { ep_tx_busy_flag = true; 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 + } } }