rle
erikkaashoek 5 days ago
parent 43dc76f3d1
commit bc76878f63

@ -0,0 +1,49 @@
# Copilot Instructions for tinySA
## Build Environment
Building requires the ARM GCC toolchain and MSYS2 utilities from ChibiStudio.
Before running `make`, set up the environment by running `C:\ChibiStudio\start_gcc113.bat`.
This configures the following PATH entries:
- `C:\ChibiStudio\tools\msys2\usr\bin` — provides `make`, `bash`, and other Unix utilities
- `C:\ChibiStudio\tools\openocd\bin` — OpenOCD for flashing
- `C:\ChibiStudio\tools\GNU Tools ARM Embedded\11.3 2022.08\bin` — ARM GCC 11.3 toolchain
Or set up the PATH manually in a terminal before building:
```bat
set PATH=C:\ChibiStudio\tools\msys2\usr\bin;%PATH%
set PATH=C:\ChibiStudio\tools\openocd\bin;%PATH%
set PATH=C:\ChibiStudio\tools\GNU Tools ARM Embedded\11.3 2022.08\arm-none-eabi\bin;%PATH%
set PATH=C:\ChibiStudio\tools\GNU Tools ARM Embedded\11.3 2022.08\bin;%PATH%
```
## Building
To build for the **tinySA Ultra** (STM32F303):
```sh
make TARGET=F303
```
To flash:
```sh
make TARGET=F303 dfu flash
```
## Project Structure
- `sa_core.c` / `sa_cmd.c` / `ui.c` — main application logic
- `si4468.c` / `si4432.c` — RF chip drivers
- `main.c` — entry point
- `NANOVNA_STM32_F303/` — board-specific files for the tinySA (F303 target)
- `ChibiOS/` — RTOS
## remote control protocol
See 'PROTOCOL.md' for details on the remote control protocol used by the tinySA.
tinySA is a resource constraint device. All code must use minimum CPU cycles, RAM and ROM. The codebase is written in C, with some assembly for critical sections. C++ is not used to avoid the overhead of exceptions and RTTI.

