From 33089b95ab5afc114bb08b86196fdc4ce544eb67 Mon Sep 17 00:00:00 2001 From: Juli Date: Thu, 17 Sep 2026 15:52:56 +0200 Subject: [PATCH] =?UTF-8?q?Wheel=20side=20setting:=20rotate=20the=20displa?= =?UTF-8?q?y=20180=C2=B0=20for=20left-handed=20use?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hardware mirror in the ST7789 (rotation 3 <-> rotation 1); the 35-px window offset is the same both ways. Stored in settings v3. --- README.md | 2 ++ main/display.c | 11 +++++++++++ main/display.h | 3 +++ main/main.c | 1 + main/menu.c | 8 +++++++- main/settings.c | 2 ++ main/settings.h | 3 ++- 7 files changed, 28 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3e34f4a..4944ee2 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,8 @@ Entries: * **Theme** — the look of the menu, boot page and pop-ups, applied as you cycle: *Phosphor* (green), *Pink*, *Amber*, *Ice*, and *Terminal* (green with an 8×16 pixel font). The camera caption keeps its own neutral style. +* **Wheel side** — *Right* (as built) or *Left*: rotates the picture 180° so + you can turn the unit round and keep the knob under your left hand. * **Forget a favourite**, **Wi-Fi setup** (reboots into the hotspot), **Power off**, the board name with its IP, and the power source. diff --git a/main/display.c b/main/display.c index 6c8c5f2..2f5adbe 100644 --- a/main/display.c +++ b/main/display.c @@ -97,3 +97,14 @@ void display_off(void) display_set_backlight(0); if (panel) esp_lcd_panel_disp_on_off(panel, false); } + +void display_set_flipped(bool flipped) +{ + if (!panel) return; + // Rotation 3 (MV|MY) is the stock orientation; rotation 1 (MV|MX) is its 180° twin. + // The 170-px window is centred in the 240-column RAM, so the 35-px gap is the same both ways. + lvgl_port_lock(0); + esp_lcd_panel_mirror(panel, flipped, !flipped); + lv_obj_invalidate(lv_screen_active()); + lvgl_port_unlock(); +} diff --git a/main/display.h b/main/display.h index 49efe32..b264297 100644 --- a/main/display.h +++ b/main/display.h @@ -1,4 +1,5 @@ #pragma once +#include #include #define LCD_H_RES 320 @@ -10,3 +11,5 @@ void display_init(void); void display_set_backlight(uint8_t percent); // Panel sleep-in (used before powering down). void display_off(void); +// 180° rotation so the knob can sit on the left; redraws the current screen. +void display_set_flipped(bool flipped); diff --git a/main/main.c b/main/main.c index 812b1d6..6dd4eb8 100644 --- a/main/main.c +++ b/main/main.c @@ -38,6 +38,7 @@ void app_main(void) leds_set_mode(LED_BREATHE, 0x404040); display_init(); + display_set_flipped(settings.flip); ui_init(); ui_set_theme(settings.theme); ui_status("insecam widget", "starting"); diff --git a/main/menu.c b/main/menu.c index 9a51ad8..316427b 100644 --- a/main/menu.c +++ b/main/menu.c @@ -20,7 +20,7 @@ static const char *TAG = "menu"; typedef enum { VIEW_TOP, VIEW_FAV_PLAY, VIEW_FAV_SAVE, VIEW_FAV_FORGET } view_t; enum { ROW_FAV_TOGGLE, ROW_FAVS, ROW_SOURCE, ROW_PROVIDER, ROW_INTERVAL, ROW_LISTING, ROW_LCD, ROW_RING, - ROW_CAPTION, ROW_THEME, ROW_FORGET, ROW_WIFI, ROW_POWER, ROW_IP, ROW_BATTERY, ROW_CLOSE, TOP_ROWS }; + ROW_CAPTION, ROW_THEME, ROW_FLIP, ROW_FORGET, ROW_WIFI, ROW_POWER, ROW_IP, ROW_BATTERY, ROW_CLOSE, TOP_ROWS }; static ui_menu_row_t rows[TOP_ROWS > FAV_SLOTS + 1 ? TOP_ROWS : FAV_SLOTS + 1]; static char values[TOP_ROWS][20]; @@ -54,6 +54,7 @@ static int build_top(const cam_info_t *current, int fav_slot) rows[ROW_RING] = (ui_menu_row_t){"Ring brightness", values[ROW_RING], false}; rows[ROW_CAPTION] = (ui_menu_row_t){"Caption", settings.caption ? "Shown" : "Hidden", false}; rows[ROW_THEME] = (ui_menu_row_t){"Theme", ui_theme_name(settings.theme), false}; + rows[ROW_FLIP] = (ui_menu_row_t){"Wheel side", settings.flip ? "Left" : "Right", false}; rows[ROW_FORGET] = (ui_menu_row_t){"Forget a favourite", NULL, fav_count() == 0}; rows[ROW_WIFI] = (ui_menu_row_t){"Wi-Fi setup", NULL, false}; rows[ROW_POWER] = (ui_menu_row_t){"Power off", "knob wakes", false}; @@ -191,6 +192,11 @@ menu_result_t menu_run(const cam_info_t *current, int *fav_slot_out) ui_set_theme(settings.theme); settings_save(); break; + case ROW_FLIP: + settings.flip = !settings.flip; + display_set_flipped(settings.flip); + settings_save(); + break; case ROW_LISTING: settings.listing = (settings.listing + 1) % 3; settings_save(); diff --git a/main/settings.c b/main/settings.c index 3d6268b..456d775 100644 --- a/main/settings.c +++ b/main/settings.c @@ -46,6 +46,8 @@ void settings_init(void) if (nvs_get_blob(nvs, "settings", &stored, &len) == ESP_OK && len >= 7 && len <= sizeof stored) { memcpy(&settings, &stored, len); if (len <= offsetof(settings_t, provider)) settings.provider = PROVIDER_PREF_MIXED; // pre-provider blob + if (settings.version < 3) settings.flip = 0; // field lived in padding before v3 + settings.flip = settings.flip ? 1 : 0; settings.version = SETTINGS_VERSION; if (settings.interval_s < 5 || settings.interval_s > 300) settings.interval_s = CONFIG_WIDGET_INTERVAL_S; if (settings.lcd_brightness > 100) settings.lcd_brightness = 100; diff --git a/main/settings.h b/main/settings.h index fb00003..ce5462a 100644 --- a/main/settings.h +++ b/main/settings.h @@ -18,8 +18,9 @@ typedef struct { uint8_t provider; // provider_pref_t (appended; older blobs load with the default) uint8_t version; // SETTINGS_VERSION; lets us tell a pre-provider blob apart uint8_t theme; // ui theme index + uint8_t flip; // 1 = screen rotated 180° (knob on the left) } settings_t; -#define SETTINGS_VERSION 2 +#define SETTINGS_VERSION 3 extern settings_t settings;