diff --git a/docs/CREDITS b/docs/CREDITS index f1affc6eb8..0ec830bc14 100644 --- a/docs/CREDITS +++ b/docs/CREDITS @@ -761,6 +761,7 @@ Javier Gutiérrez Gertrúdix Sergey Puskov Eivind Ødegård Teun van Dalen +Adam N. Burke The libmad team The wavpack team diff --git a/firmware/drivers/button.c b/firmware/drivers/button.c index a1da8da0f9..cd424d4245 100644 --- a/firmware/drivers/button.c +++ b/firmware/drivers/button.c @@ -459,7 +459,6 @@ static int button_flip(int button) { int newbutton = button; -#if (CONFIG_PLATFORM & PLATFORM_NATIVE) newbutton &= ~( #if defined(BUTTON_LEFT) && defined(BUTTON_RIGHT) BUTTON_LEFT | BUTTON_RIGHT @@ -521,7 +520,6 @@ static int button_flip(int button) if (button & BUTTON_PREV) newbutton |= BUTTON_NEXT; #endif -#endif /* !SIMULATOR */ return newbutton; } diff --git a/firmware/export/config/sansaclipzip.h b/firmware/export/config/sansaclipzip.h index 5dcbadf6ba..4aa0d96d42 100644 --- a/firmware/export/config/sansaclipzip.h +++ b/firmware/export/config/sansaclipzip.h @@ -76,7 +76,7 @@ #endif /* define this if you can flip your LCD */ -//#define HAVE_LCD_FLIP +#define HAVE_LCD_FLIP /* define this if you can invert the pixels */ //#define HAVE_LCD_INVERT diff --git a/firmware/target/arm/as3525/sansa-clipzip/lcd-clipzip.c b/firmware/target/arm/as3525/sansa-clipzip/lcd-clipzip.c index 1b4ce3f05c..4f8ea2c863 100644 --- a/firmware/target/arm/as3525/sansa-clipzip/lcd-clipzip.c +++ b/firmware/target/arm/as3525/sansa-clipzip/lcd-clipzip.c @@ -29,6 +29,10 @@ /* the detected lcd type (0 or 1) */ static int lcd_type; +/* set by lcd_set_flip(): when true the panel is rotated 180 degrees via the + controller's GRAM write direction (see lcd_set_flip and lcd_setup_rect) */ +static bool lcd_flipped = false; + #ifdef HAVE_LCD_ENABLE /* whether the lcd is currently enabled or not */ static bool lcd_enabled; @@ -274,6 +278,10 @@ void lcd_enable(bool on) sleep(HZ * 100/1000); lcd_write(0xD0, 0x00); /* SCREEN_SAVER_CONTROL */ + + /* apply 180 degree flip via memory write direction (1Dh): + MDIR1|MDIR0 = decrement both; normal is horizontal-decrement */ + lcd_write(0x1D, lcd_flipped ? 0x02 : 0x01); } else { lcd_write(0xD2, 0x05); @@ -290,6 +298,10 @@ void lcd_enable(bool on) lcd_write(0x03, 0x00); lcd_write(0x02, 0x01); + + /* apply 180 degree flip via graphic RAM writing direction (05h): + D[2:0] = 011 starts from XE,YE (both axes reversed) */ + lcd_write(0x05, lcd_flipped ? 0x03 : 0x00); } else { lcd_write(0x02, 0x00); @@ -297,7 +309,7 @@ void lcd_enable(bool on) lcd_write(0x03, 0x01); } } - + lcd_enabled = on; } @@ -324,6 +336,18 @@ void lcd_init_device(void) /* sets up the lcd to receive frame buffer data */ static void lcd_setup_rect(int x, int x_end, int y, int y_end) { + if (lcd_flipped) { + /* Mirror the window to the opposite corner; the reversed write + direction set in lcd_enable() fills it back-to-front, drawing the + framebuffer rotated 180 degrees with no per-pixel work. */ + int fx = LCD_WIDTH - 1 - x_end; + int fy = LCD_HEIGHT - 1 - y_end; + x_end = LCD_WIDTH - 1 - x; + y_end = LCD_HEIGHT - 1 - y; + x = fx; + y = fy; + } + if (lcd_type == 0) { lcd_write(0x34, x); /* MEM_X1 */ lcd_write(0x35, x_end); /* MEM_X2 */ @@ -380,6 +404,23 @@ void lcd_write_data(const fb_data *data, int count) } } +/* Rotate the display 180 degrees (the flip_display setting). Both panel + controllers do this in hardware by reversing the GRAM write direction (set in + lcd_enable) so the address counter walks the framebuffer backwards; + lcd_setup_rect mirrors the write window to match. Cycle the panel off/on here + so a change (e.g. toggled from the menu) takes effect immediately. */ +void lcd_set_flip(bool yesno) +{ + if (yesno == lcd_flipped) + return; + lcd_flipped = yesno; + + if (lcd_enabled) { + lcd_enable(false); + lcd_enable(true); + } +} + /* Updates a fraction of the display. */ void lcd_update_rect(int x, int y, int width, int height) { @@ -392,7 +433,7 @@ void lcd_update_rect(int x, int y, int width, int height) /* rectangle is outside visible display, do nothing */ return; } - + /* update entire horizontal strip for display type 0 (wisechip) */ if (lcd_type == 0) { x = 0; diff --git a/firmware/target/hosted/sdl/lcd-bitmap.c b/firmware/target/hosted/sdl/lcd-bitmap.c index 048e3f92a9..0280bd537b 100644 --- a/firmware/target/hosted/sdl/lcd-bitmap.c +++ b/firmware/target/hosted/sdl/lcd-bitmap.c @@ -113,6 +113,17 @@ static unsigned long get_lcd_pixel(int x, int y) #endif } +#ifdef HAVE_LCD_FLIP +/* The simulator has no real LCD controller, so flip_display is done in software + here: when set, the framebuffer is mirrored as it is copied to the surface. + (On the device the controller flips itself; see lcd-clipzip.c.) */ +static bool sim_lcd_flipped = false; +void lcd_set_flip(bool yesno) +{ + sim_lcd_flipped = yesno; +} +#endif + void lcd_update(void) { /* update a full screen rect */ @@ -121,6 +132,29 @@ void lcd_update(void) void lcd_update_rect(int x_start, int y_start, int width, int height) { +#ifdef HAVE_LCD_FLIP + if (sim_lcd_flipped) + { + /* redraw the whole panel mirrored in both axes (sim software flip) */ + SDL_Rect d = {0, 0, 1, 1}; + int x, y; + for (y = 0; y < LCD_HEIGHT; y++) + { + for (x = 0; x < LCD_WIDTH; x++) + { + d.x = x; + d.y = y; + SDL_FillRect(lcd_surface, &d, (Uint32) + get_lcd_pixel(LCD_WIDTH - 1 - x, LCD_HEIGHT - 1 - y)); + } + } + sdl_gui_update(lcd_surface, 0, 0, LCD_WIDTH, + LCD_HEIGHT + LCD_SPLIT_LINES, SIM_LCD_WIDTH, SIM_LCD_HEIGHT, + background ? UI_LCD_POSX : 0, background? UI_LCD_POSY : 0); + return; + } +#endif + sdl_update_rect(lcd_surface, x_start, y_start, width, height, LCD_WIDTH, LCD_HEIGHT, get_lcd_pixel); sdl_gui_update(lcd_surface, x_start, y_start, width, diff --git a/uisimulator/common/lcd-common.c b/uisimulator/common/lcd-common.c index 1bb5beebb7..ac2f4077e3 100644 --- a/uisimulator/common/lcd-common.c +++ b/uisimulator/common/lcd-common.c @@ -37,10 +37,12 @@ static bool lcd_enabled = false; static bool lcd_sleeping = true; #endif +#if !defined(HAVE_LCD_FLIP) void lcd_set_flip(bool yesno) { (void)yesno; } +#endif void lcd_set_invert_display(bool invert) {