@ -0,0 +1,377 @@
# tinyGTC Remote Control & Screen Mirroring Protocol
This document describes the serial communication protocol used between the **tinyGTC-App** Windows application and a compatible device. It is intended to enable third-party device firmware to be controlled and mirrored by this application.
---
## 1. USB Device Identification
The application discovers devices on the USB bus using the Windows Setup API. A device is considered compatible when both of the following match:
| Property | Value |
|----------|-------|
| USB Vendor ID (VID) | `0x0483` (STMicroelectronics) |
| USB Product ID (PID) | `0x5741` (tinyGTC) or `0x5740` (tinySA) |
The device must expose a virtual COM port (VCP).
---
## 2. Serial Port Parameters
| Parameter | Value |
|-----------|-------|
| Data bits | 8 |
| Stop bits | 1 |
| Parity | None |
| Flow control | None |
Timeouts configured by the host:
| Timeout | Value |
|---------|-------|
| ReadIntervalTimeout | 50 ms |
| ReadTotalTimeoutConstant | 500 ms |
| ReadTotalTimeoutMultiplier | 10 ms/byte |
| WriteTotalTimeoutConstant | 500 ms |
| WriteTotalTimeoutMultiplier | 10 ms/byte |
---
## 3. Initialization Sequence
Upon connecting, the host performs the following steps:
1. Flush any data already in the device's RX buffer.
2. Wait **100 ms**.
3. Send `scpi off\r` (disables SCPI mode on the device).
4. Wait **100 ms**.
5. Send `capt\r\n` (requests the first full screen capture).
---
## 4. Host → Device Commands
All commands are plain ASCII text terminated with `\r` (carriage return). A trailing `\n` (line feed) is also accepted. There is no binary encoding on the host-to-device path.
| Command | Description |
|---------|-------------|
| `scpi off\r` | Disable SCPI/UART command mode on the device |
| `capt\r` | Request a full screen capture (device replies asynchronously; see Section 6.1) |
| `refresh on\r` | Enable automatic push of incremental screen updates |
| `refresh rle\r` | Enable automatic push of incremental screen updates using rle encoding |
| `refresh off\r` | Disable automatic push of incremental screen updates |
| `touch X Y\r` | Simulate a touch-screen press at pixel coordinate (X, Y) |
| `release\r` | Release a previous touch press |
In case of a tinySA the host first sends 'refresh rle' en check if the command is understood. If not a 'refresh on' command is send and the pixel transfers will be done without rle.
If the 'refresh rle' command is accepted it is assumed the tinySA will use rle for pixel transfer
A tinyGTC will always use rle when transferring pixels.
### Touch Coordinate System
- Origin (0, 0) is the **top-left** corner of the display.
- X increases to the right; Y increases downward.
- Coordinates are in **device pixels** (not scaled), matching the display dimensions (see Section 8).
- The host converts scaled screen-window coordinates to device pixels before sending.
### Command Interaction Notes
- `touch` and `release` are typically used together: send `touch X Y\r`, wait ≥100 ms, then send `release\r`.
- `refresh on` causes the device to continuously push `bulk`, `fill`, and `flip` events as the screen changes.
- `refresh off` stops the push; the host can still request individual full captures with `capt`.
---
## 5. Device → Host Protocol Overview
The device communicates back to the host using a **line-based event model**:
1. The device sends a **text event line** terminated with `\r\n`.
2. Immediately following the event line, it sends **binary payload data** (or no data, for lines that are purely informational).
The host reads one `\r\n`-terminated line, inspects it for known keywords, and then reads the binary payload appropriate to that keyword.
### Event Keywords
The host performs a substring search on each received line:
| Substring present in line | Event type | Binary payload follows? |
|---------------------------|------------|------------------------|
| `"apt"` **or** `"ture"` | Full screen capture | Yes see Section 6.1 |
| `"ulk"` | Bulk region update | Yes see Section 6.2 |
| `"ill"` | Fill region update | Yes see Section 6.3 |
| `"lip"` | Flip (rotation change) | Yes see Section 6.4 |
| (anything else) | Informational / ignored | No |
> **Note:** The keyword matching is case-sensitive and uses partial substring matching, so the device is free to include additional text in the line (e.g. `"> capture\r\n"` matches `"apt"` and `"ture"`; `"> bulk\r\n"` matches `"ulk"`).
---
## 6. Device → Host Binary Payloads
### 6.1 Full Screen Capture
**Trigger:** Event line containing `"apt"` or `"ture"`.
**Payload:** Exactly `width × height` pixels, each pixel encoded as a 2-byte little-endian word in the compact RLE pixel format described in Section 7.
- Pixels are ordered **left-to-right, top-to-bottom** (row-major).
- Rotation is fixed at **232** (standard landscape orientation) for full captures.
- The total uncompressed pixel count is always `width × height`; the RLE encoding means the byte count may be less, but the pixel count is exact.
Example for a 480×320 display: the host reads exactly `480 × 320 = 153,600` decoded pixel values (each returned by one invocation of the pixel decoder in Section 7).
---
### 6.2 Bulk Region Update
**Trigger:** Event line containing `"ulk"`.
**Payload structure:**
| Bytes | Type | Description |
|-------|------|-------------|
| 2 | `uint16_t` little-endian | X left edge of the region |
| 2 | `uint16_t` little-endian | Y top edge of the region |
| 2 | `uint16_t` little-endian | W width of the region |
| 2 | `uint16_t` little-endian | H height of the region |
| W × H × ~2 bytes | compact pixel stream | Pixel data in Section 7 format |
- Pixels are ordered row-by-row within the bounding rectangle.
- The region must be fully within the display: `x + w ≤ width`, `y + h ≤ height`.
- The host decodes exactly `W × H` pixels from the compact stream and writes them into the frame buffer at the correct positions, respecting the current rotation (Section 8).
---
### 6.3 Fill Region Update
**Trigger:** Event line containing `"ill"`.
**Payload structure:**
| Bytes | Type | Description |
|-------|------|-------------|
| 2 | `uint16_t` little-endian | X |
| 2 | `uint16_t` little-endian | Y |
| 2 | `uint16_t` little-endian | W |
| 2 | `uint16_t` little-endian | H |
| 2 | `uint16_t` **big-endian** | Fill color (standard RGB565, MSB first) |
| 2 | raw bytes | End marker: `0x00 0x40` |
- The host fills the entire `W × H` rectangle with the given color.
- The end marker bytes are `0x00 0x40` (this is the byte-swapped representation of `RUN_END = 0x4000`).
---
### 6.4 Flip (Rotation Change)
**Trigger:** Event line containing `"lip"`.
**Payload structure:**
| Bytes | Type | Description |
|-------|------|-------------|
| 2 | `uint16_t` little-endian | X |
| 2 | `uint16_t` little-endian | Y |
| 2 | `uint16_t` little-endian | W |
| 2 | `uint16_t` little-endian | H |
| 2 | `uint16_t` little-endian | New rotation value |
| 2 | raw bytes | End marker: `0x00 0x40` |
- The rotation value changes the mapping from incoming pixel data to the frame buffer (see Section 8).
- The end marker bytes are `0x00 0x40`.
---
## 7. Compact Pixel Encoding (Inline RLE)
All pixel streams (full captures and bulk regions) use the same compact 2-byte-per-word encoding. Each 2-byte word encodes **one color value plus a repeat count**, packing both into the bits of a standard 16-bit RGB565 word.
### 7.1 Bit Layout
The 16-bit word is received **little-endian** (low byte first over the wire):
```
Bit: [15][14][13][12][11][10][ 9][ 8][ 7][ 6][ 5][ 4][ 3][ 2][ 1][ 0]
Role: c c c B B B c c R R R c c G G G
```
- **Uppercase** = color bits: `B` (blue, 3 bits), `R` (red, 3 bits), `G` (green, 3 bits)
- **Lowercase** `c` = repeat-count bits (7 bits total)
Mask constants:
```
REPEAT_MASK = 0xe318 (bits [15:13], [9:8], [4:3])
COLOR_MASK = 0x1ce7 (bits [12:10], [7:5], [2:0])
```
### 7.2 Decoding Algorithm
```
Function ReadPixel() → rgb565_pixel:
// If there are pending repeats, return the stored color
if remaining > 0:
remaining -= 1
return current_color
// Read 2 bytes little-endian from the serial stream
byte0, byte1 ← read 2 bytes
word ← byte0 | (byte1 << 8)
// Extract 7-bit repeat count from the interleaved count bits
remaining ← ((word & 0xe000) >> 9) // bits [15:13] → count bits [6:4]
| ((word & 0x0300) >> 6) // bits [9:8] → count bits [3:2]
| ((word & 0x0018) >> 3) // bits [4:3] → count bits [1:0]
// remaining is now 0..127
// Fill the count bit positions with 1s to complete the RGB565 word
word |= 0xe318
// Byte-swap to produce standard big-endian RGB565
pixel ← ((word & 0x00ff) << 8) | ((word & 0xff00) >> 8)
current_color ← pixel
return pixel
```
> **Pixel delivery:** the first call delivers the pixel once; subsequent calls deliver the same pixel `remaining` more times without reading from the stream. The total delivery count per encoded word is `1 + remaining` (i.e. 1 to 128).
### 7.3 Color Fidelity Note
The encoding trades 7 color LSBs for the run-length count, so each channel carries only 3 significant bits out of the RGB565 5/6/5 bit allocation. The reconstruction forces the count-bit positions to `1`, so the decoded RGB565 color has certain bits always set (`0xe318` after the byte-swap), resulting in slight color quantization compared to an uncompressed RGB565 stream. The host applies no further correction.
### 7.4 Encoding a Pixel Word (for device firmware implementors)
```
Function EncodePixel(rgb565_pixel, repeat_count) → 2 bytes:
// repeat_count: 0 = send once, 127 = send 128 times
// rgb565_pixel is standard RGB565 (big-endian convention)
// Byte-swap to match wire format
word ← ((rgb565_pixel & 0x00ff) << 8) | ((rgb565_pixel & 0xff00) >> 8)
// Clear the count bit positions and insert count
word &= COLOR_MASK // 0x1ce7 keep only color bits
word |= ( (((repeat_count) << 9) & 0xe000) // count bits [6:4] [15:13]
|(((repeat_count) << 6) & 0x0300) // count bits [3:2] [9:8]
|(((repeat_count) << 3) & 0x0018) ) // count bits [1:0] [4:3]
// Transmit little-endian
byte0 ← word & 0xff
byte1 ← (word >> 8) & 0xff
send byte0, byte1
```
> **Important:** When encoding, first byte-swap the pixel (so it is stored in the same non-standard orientation that the receiver expects), then clear color bits, then insert the count. The color bits stored in the wire format are the 3 MSBs of each channel from the original RGB565 value (after the byte-swap operation).
---
## 8. Rotation / Coordinate Mapping
The rotation value (set by `flip` events) controls how bulk pixel data is written into the frame buffer.
| Rotation value | Meaning | Pixel mapping |
|----------------|---------|---------------|
| `232` | Standard landscape | `framebuffer[(y + row) * width + (x + col)] = pixel` (row-major, direct) |
| `136` | Rotated (portrait) | `destX = y + row; destY = height (x + col); framebuffer[destY * width + destX] = pixel` |
The full-screen capture and fill operations always use rotation `232` regardless of the current rotation state.
---
## 9. Supported Device Screen Sizes
The host must know the display dimensions in advance (configured via command-line argument or defaulting to tinyGTC size). The device does not announce its dimensions over the protocol.
| Device | Width (pixels) | Height (pixels) |
|--------|---------------|-----------------|
| tinyGTC (default) | 480 | 320 |
| tinyGTC Ultra | 480 | 320 |
| tinySA Ultra | 480 | 320 |
| NanoVNA-H4 | 480 | 320 |
| tinySA | 320 | 240 |
| NanoVNA-H | 320 | 240 |
---
## 10. Frame Buffer Format
The host maintains an in-memory frame buffer of `width × height` 16-bit RGB565 values (stored as `uint32_t` but only the lower 16 bits are used). The host converts to 32-bit BGRA for display:
```
R = ((rgb565 & 0xF800) >> 11) << 3 // 5-bit red 8-bit
G = ((rgb565 & 0x07E0) >> 5) << 2 // 6-bit green 8-bit
B = (rgb565 & 0x001F) << 3 // 5-bit blue 8-bit
```
Optional invert mode: `R = 255 R`, `G = 255 G`, `B = 255 B`.
---
## 11. Connection Management
- The host auto-discovers the first matching USB VCP at startup.
- Connection health is checked every **1000 ms** via `ClearCommError`; hardware errors (`CE_BREAK`, `CE_FRAME`, `CE_OVERRUN`, `CE_RXOVER`, `CE_TXFULL`) indicate lost connection.
- On disconnect, the host waits **500 ms** then attempts to re-open and re-initialize the device.
- On re-connection, the host does **not** automatically re-enable `refresh on`; the device resumes the capture stream via `capt`.
- On clean disconnect, the host sends `refresh off\r` before closing the port.
---
## 12. Protocol State Machine Summary
```
HOST DEVICE
| |
|── scpi off\r ──────────────────────────────► | (disable SCPI)
|── capt\r\n ─────────────────────────────────► | (request first frame)
| |
| ◄──────────── "> capture\r\n" ────────────── | (event line)
| ◄──── width×height pixels (compact RLE) ───── | (pixel stream)
| |
| [user enables auto-refresh] |
|── refresh on\r ──────────────────────────────► |
| |
| ◄──────────── "> bulk\r\n" ────────────────── | (dirty region)
| ◄─── 8-byte header + W×H pixels ──────────── |
| |
| ◄──────────── "> fill\r\n" ────────────────── | (solid fill)
| ◄─── 8-byte header + 2-byte color + 2-byte end marker ─── |
| |
| ◄──────────── "> flip\r\n" ────────────────── | (rotation)
| ◄─── 8-byte header + 2-byte rotation + 2-byte end marker ─|
| |
| [user clicks on mirrored screen] |
|── touch 123 87\r ────────────────────────────► |
| [wait ~100ms] |
|── release\r ─────────────────────────────────► |
| |
|── refresh off\r ─────────────────────────────► | (on disconnect)
```
---
## 13. Implementing a Compatible Device
To make a device controllable by this application, the firmware must:
1. **Enumerate as a USB CDC VCP** with `VID=0x0483`, appropriate PID, and bus-reported device description containing `"tinyGTC Command port"`.
2. **Accept the serial commands** in Section 4 on the VCP UART at 115200 8N1.
3. **On `scpi off\r`:** disable any SCPI mode and prepare for the remote protocol.
4. **On `capt\r`:** send the event line `"> capture\r\n"` (or any line containing `"apt"` or `"ture"`), immediately followed by the full pixel stream (Section 6.1) using the compact pixel encoding (Section 7).
5. **For incremental updates (when `refresh on` is active):** for each display region that changes, send one of:
- A line containing `"ulk"` + 8-byte header + pixel stream (Section 6.2) for arbitrary content.
- A line containing `"ill"` + 8-byte header + fill color + end marker (Section 6.3) for solid-color fills.
- A line containing `"lip"` + 8-byte header + rotation + end marker (Section 6.4) when the display rotation changes.
6. **On `touch X Y\r`:** simulate a touchscreen press at the given coordinates.
7. **On `release\r`:** release the simulated touch.

