From e5cdb042bfda9c1772d11f894660a2e4175e8da6 Mon Sep 17 00:00:00 2001 From: Gustavo Cateim Date: Sun, 23 Aug 2026 23:28:56 -0300 Subject: [PATCH] camera: add user option to rotate the camera image 180 degrees Some DIY boards take a detachable camera module which can end up physically mounted either way up. Two Waveshare S3 Touch LCD 2 units with the same OV5640 module have been seen producing opposite image orientations, so no build-time default suits both and the sensor model cannot be used to tell them apart at runtime (see discussion in PR 331). Add a 'Rotate Camera' entry to the display settings menu on camera boards other than the official Jade units. The setting is persisted as a bit in the existing gui flags storage field and picks between the two already-compiled copy functions at runtime in the camera task, composing with any flipped display orientation. While the rotation is active the menu label reads 'Camera Rotated', doubling as the state indicator. --- main/button_events.h | 1 + main/camera.c | 7 ++++++- main/process/dashboard.c | 18 ++++++++++++++++++ main/storage.h | 1 + main/ui/dashboard.c | 14 ++++++++++++++ 5 files changed, 40 insertions(+), 1 deletion(-) diff --git a/main/button_events.h b/main/button_events.h index 8b835ff4..fbbe94f4 100644 --- a/main/button_events.h +++ b/main/button_events.h @@ -137,6 +137,7 @@ typedef enum { BTN_SETTINGS_DISPLAY_EXIT, BTN_SETTINGS_DISPLAY_BRIGHTNESS, BTN_SETTINGS_DISPLAY_ORIENTATION, + BTN_SETTINGS_DISPLAY_CAMERA_ROTATE, BTN_SETTINGS_DISPLAY_THEME, BTN_SETTINGS_XPUB_EXPORT, BTN_SETTINGS_QR_PINSERVER, diff --git a/main/camera.c b/main/camera.c index 82c7f43e..5bae933b 100644 --- a/main/camera.c +++ b/main/camera.c @@ -9,6 +9,7 @@ #include "jade_tasks.h" #include "power.h" #include "sensitive.h" +#include "storage.h" #include "ui.h" #include "utils/event.h" #include "utils/malloc_ext.h" @@ -376,8 +377,12 @@ static void jade_camera_task(void* data) typedef void (*copy_camera_image_fn_t)( uint8_t[DISPLAY_IMAGE_HEIGHT][DISPLAY_IMAGE_WIDTH], const uint8_t[CAMERA_IMAGE_HEIGHT][CAMERA_IMAGE_WIDTH]); + // The user may have persisted an extra 180-degree rotation to correct for camera + // modules which can be physically mounted either way up (eg. on some DIY units). + // This composes with any flipped display orientation, hence the inequality. + const bool camera_rotated = storage_get_gui_flags() & GUI_FLAGS_CAMERA_ROTATED; copy_camera_image_fn_t copy_camera_image - = gui_get_flipped_orientation() ? COPY_CAMERA_IMAGE_FLIPPED : COPY_CAMERA_IMAGE_STRAIGHT; + = (gui_get_flipped_orientation() != camera_rotated) ? COPY_CAMERA_IMAGE_FLIPPED : COPY_CAMERA_IMAGE_STRAIGHT; camera_task_config_t* const camera_config = (camera_task_config_t*)data; JADE_ASSERT(camera_config->fn_process); diff --git a/main/process/dashboard.c b/main/process/dashboard.c index 43fac712..2a4ec16a 100644 --- a/main/process/dashboard.c +++ b/main/process/dashboard.c @@ -1925,6 +1925,16 @@ static void handle_flip_orientation(void) } } +#if defined(CONFIG_HAS_CAMERA) && !defined(CONFIG_BOARD_TYPE_JADE_ANY) +static void handle_camera_rotate(void) +{ + // Toggle the extra 180-degree camera image rotation - takes effect + // next time the camera is used + const uint8_t gui_flags = storage_get_gui_flags(); + storage_set_gui_flags(gui_flags ^ GUI_FLAGS_CAMERA_ROTATED); +} +#endif + #ifdef CONFIG_HAS_CAMERA static void handle_pinserver_scan(void) { @@ -2302,6 +2312,14 @@ static void handle_settings(const bool startup_menu) handle_flip_orientation(); break; +#if defined(CONFIG_HAS_CAMERA) && !defined(CONFIG_BOARD_TYPE_JADE_ANY) + case BTN_SETTINGS_DISPLAY_CAMERA_ROTATE: + handle_camera_rotate(); + // remake parent screen to update the menu item label + act = make_display_settings_activity(); + break; +#endif + case BTN_SETTINGS_DISPLAY_THEME: handle_display_theme(); // remake parent screen to update colours diff --git a/main/storage.h b/main/storage.h index 538eb7c9..9343e805 100644 --- a/main/storage.h +++ b/main/storage.h @@ -13,6 +13,7 @@ #define BLE_ENABLED 0x1 #define GUI_FLAGS_THEMES_MASK 0x7 +#define GUI_FLAGS_CAMERA_ROTATED 0x20 #define GUI_FLAGS_FLIP_ORIENTATION 0x40 #define GUI_FLAGS_USE_WHEEL_CLICK 0x80 diff --git a/main/ui/dashboard.c b/main/ui/dashboard.c index 2001468c..277f177b 100644 --- a/main/ui/dashboard.c +++ b/main/ui/dashboard.c @@ -2,6 +2,7 @@ #include "../button_events.h" #include "../display.h" #include "../jade_assert.h" +#include "../storage.h" #include "../ui.h" #include "process.h" #include "utils/malloc_ext.h" @@ -392,6 +393,13 @@ gui_activity_t* make_display_settings_activity(void) btn_data_t hdrbtns[] = { { .txt = "=", .font = JADE_SYMBOLS_16x16_FONT, .ev_id = BTN_SETTINGS_DISPLAY_EXIT }, { .txt = NULL, .font = GUI_DEFAULT_FONT, .ev_id = GUI_BUTTON_EVENT_NONE } }; +#if defined(CONFIG_HAS_CAMERA) && !defined(CONFIG_BOARD_TYPE_JADE_ANY) + // The label doubles as the state indicator - shows 'Camera Rotated' while + // the extra 180-degree camera rotation is active + const char* const camera_btn_label + = (storage_get_gui_flags() & GUI_FLAGS_CAMERA_ROTATED) ? "Camera Rotated" : "Rotate Camera"; +#endif + // NOTE: Only boards listed here have brightness controls // NOTE: Jade v1.1's do not support Flip Orientation because of issues with screen offsets #if defined(CONFIG_BOARD_TYPE_JADE_V2_ANY) || defined(CONFIG_BOARD_TYPE_WS_TOUCH_LCD2) \ @@ -399,6 +407,9 @@ gui_activity_t* make_display_settings_activity(void) btn_data_t menubtns[] = { { .txt = "Display Brightness", .font = GUI_DEFAULT_FONT, .ev_id = BTN_SETTINGS_DISPLAY_BRIGHTNESS }, { .txt = "Flip Orientation", .font = GUI_DEFAULT_FONT, .ev_id = BTN_SETTINGS_DISPLAY_ORIENTATION }, +#if defined(CONFIG_HAS_CAMERA) && !defined(CONFIG_BOARD_TYPE_JADE_ANY) + { .txt = camera_btn_label, .font = GUI_DEFAULT_FONT, .ev_id = BTN_SETTINGS_DISPLAY_CAMERA_ROTATE }, +#endif { .txt = "Theme", .font = GUI_DEFAULT_FONT, .ev_id = BTN_SETTINGS_DISPLAY_THEME } }; #elif defined(CONFIG_BOARD_TYPE_JADE_V1_1) btn_data_t menubtns[] @@ -409,6 +420,9 @@ gui_activity_t* make_display_settings_activity(void) #else // DIY units btn_data_t menubtns[] = { { .txt = "Flip Orientation", .font = GUI_DEFAULT_FONT, .ev_id = BTN_SETTINGS_DISPLAY_ORIENTATION }, +#if defined(CONFIG_HAS_CAMERA) + { .txt = camera_btn_label, .font = GUI_DEFAULT_FONT, .ev_id = BTN_SETTINGS_DISPLAY_CAMERA_ROTATE }, +#endif { .txt = "Theme", .font = GUI_DEFAULT_FONT, .ev_id = BTN_SETTINGS_DISPLAY_THEME } }; #endif