diff --git a/App/app/uart.c b/App/app/uart.c index 8b519654..0bd99605 100644 --- a/App/app/uart.c +++ b/App/app/uart.c @@ -677,14 +677,26 @@ bool UART_IsCommandAvailable(uint32_t Port) return false; } - while (1) + // Limit iterations to prevent long loops when buffer is full of non-command data + uint16_t maxIterations = ReadBufSize + 1; + + while (maxIterations--) { if ((*pReadPointer) == DmaLength) return false; - while ((*pReadPointer) != DmaLength && ReadBuf[*pReadPointer] != 0xABU) + // Find 0xAB with iteration limit + uint16_t searchLimit = ReadBufSize; + while ((*pReadPointer) != DmaLength && ReadBuf[*pReadPointer] != 0xABU && searchLimit--) *pReadPointer = DMA_INDEX((*pReadPointer), 1, ReadBufSize); + if (searchLimit == 0) + { + // Too many bytes without finding 0xAB - sync to current position and exit + *pReadPointer = DmaLength; + return false; + } + if ((*pReadPointer) == DmaLength) return false; @@ -702,6 +714,13 @@ bool UART_IsCommandAvailable(uint32_t Port) *pReadPointer = DMA_INDEX(*pReadPointer, 1, ReadBufSize); } + if (maxIterations == 0) + { + // Safety: too many outer loop iterations + *pReadPointer = DmaLength; + return false; + } + Index = DMA_INDEX(*pReadPointer, 2, ReadBufSize); Size = (ReadBuf[DMA_INDEX(Index, 1, ReadBufSize)] << 8) | ReadBuf[Index]; @@ -847,4 +866,4 @@ void UART_HandleCommand(uint32_t Port) #ifdef ENABLE_FEAT_F4HWN_SCREENSHOT gUART_LockScreenshot = 20; // lock screenshot #endif -} +} \ No newline at end of file diff --git a/App/driver/vcp.c b/App/driver/vcp.c index f4398592..87cfc1d5 100644 --- a/App/driver/vcp.c +++ b/App/driver/vcp.c @@ -37,3 +37,25 @@ void VCP_Init() NVIC_SetPriority(USBD_IRQn, 3); NVIC_EnableIRQ(USBD_IRQn); } + +bool VCP_ScreenshotPing(void) +{ + static uint32_t read_ptr = 0; + + uint32_t write_ptr = VCP_RxBufPointer; + + while (read_ptr != write_ptr) + { + uint8_t b = VCP_RxBuf[read_ptr]; + + read_ptr++; + if (read_ptr >= VCP_RX_BUF_SIZE) + read_ptr = 0; + + if (b == 0x55) + { + return true; + } + } + return false; +} diff --git a/App/driver/vcp.h b/App/driver/vcp.h index 24e9606e..d7cc2c3a 100644 --- a/App/driver/vcp.h +++ b/App/driver/vcp.h @@ -19,6 +19,7 @@ #include #include +#include #include "usb_config.h" #define VCP_RX_BUF_SIZE 256 @@ -27,6 +28,7 @@ extern uint8_t VCP_RxBuf[VCP_RX_BUF_SIZE]; extern volatile uint32_t VCP_RxBufPointer; void VCP_Init(); +bool VCP_ScreenshotPing(void); static inline void VCP_Send(const uint8_t *Buf, uint32_t Size) { diff --git a/App/misc.c b/App/misc.c index fe3d56fa..91cb977f 100644 --- a/App/misc.c +++ b/App/misc.c @@ -202,7 +202,8 @@ volatile bool gTxTimeoutReached; volatile uint16_t gRxTimerCountdown_500ms; #endif #ifdef ENABLE_FEAT_F4HWN_SCREENSHOT - volatile uint8_t gUART_LockScreenshot = 0; // lock screenshot if Chirp is used + volatile uint8_t gUART_LockScreenshot = 0; // lock screenshot if Chirp is used + bool gUSB_ScreenshotEnabled = false; #endif #endif diff --git a/App/misc.h b/App/misc.h index f7bb67d7..cab2e4d7 100644 --- a/App/misc.h +++ b/App/misc.h @@ -321,6 +321,7 @@ extern volatile bool gTxTimeoutReached; #endif #ifdef ENABLE_FEAT_F4HWN_SCREENSHOT extern volatile uint8_t gUART_LockScreenshot; // lock screenshot if Chirp is used + extern bool gUSB_ScreenshotEnabled; #endif #endif diff --git a/App/screenshot.c b/App/screenshot.c index bad36206..f7c4f353 100644 --- a/App/screenshot.c +++ b/App/screenshot.c @@ -18,7 +18,16 @@ #include "driver/st7565.h" #include "screenshot.h" #include "misc.h" -#include +#include "driver/vcp.h" + +static void Screenshot_Send(const uint8_t *buf, uint16_t len) +{ + if (gUSB_ScreenshotEnabled) { + cdc_acm_data_send_with_dtr(buf, len); + } else { + UART_Send(buf, len); + } +} // SRAM optimization: minimize static allocations // - previousFrame: 1024 bytes (REQUIRED - need to compare for delta) @@ -43,6 +52,12 @@ void getScreenShot(bool force) if (UART_IsCableConnected()) { keepAlive = 10; + gUSB_ScreenshotEnabled = false; + } + + if (VCP_ScreenshotPing()) { + keepAlive = 10; + gUSB_ScreenshotEnabled = true; } if (keepAlive > 0) { @@ -114,7 +129,7 @@ void getScreenShot(bool force) // New format: sends 0xFF before header // Old format: doesn't exist, so viewers can differentiate uint8_t versionMarker = 0xFF; - UART_Send(&versionMarker, 1); + Screenshot_Send(&versionMarker, 1); // ==== Send header ==== uint8_t header[5] = { @@ -123,7 +138,7 @@ void getScreenShot(bool force) (uint8_t)(deltaLen & 0xFF) }; - UART_Send(header, 5); + Screenshot_Send(header, 5); // ==== SECOND PASS: Send only changed chunks ==== uint8_t chunk[9]; @@ -136,12 +151,12 @@ void getScreenShot(bool force) chunk[0] = chunkIdx; memcpy(&chunk[1], cur, 8); - UART_Send(chunk, 9); + Screenshot_Send(chunk, 9); // Update previousFrame for next comparison memcpy(prev, cur, 8); } uint8_t end = 0x0A; - UART_Send(&end, 1); + Screenshot_Send(&end, 1); } \ No newline at end of file