147
main.c

@ -966,13 +966,69 @@ VNA_SHELL_FUNCTION(cmd_remark)
#ifdef __REMOTE_DESKTOP__
uint8_t remote_mouse_down = false;
uint8_t auto_capture = false;
uint8_t rle = false;
// RLE-encode a pixel buffer and send it over the USB shell stream.
// buf : pixel_t array in tinySA wire format (byte-swapped RGB565)
// count : number of pixels
// Used for bulk region updates (PROTOCOL.md §6.2 / §7). No RLE terminator
// is appended: the host reads exactly W*H decoded pixels by count.
//
// out[32] layout: up to 29 run-code words, then 1 last-run word + 2 words
// for the "ch> " prompt = 32 total. Only ONE streamWrite at the final flush
// avoids USB CDC packet ordering issues that arise from multiple writes.
void do_send_rle(const uint16_t *buf, int count)
{
uint16_t out[32];
int outidx = 0;
uint16_t cur = 0;
int run = 0;
while (count-- > 0) {
uint16_t p = (*buf++) & RLE_COLOR_MASK;
if (run == 0 || (cur & RLE_COLOR_MASK) != p || run >= 128) {
if (run > 0) {
out[outidx++] = cur;
if (outidx >= 29) { // flush; keep 3 slots: last-run + 2x "ch> "
streamWrite(shell_stream, (void*)out, (uint16_t)(outidx * 2));
//osalThreadSleepMilliseconds(10);
outidx = 0;
}
}
cur = p; // repeat_count = 0 → pixel delivered once
run = 1;
} else {
cur = p | RLE_ENCODE_COUNT(run);
run++;
}
}
// Append last run + "ch> " into the same buffer; one send, zero extra packets
if (run > 0)
out[outidx++] = cur;
out[outidx++] = (uint16_t)('c' | ('h' << 8)); // bytes: 'c', 'h'
out[outidx++] = (uint16_t)('>' | (' ' << 8)); // bytes: '>', ' '
streamWrite(shell_stream, (void*)out, (uint16_t)(outidx * 2));
//osalThreadSleepMilliseconds(10);
}
void send_region(remote_region_t *rd, uint8_t * buf, uint16_t size)
{
if (SDU1.config->usbp->state == USB_ACTIVE) {
streamWrite(shell_stream, (void*) rd, sizeof(remote_region_t));
streamWrite(shell_stream, (void*) buf, size);
streamWrite(shell_stream, (void*)"ch> ", 4);
// Write tag and coordinates as two explicit writes to avoid any
// struct-layout / sizeof ambiguity (same pattern as cmd_capt).
const int16_t dims[4] = {rd->x, rd->y, rd->w, rd->h};
streamWrite(shell_stream, (void*) rd->new_str, 6);
// osalThreadSleepMilliseconds(1);
streamWrite(shell_stream, (void*) dims, 8);
// osalThreadSleepMilliseconds(1);
if (rle && size > 2) { // bulk pixels -> RLE encode
do_send_rle((const uint16_t *)buf, size >> 1);
} else { // fill/flip or raw-pixel mode
streamWrite(shell_stream, (void*) buf, size);
// osalThreadSleepMilliseconds(1);
streamWrite(shell_stream, (void*)"ch> ", 4);
// osalThreadSleepMilliseconds(1);
}
}
else
auto_capture = false;
@ -980,12 +1036,20 @@ 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)
int m = generic_option_cmd("refresh", "off|on", argc, argv[0]);
if (m>=0) {
auto_capture = m;
}
int m = generic_option_cmd("refresh", "off|on|rle", argc, argv[0]);
if (m == 0) { auto_capture = false; rle = false; }
else if (m == 1) { auto_capture = true; rle = false; }
else if (m == 2) { auto_capture = true; rle = true; }
}
VNA_SHELL_FUNCTION(cmd_rle)
{
int m = generic_option_cmd("rle", "off|on", argc, argv[0]);
if (m == 0) { rle = false; }
else if (m == 1) { rle = true; }
}
VNA_SHELL_FUNCTION(cmd_touch)
{
if (argc != 2) return;
@ -1028,6 +1092,71 @@ VNA_SHELL_FUNCTION(cmd_capture)
}
}
// RLE-encoded screen capture. Sends a "bulk\r\n" + x,y,w,h header (14 bytes)
// using two explicit writes to avoid struct-layout ambiguity, then RLE encodes
// the full screen in 2-row chunks reusing spi_buffer (no extra RAM). RLE state
// is kept across row boundaries so runs are never split artificially.
// "ch> " prompt is left to the shell on return.
VNA_SHELL_FUNCTION(cmd_capt)
{
(void)argc;
(void)argv;
#ifdef TINYSA4
#if SPI_BUFFER_SIZE < (2*LCD_WIDTH)
#error "Low size of spi_buffer for cmd_capt"
#endif
#else
#if SPI_BUFFER_SIZE < (3*LCD_WIDTH + 1)
#error "Low size of spi_buffer for cmd_capt"
#endif
#endif
#if 0
// Send "bulk\r\n" header (6 bytes) then x,y,w,h (8 bytes) explicitly
// to avoid any compiler struct-layout ambiguity.
static const char capt_tag[] = "bulk\r\n";
const int16_t capt_dims[4] = {0, 0, LCD_WIDTH, LCD_HEIGHT};
streamWrite(shell_stream, (void*)capt_tag, 6);
osalThreadSleepMilliseconds(1);
streamWrite(shell_stream, (void*)capt_dims, 8);
osalThreadSleepMilliseconds(1);
#endif
uint16_t out[32];
int outidx = 0;
uint16_t cur = 0;
int run = 0;
int y;
for (y = 0; y < LCD_HEIGHT; y += 2) {
ili9341_read_memory(0, y, LCD_WIDTH, 2, spi_buffer);
const uint16_t *px = (const uint16_t *)spi_buffer;
int n = 2 * LCD_WIDTH;
while (n-- > 0) {
uint16_t p = (*px++) & RLE_COLOR_MASK;
if (run == 0 || (cur & RLE_COLOR_MASK) != p || run >= 128) {
if (run > 0) {
out[outidx++] = cur;
if (outidx >= 29) {
streamWrite(shell_stream, (void*)out, (uint16_t)(outidx * 2));
osalThreadSleepMilliseconds(1);
outidx = 0;
}
}
cur = p;
run = 1;
} else {
cur = p | RLE_ENCODE_COUNT(run);
run++;
}
}
}
// flush last run; shell appends "ch> " prompt automatically after return
if (run > 0)
out[outidx++] = cur;
if (outidx > 0) {
streamWrite(shell_stream, (void*)out, (uint16_t)(outidx * 2));
osalThreadSleepMilliseconds(1);
}
}
#ifdef ENABLE_SD_CARD_CMD
#ifndef __USE_SD_CARD__
#error "Need enable SD card support __USE_SD_CARD__ in nanovna.h, for use ENABLE_SD_CARD_CMD"
@ -2489,8 +2618,10 @@ static const VNAShellCommand commands[] =
{"usart_cfg" , cmd_usart_cfg , CMD_WAIT_MUTEX | CMD_RUN_IN_LOAD},
#endif
{"capture" , cmd_capture , CMD_WAIT_MUTEX | CMD_RUN_IN_UI},
{"capt" , cmd_capt , CMD_WAIT_MUTEX | CMD_RUN_IN_UI},
#ifdef __REMOTE_DESKTOP__
{"refresh" , cmd_refresh , 0},
{"rle" , cmd_rle , 0},
{"touch" , cmd_touch , 0},
{"release" , cmd_release , 0},
#endif

