diff --git a/main.c b/main.c index a2c1ed0..65e2a68 100644 --- a/main.c +++ b/main.c @@ -983,10 +983,21 @@ VNA_SHELL_FUNCTION(cmd_remark) #ifdef __REMOTE_DESKTOP__ uint8_t remote_mouse_down = false; uint8_t auto_capture = false; +#ifdef __REFRESH_RLE__ +uint8_t remote_hold = false; +static bool send_region_rle8(remote_region_t *rd, const pixel_t *px); +#endif void send_region(remote_region_t *rd, uint8_t * buf, uint16_t size) { +#ifdef __REFRESH_RLE__ + if (remote_hold) return; +#endif if (SDU1.config->usbp->state == USB_ACTIVE) { +#ifdef __REFRESH_RLE__ + if (auto_capture == 2 && rd->new_str[0] == 'b' && send_region_rle8(rd, (const pixel_t *)buf)) + return; +#endif streamWrite(shell_stream, (void*) rd, sizeof(remote_region_t)); streamWrite(shell_stream, (void*) buf, size); streamWrite(shell_stream, (void*)"ch> ", 4); @@ -998,7 +1009,11 @@ void send_region(remote_region_t *rd, uint8_t * buf, uint16_t size) VNA_SHELL_FUNCTION(cmd_refresh) { // read pixel count at one time (PART*2 bytes required for read buffer) +#ifdef __REFRESH_RLE__ + int m = generic_option_cmd("refresh", "off|on|rle", argc, argv[0]); +#else int m = generic_option_cmd("refresh", "off|on", argc, argv[0]); +#endif if (m>=0) { auto_capture = m; } @@ -1160,6 +1175,47 @@ static bool capture_rle8(void) } return true; } + +#ifdef __REFRESH_RLE__ +/* + * "refresh rle": a bulk push of 256 pixels or more is sent RLE8 packed with its own palette: + * "rle8\r\n", x, y, w, h, u16 palette size in bytes, palette, then the palette indices of all + * w * h pixels as one PackBits stream without lengths (the receiver unpacks until it has w * h), + * so runs of background continue over the rows. Smaller pushes fit the USB queue and stay "bulk", + * as do regions with too many colours to get smaller. + */ +static uint16_t rle8_buf[32 + LCD_WIDTH / 2]; // packed part, its indices from byte 64 +static bool send_region_rle8(remote_region_t *rd, const pixel_t *px) +{ + int n = rd->w * rd->h, i = 0, k, m, x; + pixel_t c = ~px[0]; + if (n < 256) + return false; + capture_colors = 0; + for (x = 0; x < n; x++) // the palette of the region + if (px[x] != c && !capture_palette_add(c = px[x])) + return false; + if (2 * capture_colors + n / 64 + 2 > n) // packed it could be larger than raw + return false; + uint16_t size = capture_colors * sizeof(pixel_t); + memcpy(rd->new_str, "rle8\r\n", sizeof(rd->new_str)); + streamWrite(shell_stream, (void *)rd, sizeof(remote_region_t)); + streamWrite(shell_stream, (void *)&size, sizeof(size)); + streamWrite(shell_stream, (void *)capture_palette, size); + uint8_t *index = (uint8_t *)&rle8_buf[32]; + for (k = 0, c = ~px[0]; k < n; k += m) { // LCD_WIDTH indices at a time, packed in place + m = n - k < LCD_WIDTH ? n - k : LCD_WIDTH; + for (x = 0; x < m; x++, px++) { + if (*px != c) + i = capture_palette_find(c = *px); + index[x] = i; + } + streamWrite(shell_stream, (void *)rle8_buf, packbits(index, (uint8_t *)rle8_buf, m)); + } + streamWrite(shell_stream, (void *)"ch> ", 4); + return true; +} +#endif #endif VNA_SHELL_FUNCTION(cmd_capture) diff --git a/nanovna.h b/nanovna.h index 4f8a3ab..d0de563 100644 --- a/nanovna.h +++ b/nanovna.h @@ -112,6 +112,7 @@ #define __USE_USB_MSC__ // USB DISK mode: SD card as USB mass storage next to the USB serial port #define __SD_FIRMWARE_UPDATE__ // Install a firmware .bin from the SD card (fw_update.c) #define __CAPTURE_RLE8__ // capture with an argument sends the screen RLE8 compressed (NanoVNA-D format) +#define __REFRESH_RLE__ // refresh rle: remote desktop pushes RLE8 compressed, the waterfall as a scroll #define __LCD_BRIGHTNESS__ // LCD or hardware allow change brightness, add menu item for this #define __HARMONIC__ #define __NOISE_FIGURE__ @@ -298,7 +299,10 @@ const char *get_hw_version_text(void); #ifdef __REMOTE_DESKTOP__ extern uint8_t remote_mouse_down; -extern uint8_t auto_capture; +extern uint8_t auto_capture; // 0 = refresh off, 1 = refresh on, 2 = refresh rle +#ifdef __REFRESH_RLE__ +extern uint8_t remote_hold; // drop pushes, e.g. while the waterfall scrolls (pushed as one "scrl") +#endif typedef struct { char new_str[6]; int16_t x; @@ -1803,6 +1807,9 @@ void clock_at_48MHz(void); #if defined(__SD_FIRMWARE_UPDATE__) && (!defined(TINYSA4) || !defined(__USE_USB_MSC__) || !defined(__SD_FILE_BROWSER__)) #error "__SD_FIRMWARE_UPDATE__ needs TINYSA4, __USE_USB_MSC__ and __SD_FILE_BROWSER__" #endif +#if defined(__REFRESH_RLE__) && (!defined(__REMOTE_DESKTOP__) || !defined(__CAPTURE_RLE8__)) +#error "__REFRESH_RLE__ needs __REMOTE_DESKTOP__ and __CAPTURE_RLE8__" +#endif #ifdef __SD_FIRMWARE_UPDATE__ #include "fw_update.h" #endif diff --git a/plot.c b/plot.c index 51f4e39..3eba62f 100644 --- a/plot.c +++ b/plot.c @@ -2205,7 +2205,12 @@ static void update_waterfall(void){ // START_PROFILE; #ifdef TINYSA4 #define WATERFALL_MULTI (SPI_BUFFER_SIZE / WIDTH) +#ifdef __REFRESH_RLE__ + remote_hold = (auto_capture == 2); // refresh rle: scroll as without remote, then push one "scrl" + if (!auto_capture || remote_hold) { +#else if (!auto_capture) { +#endif for (i = CHART_BOTTOM-WATERFALL_MULTI; i>=graph_bottom; i-=WATERFALL_MULTI) { // Scroll down WATERFALL_MULTI lines at once ili9341_read_memory(OFFSETX, i, w_width, WATERFALL_MULTI, spi_buffer); ili9341_bulk(OFFSETX, i+1, w_width, WATERFALL_MULTI); @@ -2217,6 +2222,14 @@ static void update_waterfall(void){ ili9341_read_memory(OFFSETX, i, w_width, 1, spi_buffer); ili9341_bulk(OFFSETX, i+1, w_width, 1); } +#ifdef __REFRESH_RLE__ + if (remote_hold) { // rows graph_bottom .. CHART_BOTTOM-1 moved down by dy + remote_region_t rd = {"scrl\r\n", OFFSETX, graph_bottom, w_width, CHART_BOTTOM - graph_bottom}; + int16_t dy = 1; + remote_hold = false; + send_region(&rd, (uint8_t *)&dy, sizeof(dy)); + } +#endif index_y_t *index = NULL; for (int t=0;t