Merge branch 'keypad-cursor'

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
copilot/add-multi-platform-rf-scan-exports
erikkaashoek 2 weeks ago
commit 2e6cd0cd7d

@ -1,3 +1,8 @@
V1.4260 2026-10-27 For all tinySA models
- File, band and preset names can be edited anywhere: touch the name to place the cursor, keys insert and backspace deletes at the cursor (Ultra only)
- While a keypad is open, console commands that cannot run (e.g. vbat, sweep) are answered "keypad active" at once instead of after 20 s, so remote editing with tinySA-App no longer slows down
- No more white flash when switching on a tinySA Ultra (ZS405) (Ultra only)
V1.4255 2026-10-23 For all tinySA Ultra models
- "refresh rle" remote control: compressed screen updates and a scrolling waterfall, 8x to 16x less USB data (tinySA-App uses it automatically)

@ -504,6 +504,12 @@ void lcd_setBrightness(uint16_t b){
}
#endif
#ifdef __LCD_BRIGHTNESS__
#define LCD_WAKE_UP_MS 120 // after sleep out the panel supplies settle, the backlight comes on after the init
#else
#define LCD_WAKE_UP_MS 2 // backlight not controlled: a longer wait only shows the uninitialised panel longer
#endif
void ili9341_init(void)
{
LCD_DC_DATA;
@ -513,8 +519,8 @@ void ili9341_init(void)
const uint8_t *p;
for (p = LCD_INIT; *p; ) {
send_command(p[0], p[1], &p[2]);
chThdSleepMilliseconds(p[0] == ILI9341_SLEEP_OUT ? LCD_WAKE_UP_MS : 2);
p += 2 + p[1];
chThdSleepMilliseconds(2);
}
#ifdef TINYSA4
if ((hwid % 100) >= 2) {

@ -962,6 +962,7 @@ VNA_SHELL_FUNCTION(cmd_menu)
}
uint8_t remote_text = false;
uint8_t keypad_open = false; // set by ui.c while the sweep thread waits for keypad input
VNA_SHELL_FUNCTION(cmd_text)
{
if (argc!= 1)
@ -3212,6 +3213,11 @@ static void VNAShell_executeLine(char *line)
return;
}
#endif
// The sweep thread stays in an open keypad until it closes: answer at once instead of a 20 s timeout
if ((cmd_flag & CMD_WAIT_MUTEX) && keypad_open) {
shell_printf("keypad active" VNA_SHELL_NEWLINE_STR VNA_SHELL_PROMPT_STR);
return;
}
if (cmd_flag & CMD_WAIT_MUTEX) {
chSysLock();
shell_function = scp->sc_function;
@ -3544,9 +3550,6 @@ int main(void)
adc_init();
PULSE
DAC->CR|= DAC_CR_EN1 | DAC_CR_EN2; // Use DAC: CH1 and CH2
#ifdef __LCD_BRIGHTNESS__
lcd_setBrightness(DEFAULT_BRIGHTNESS);
#endif
DAC->DHR12R1 = 0; // Setup DAC: CH1 value
/*
@ -3557,6 +3560,11 @@ int main(void)
#endif
ili9341_init();
PULSE
#ifdef __LCD_BRIGHTNESS__
// Backlight on only now the screen is cleared: a panel in reset or before its init
// shows white (the ZS405 panel, ZS406/ZS407 stay black)
lcd_setBrightness(DEFAULT_BRIGHTNESS);
#endif
#ifdef TINYSA4
ili9341_set_foreground(LCD_FG_COLOR);

80
ui.c

@ -1205,6 +1205,11 @@ const uint8_t right_icons [] =
#define KP_500 40
enum {NUM_KEYBOARD, TXT_KEYBOARD};
#ifdef __USE_SD_CARD__
#define IS_TXT_KEYBOARD (keypads[0].c == TXT_KEYBOARD)
#else
#define IS_TXT_KEYBOARD false // keypads_text needs the SD card, the text keypad code is left out
#endif
typedef struct {
uint16_t x_offs;
@ -7138,15 +7143,47 @@ draw_numeric_input(const char *buf)
}
}
#define TXT_INPUT_X (14 + 10 * FONT_WIDTH)
#define TXT_CURSOR_OUT 4 // the cursor sticks out above and below the letters, so it is no I
static uint8_t kp_cursor; // text keypad: characters are inserted and deleted here
// Text with the cursor as a blue 2 pixel bar in its own gap (the glyphs are only 1 pixel apart)
static void
draw_text_input(const char *buf)
{
ili9341_set_foreground(LCD_INPUT_TEXT_COLOR);
ili9341_set_background(LCD_INPUT_BG_COLOR);
uint16_t x = 14 + 10 * FONT_WIDTH;
int x = TXT_INPUT_X;
uint16_t y = LCD_HEIGHT-(wFONT_GET_HEIGHT + NUM_INPUT_HEIGHT)/2;
ili9341_fill(x, y, wFONT_MAX_WIDTH * 20, wFONT_GET_HEIGHT);
ili9341_drawstring_10x14(buf, x, y);
ili9341_fill(x, y - TXT_CURSOR_OUT, LCD_WIDTH - x, wFONT_GET_HEIGHT + 2 * TXT_CURSOR_OUT);
char txt[2] = {0, 0};
for (int i = 0; ; i++) {
if (i == kp_cursor) {
ili9341_set_background(LCD_BRIGHT_COLOR_BLUE);
ili9341_fill(x, y - TXT_CURSOR_OUT, 2, wFONT_GET_HEIGHT + 2 * TXT_CURSOR_OUT);
ili9341_set_background(LCD_INPUT_BG_COLOR);
x += 3;
}
if ((txt[0] = buf[i]) == 0) break;
ili9341_drawstring_10x14(txt, x, y);
x += wFONT_GET_WIDTH(txt[0]);
}
}
// Touch on the text: the cursor goes to the character boundary nearest to touch_x
static void
text_cursor_touch(int touch_x)
{
int x = TXT_INPUT_X, i;
for (i = 0; kp_buf[i]; i++) {
int w = wFONT_GET_WIDTH(kp_buf[i]);
if (touch_x < x + w / 2) break;
x += w;
}
if (i == kp_cursor) return;
kp_cursor = i;
draw_text_input(kp_buf);
}
static void
@ -8005,15 +8042,21 @@ full_keypad_click(int c, int kp_index)
set_numeric_value(); // Also for text values
return KP_DONE;
}
if (c == S_LARROW[0]) { // Backspace
if (kp_cursor > kp_index) // kp_buf replaced by the text command
kp_cursor = kp_index;
if (c == S_LARROW[0]) { // Backspace: the character before the cursor
if (kp_index == 0)
return KP_CANCEL;
if (keypad_long_press) // long press erases the whole input, stay in the keypad
kp_index = 0;
else
--kp_index;
} else if (kp_index < TXTINPUT_LEN) { // any other text input
kp_buf[kp_index++] = c;
kp_index = kp_cursor = 0;
else if (kp_cursor > 0) {
memmove(&kp_buf[kp_cursor - 1], &kp_buf[kp_cursor], kp_index - kp_cursor);
kp_cursor--, kp_index--;
}
} else if (kp_index < TXTINPUT_LEN) { // any other text input, inserted at the cursor
memmove(&kp_buf[kp_cursor + 1], &kp_buf[kp_cursor], kp_index - kp_cursor);
kp_buf[kp_cursor++] = c;
kp_index++;
}
kp_buf[kp_index] = '\0';
draw_text_input(kp_buf);
@ -8024,7 +8067,7 @@ static int
keypad_click(int key) {
int c = keypads[key+1].c; // !!! Use key + 1 (zero key index used or size define)
int index = strlen(kp_buf);
int result = keypads[0].c == NUM_KEYBOARD ? num_keypad_click(c, index) : full_keypad_click(c, index);
int result = IS_TXT_KEYBOARD ? full_keypad_click(c, index) : num_keypad_click(c, index);
return result;
}
@ -8033,6 +8076,13 @@ keypad_apply_touch(void)
{
int touch_x, touch_y;
touch_position(&touch_x, &touch_y);
if (IS_TXT_KEYBOARD && touch_y >= LCD_HEIGHT - NUM_INPUT_HEIGHT) {
do { // touch on the text moves the cursor, follow the finger
touch_position(&touch_x, &touch_y);
text_cursor_touch(touch_x);
} while (touch_check() != EVT_TOUCH_RELEASED);
return -1;
}
const keypad_pos_t *p = &key_pos[keypads[0].c];
if (touch_x < p->x_offs || touch_y < p->y_offs) return -1;
// Calculate key position from touch x and y
@ -8056,6 +8106,7 @@ keypad_apply_touch(void)
extern uint8_t in_menu_command;
extern uint8_t remote_text;
extern uint8_t keypad_open;
static void
ui_process_keypad(void)
@ -8069,13 +8120,15 @@ ui_process_keypad(void)
keypad_long_press = false;
if (!preset_text)
kp_buf[0] = 0;
kp_cursor = strlen(kp_buf);
if (in_menu_command) return;
if (preset_text) { // show the default, ENTER accepts it as is
if (keypads[0].c == NUM_KEYBOARD)
draw_numeric_input(kp_buf);
else
if (IS_TXT_KEYBOARD)
draw_text_input(kp_buf);
else
draw_numeric_input(kp_buf);
}
keypad_open = true; // shell commands for the sweep thread are refused now
while (TRUE) {
status = btn_check();
if (status & (EVT_UP|EVT_DOWN)) {
@ -8109,6 +8162,7 @@ ui_process_keypad(void)
break;
}
}
keypad_open = false;
kp_help_text = NULL;
redraw_frame();
if (current_menu_is_form()) {

Loading…
Cancel
Save

Powered by TurnKey Linux.