@ -296,6 +296,17 @@ const char *get_hw_version_text(void);
#ifdef __REMOTE_DESKTOP__
extern uint8_t remote_mouse_down;
extern uint8_t auto_capture;
extern uint8_t rle_capture; // When set, bulk pixel data is RLE-encoded
// RLE pixel encoding (PROTOCOL.md §7):
// 16-bit wire word (transmitted LE): colour bits in 0x1ce7, count bits in 0xe318
// repeat_count 0 = pixel appears once, 127 = appears 128 times
#define RLE_COLOR_MASK 0x1ce7u
#define RLE_REPEAT_MASK 0xe318u
#define RLE_RUN_END 0x4000u
#define RLE_ENCODE_COUNT(n) ( (((uint16_t)(n) << 9) & 0xe000u) \
| (((uint16_t)(n) << 6) & 0x0300u) \
| (((uint16_t)(n) << 3) & 0x0018u) )
void do_send_rle(const uint16_t *buf, int count);
typedef struct {
char new_str[6];
int16_t x;
@ -1100,14 +1111,14 @@ typedef uint16_t pixel_t;
[LCD_BG_COLOR ] = RGB565( 0, 0, 0), \
[LCD_FG_COLOR ] = RGB565(255,255,255), \
[LCD_GRID_COLOR ] = RGB565(128,128,128), \
[LCD_MENU_COLOR ] = RGB565(230,230,230), \
[LCD_MENU_COLOR ] = RGB565(224,224,224), \
[LCD_MENU_TEXT_COLOR ] = RGB565( 0, 0, 0), \
[LCD_MENU_ACTIVE_COLOR] = RGB565(210,210,210), \
[LCD_MENU_ACTIVE_COLOR] = RGB565(192,192,192), \
[LCD_TRACE_1_COLOR ] = RGB565(255,255, 0), \
[LCD_TRACE_2_COLOR ] = RGB565( 64,255, 64), \
[LCD_TRACE_3_COLOR ] = RGB565(255, 64, 64), \
[LCD_TRACE_4_COLOR ] = RGB565(255, 0,255), \
[LCD_NORMAL_BAT_COLOR ] = RGB565( 31,227, 0), \
[LCD_NORMAL_BAT_COLOR ] = RGB565( 32,224, 0), \
[LCD_LOW_BAT_COLOR ] = RGB565(255, 0, 0), \
[LCD_TRIGGER_COLOR ] = RGB565( 0, 0,255), \
[LCD_RISE_EDGE_COLOR ] = RGB565(255,255,255), \
@ -1119,10 +1130,10 @@ typedef uint16_t pixel_t;
[LCD_BRIGHT_COLOR_BLUE] = RGB565( 0, 0,255), \
[LCD_BRIGHT_COLOR_RED ] = RGB565(255,128,128), \
[LCD_BRIGHT_COLOR_GREEN]= RGB565( 0,255, 0), \
[LCD_DARK_GREY ] = RGB565(140,140,140), \
[LCD_LIGHT_GREY ] = RGB565(220,220,220), \
[LCD_HAM_COLOR ] = RGB565( 80, 80, 80), \
[LCD_GRID_VALUE_COLOR ] = RGB565(196,196,196), \
[LCD_DARK_GREY ] = RGB565(160,160,160), \
[LCD_LIGHT_GREY ] = RGB565(224,224,224), \
[LCD_HAM_COLOR ] = RGB565( 96, 96, 96), \
[LCD_GRID_VALUE_COLOR ] = RGB565(192,192,192), \
[LCD_M_REFERENCE ] = RGB565(255,255,255), \
[LCD_M_DELTA ] = RGB565( 0,255, 0), \
[LCD_M_NOISE ] = RGB565( 0,255,255), \
@ -1133,14 +1144,14 @@ typedef uint16_t pixel_t;
[LCD_BG_COLOR ] = RGB565( 0, 0, 0), \
[LCD_FG_COLOR ] = RGB565(255,255,255), \
[LCD_GRID_COLOR ] = RGB565(128,128,128), \
[LCD_MENU_COLOR ] = RGB565(230,230,230), \
[LCD_MENU_COLOR ] = RGB565(224,224,224), \
[LCD_MENU_TEXT_COLOR ] = RGB565( 0, 0, 0), \
[LCD_MENU_ACTIVE_COLOR] = RGB565(210,210,210), \
[LCD_MENU_ACTIVE_COLOR] = RGB565(192,192,192), \
[LCD_TRACE_1_COLOR ] = RGB565(255,255, 0), \
[LCD_TRACE_2_COLOR ] = RGB565( 64,255, 64), \
[LCD_TRACE_3_COLOR ] = RGB565(255, 0,255), \
[LCD_TRACE_4_COLOR ] = RGB565(255, 64, 64), \
[LCD_NORMAL_BAT_COLOR ] = RGB565( 31,227, 0), \
[LCD_NORMAL_BAT_COLOR ] = RGB565( 32,224, 0), \
[LCD_LOW_BAT_COLOR ] = RGB565(255, 0, 0), \
[LCD_TRIGGER_COLOR ] = RGB565( 0, 0,255), \
[LCD_RISE_EDGE_COLOR ] = RGB565(255,255,255), \
@ -1152,10 +1163,10 @@ typedef uint16_t pixel_t;
[LCD_BRIGHT_COLOR_BLUE] = RGB565( 0, 0,255), \
[LCD_BRIGHT_COLOR_RED ] = RGB565(255,128,128), \
[LCD_BRIGHT_COLOR_GREEN]= RGB565( 0,255, 0), \
[LCD_DARK_GREY ] = RGB565(140,140,140), \
[LCD_LIGHT_GREY ] = RGB565(220,220,220), \
[LCD_HAM_COLOR ] = RGB565( 40, 40, 40), \
[LCD_GRID_VALUE_COLOR ] = RGB565(196,196,196), \
[LCD_DARK_GREY ] = RGB565(160,160,160), \
[LCD_LIGHT_GREY ] = RGB565(224,224,224), \
[LCD_HAM_COLOR ] = RGB565( 32, 32, 32), \
[LCD_GRID_VALUE_COLOR ] = RGB565(192,192,192), \
[LCD_M_REFERENCE ] = RGB565(255,255,255), \
[LCD_M_DELTA ] = RGB565( 0,255, 0), \
[LCD_M_NOISE ] = RGB565( 0,255,255), \

Loading…
Cancel
Save

Powered by TurnKey Linux.